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' ],
93 digraphWordsSorted = [
103 [ 'January, 19 2010' ],
107 [ 'December 12 \'10' ]
113 [ 'January, 19 2010' ],
114 [ 'December 12 \'10' ]
133 // Comma's sort after dots
134 // Not intentional but test to detect changes
155 correctDateSorting1 = [
156 [ '01 January 2010' ],
157 [ '05 February 2010' ],
158 [ '16 January 2010' ]
160 correctDateSortingSorted1 = [
161 [ '01 January 2010' ],
162 [ '16 January 2010' ],
163 [ '05 February 2010' ]
166 correctDateSorting2 = [
167 [ 'January 01 2010' ],
168 [ 'February 05 2010' ],
169 [ 'January 16 2010' ]
171 correctDateSortingSorted2 = [
172 [ 'January 01 2010' ],
173 [ 'January 16 2010' ],
174 [ 'February 05 2010' ]
178 [ '2009-12-25T12:30:45.001Z' ],
181 [ '2009-12-25T12:30:45' ],
182 [ '2009-12-25T12:30:45.111' ],
183 [ '2009-12-25T12:30:45+01:00' ]
185 isoDateSortingSorted = [
187 [ '2009-12-25T12:30:45' ],
188 [ '2009-12-25T12:30:45+01:00' ],
189 [ '2009-12-25T12:30:45.001Z' ],
190 [ '2009-12-25T12:30:45.111' ],
195 QUnit.module( 'jquery.tablesorter', QUnit.newMwEnvironment( {
197 this.liveMonths = mw.language.months;
198 mw.language.months = {
200 names: [ 'january', 'february', 'march', 'april', 'may_long', 'june',
201 'july', 'august', 'september', 'october', 'november', 'december' ],
202 genitive: [ 'january-gen', 'february-gen', 'march-gen', 'april-gen', 'may-gen', 'june-gen',
203 'july-gen', 'august-gen', 'september-gen', 'october-gen', 'november-gen', 'december-gen' ],
204 abbrev: [ 'jan', 'feb', 'mar', 'apr', 'may', 'jun',
205 'jul', 'aug', 'sep', 'oct', 'nov', 'dec' ]
207 names: [ 'January', 'February', 'March', 'April', 'May', 'June',
208 'July', 'August', 'September', 'October', 'November', 'December' ],
209 genitive: [ 'January', 'February', 'March', 'April', 'May', 'June',
210 'July', 'August', 'September', 'October', 'November', 'December' ],
211 abbrev: [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
212 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ]
215 teardown: function () {
216 mw.language.months = this.liveMonths;
219 wgDefaultDateFormat: 'dmy',
220 wgSeparatorTransformTable: [ '', '' ],
221 wgDigitTransformTable: [ '', '' ],
222 wgPageContentLanguage: 'en'
227 * Create an HTML table from an array of row arrays containing text strings.
228 * First row will be header row. No fancy rowspan/colspan stuff.
230 * @param {string[]} header
231 * @param {string[][]} data
234 function tableCreate( header, data ) {
236 $table = $( '<table class="sortable"><thead></thead><tbody></tbody></table>' ),
237 $thead = $table.find( 'thead' ),
238 $tbody = $table.find( 'tbody' ),
241 $.each( header, function ( i, str ) {
242 var $th = $( '<th>' );
243 $th.text( str ).appendTo( $tr );
245 $tr.appendTo( $thead );
247 for ( i = 0; i < data.length; i++ ) {
248 /*jshint loopfunc: true */
250 $.each( data[ i ], function ( j, str ) {
251 var $td = $( '<td>' );
252 $td.text( str ).appendTo( $tr );
254 $tr.appendTo( $tbody );
260 * Extract text from table.
262 * @param {jQuery} $table
263 * @return {string[][]}
265 function tableExtract( $table ) {
268 $table.find( 'tbody' ).find( 'tr' ).each( function ( i, tr ) {
270 $( tr ).find( 'td,th' ).each( function ( i, td ) {
271 row.push( $( td ).text() );
279 * Run a table test by building a table with the given data,
280 * running some callback on it, then checking the results.
282 * @param {string} msg text to pass on to qunit for the comparison
283 * @param {string[]} header cols to make the table
284 * @param {string[][]} data rows/cols to make the table
285 * @param {string[][]} expected rows/cols to compare against at end
286 * @param {function($table)} callback something to do with the table before we compare
288 function tableTest( msg, header, data, expected, callback ) {
289 QUnit.test( msg, 1, function ( assert ) {
291 $table = tableCreate( header, data );
293 // Give caller a chance to set up sorting and manipulate the table.
296 // Table sorting is done synchronously; if it ever needs to change back
297 // to asynchronous, we'll need a timeout or a callback here.
298 extracted = tableExtract( $table );
299 assert.deepEqual( extracted, expected, msg );
304 * Run a table test by building a table with the given HTML,
305 * running some callback on it, then checking the results.
307 * @param {string} msg text to pass on to qunit for the comparison
308 * @param {string} html HTML to make the table
309 * @param {string[][]} expected Rows/cols to compare against at end
310 * @param {function($table)} callback Something to do with the table before we compare
312 function tableTestHTML( msg, html, expected, callback ) {
313 QUnit.test( msg, 1, function ( assert ) {
317 // Give caller a chance to set up sorting and manipulate the table.
321 $table.tablesorter();
322 $table.find( '#sortme' ).click();
325 // Table sorting is done synchronously; if it ever needs to change back
326 // to asynchronous, we'll need a timeout or a callback here.
327 extracted = tableExtract( $table );
328 assert.deepEqual( extracted, expected, msg );
332 function reversed( arr ) {
334 var arr2 = arr.slice( 0 );
341 // Sample data set using planets named and their radius
344 'Basic planet table: sorting initially - ascending by name',
348 function ( $table ) {
349 $table.tablesorter( { sortList: [
355 'Basic planet table: sorting initially - descending by radius',
358 reversed( planetsAscRadius ),
359 function ( $table ) {
360 $table.tablesorter( { sortList: [
366 'Basic planet table: ascending by name',
370 function ( $table ) {
371 $table.tablesorter();
372 $table.find( '.headerSort:eq(0)' ).click();
376 'Basic planet table: ascending by name a second time',
380 function ( $table ) {
381 $table.tablesorter();
382 $table.find( '.headerSort:eq(0)' ).click();
386 'Basic planet table: ascending by name (multiple clicks)',
390 function ( $table ) {
391 $table.tablesorter();
392 $table.find( '.headerSort:eq(0)' ).click();
393 $table.find( '.headerSort:eq(1)' ).click();
394 $table.find( '.headerSort:eq(0)' ).click();
398 'Basic planet table: descending by name',
401 reversed( planetsAscName ),
402 function ( $table ) {
403 $table.tablesorter();
404 $table.find( '.headerSort:eq(0)' ).click().click();
408 'Basic planet table: ascending radius',
412 function ( $table ) {
413 $table.tablesorter();
414 $table.find( '.headerSort:eq(1)' ).click();
418 'Basic planet table: descending radius',
421 reversed( planetsAscRadius ),
422 function ( $table ) {
423 $table.tablesorter();
424 $table.find( '.headerSort:eq(1)' ).click().click();
428 'Sorting multiple columns by passing sort list',
432 function ( $table ) {
442 'Sorting multiple columns by programmatically triggering sort()',
446 function ( $table ) {
447 $table.tablesorter();
448 $table.data( 'tablesorter' ).sort(
457 'Reset to initial sorting by triggering sort() without any parameters',
461 function ( $table ) {
468 $table.data( 'tablesorter' ).sort(
474 $table.data( 'tablesorter' ).sort();
478 'Sort via click event after having initialized the tablesorter with initial sorting',
482 function ( $table ) {
484 { sortList: [ { 0: 'asc' }, { 1: 'asc' } ] }
486 $table.find( '.headerSort:eq(0)' ).click();
490 'Multi-sort via click event after having initialized the tablesorter with initial sorting',
494 function ( $table ) {
496 { sortList: [ { 0: 'desc' }, { 1: 'desc' } ] }
498 $table.find( '.headerSort:eq(0)' ).click();
500 // Pretend to click while pressing the multi-sort key
501 var event = $.Event( 'click' );
502 event[ $table.data( 'tablesorter' ).config.sortMultiSortKey ] = true;
503 $table.find( '.headerSort:eq(1)' ).trigger( event );
506 QUnit.test( 'Reset sorting making table appear unsorted', 3, function ( assert ) {
507 var $table = tableCreate( header, simple );
514 $table.data( 'tablesorter' ).sort( [] );
517 $table.find( 'th.headerSortUp' ).length + $table.find( 'th.headerSortDown' ).length,
519 'No sort specific sort classes addign to header cells'
523 $table.find( 'th' ).first().attr( 'title' ),
524 mw.msg( 'sort-ascending' ),
525 'First header cell has default title'
529 $table.find( 'th' ).first().attr( 'title' ),
530 $table.find( 'th' ).last().attr( 'title' ),
531 'Both header cells\' titles match'
535 // Sorting with colspans
537 tableTest( 'Sorting with colspanned headers: spanned column',
540 [ aaa1, aab5, abc3, bbc2, caa4 ],
541 function ( $table ) {
542 // Make colspanned header for test
543 $table.find( 'tr:eq(0) th:eq(1), tr:eq(0) th:eq(2)' ).remove();
544 $table.find( 'tr:eq(0) th:eq(0)' ).attr( 'colspan', '3' );
546 $table.tablesorter();
547 $table.find( '.headerSort:eq(0)' ).click();
550 tableTest( 'Sorting with colspanned headers: sort spanned column twice',
553 [ caa4, bbc2, abc3, aab5, aaa1 ],
554 function ( $table ) {
555 // Make colspanned header for test
556 $table.find( 'tr:eq(0) th:eq(1), tr:eq(0) th:eq(2)' ).remove();
557 $table.find( 'tr:eq(0) th:eq(0)' ).attr( 'colspan', '3' );
559 $table.tablesorter();
560 $table.find( '.headerSort:eq(0)' ).click();
561 $table.find( '.headerSort:eq(0)' ).click();
564 tableTest( 'Sorting with colspanned headers: subsequent column',
567 [ aaa1, bbc2, abc3, caa4, aab5 ],
568 function ( $table ) {
569 // Make colspanned header for test
570 $table.find( 'tr:eq(0) th:eq(1), tr:eq(0) th:eq(2)' ).remove();
571 $table.find( 'tr:eq(0) th:eq(0)' ).attr( 'colspan', '3' );
573 $table.tablesorter();
574 $table.find( '.headerSort:eq(1)' ).click();
577 tableTest( 'Sorting with colspanned headers: sort subsequent column twice',
580 [ aab5, caa4, abc3, bbc2, aaa1 ],
581 function ( $table ) {
582 // Make colspanned header for test
583 $table.find( 'tr:eq(0) th:eq(1), tr:eq(0) th:eq(2)' ).remove();
584 $table.find( 'tr:eq(0) th:eq(0)' ).attr( 'colspan', '3' );
586 $table.tablesorter();
587 $table.find( '.headerSort:eq(1)' ).click();
588 $table.find( '.headerSort:eq(1)' ).click();
592 QUnit.test( 'Basic planet table: one unsortable column', 3, function ( assert ) {
593 var $table = tableCreate( header, planets ),
595 $table.find( 'tr:eq(0) > th:eq(0)' ).addClass( 'unsortable' );
597 $table.tablesorter();
598 $table.find( 'tr:eq(0) > th:eq(0)' ).click();
601 tableExtract( $table ),
606 $cell = $table.find( 'tr:eq(0) > th:eq(0)' );
607 $table.find( 'tr:eq(0) > th:eq(1)' ).click();
610 $cell.hasClass( 'headerSortUp' ) || $cell.hasClass( 'headerSortDown' ),
612 'after sort: no class headerSortUp or headerSortDown'
616 $cell.attr( 'title' ),
618 'after sort: no title tag added'
625 'Bug 28775: German-style (dmy) short numeric dates',
628 // German-style dates are day-month-year
636 // Sorted by ascending date
643 function ( $table ) {
644 mw.config.set( 'wgDefaultDateFormat', 'dmy' );
645 mw.config.set( 'wgPageContentLanguage', 'de' );
647 $table.tablesorter();
648 $table.find( '.headerSort:eq(0)' ).click();
653 'Bug 28775: American-style (mdy) short numeric dates',
656 // American-style dates are month-day-year
664 // Sorted by ascending date
671 function ( $table ) {
672 mw.config.set( 'wgDefaultDateFormat', 'mdy' );
674 $table.tablesorter();
675 $table.find( '.headerSort:eq(0)' ).click();
680 'Bug 17141: IPv4 address sorting',
684 function ( $table ) {
685 $table.tablesorter();
686 $table.find( '.headerSort:eq(0)' ).click();
690 'Bug 17141: IPv4 address sorting (reverse)',
693 reversed( ipv4Sorted ),
694 function ( $table ) {
695 $table.tablesorter();
696 $table.find( '.headerSort:eq(0)' ).click().click();
701 'Accented Characters with custom collation',
705 function ( $table ) {
706 mw.config.set( 'tableSorterCollation', {
713 $table.tablesorter();
714 $table.find( '.headerSort:eq(0)' ).click();
719 'Digraphs with custom collation',
723 function ( $table ) {
724 mw.config.set( 'tableSorterCollation', {
729 $table.tablesorter();
730 $table.find( '.headerSort:eq(0)' ).click();
734 QUnit.test( 'Rowspan not exploded on init', 1, function ( assert ) {
735 var $table = tableCreate( header, planets );
737 // Modify the table to have a multiple-row-spanning cell:
738 // - Remove 2nd cell of 4th row, and, 2nd cell or 5th row.
739 $table.find( 'tr:eq(3) td:eq(1), tr:eq(4) td:eq(1)' ).remove();
740 // - Set rowspan for 2nd cell of 3rd row to 3.
741 // This covers the removed cell in the 4th and 5th row.
742 $table.find( 'tr:eq(2) td:eq(1)' ).attr( 'rowspan', '3' );
744 $table.tablesorter();
747 $table.find( 'tr:eq(2) td:eq(1)' ).prop( 'rowSpan' ),
749 'Rowspan not exploded'
754 [ 'Earth', '6051.8' ],
756 [ 'Mars', '6051.8' ],
761 planetsRowspanII = [ jupiter, mercury, saturn, venus, [ 'Venus', '6371.0' ], [ 'Venus', '3390.0' ] ];
764 'Basic planet table: same value for multiple rows via rowspan',
768 function ( $table ) {
769 // Modify the table to have a multiple-row-spanning cell:
770 // - Remove 2nd cell of 4th row, and, 2nd cell or 5th row.
771 $table.find( 'tr:eq(3) td:eq(1), tr:eq(4) td:eq(1)' ).remove();
772 // - Set rowspan for 2nd cell of 3rd row to 3.
773 // This covers the removed cell in the 4th and 5th row.
774 $table.find( 'tr:eq(2) td:eq(1)' ).attr( 'rowspan', '3' );
776 $table.tablesorter();
777 $table.find( '.headerSort:eq(0)' ).click();
781 'Basic planet table: same value for multiple rows via rowspan (sorting initially)',
785 function ( $table ) {
786 // Modify the table to have a multiple-row-spanning cell:
787 // - Remove 2nd cell of 4th row, and, 2nd cell or 5th row.
788 $table.find( 'tr:eq(3) td:eq(1), tr:eq(4) td:eq(1)' ).remove();
789 // - Set rowspan for 2nd cell of 3rd row to 3.
790 // This covers the removed cell in the 4th and 5th row.
791 $table.find( 'tr:eq(2) td:eq(1)' ).attr( 'rowspan', '3' );
793 $table.tablesorter( { sortList: [
799 'Basic planet table: Same value for multiple rows via rowspan II',
803 function ( $table ) {
804 // Modify the table to have a multiple-row-spanning cell:
805 // - Remove 1st cell of 4th row, and, 1st cell or 5th row.
806 $table.find( 'tr:eq(3) td:eq(0), tr:eq(4) td:eq(0)' ).remove();
807 // - Set rowspan for 1st cell of 3rd row to 3.
808 // This covers the removed cell in the 4th and 5th row.
809 $table.find( 'tr:eq(2) td:eq(0)' ).attr( 'rowspan', '3' );
811 $table.tablesorter();
812 $table.find( '.headerSort:eq(0)' ).click();
817 'Complex date parsing I',
821 function ( $table ) {
822 mw.config.set( 'wgDefaultDateFormat', 'mdy' );
824 $table.tablesorter();
825 $table.find( '.headerSort:eq(0)' ).click();
830 'Currency parsing I',
834 function ( $table ) {
835 $table.tablesorter();
836 $table.find( '.headerSort:eq(0)' ).click();
840 planetsAscNameLegacy = planetsAscName.slice( 0 );
841 planetsAscNameLegacy[ 4 ] = planetsAscNameLegacy[ 5 ];
842 planetsAscNameLegacy.pop();
845 'Legacy compat with .sortbottom',
848 planetsAscNameLegacy,
849 function ( $table ) {
850 $table.find( 'tr:last' ).addClass( 'sortbottom' );
851 $table.tablesorter();
852 $table.find( '.headerSort:eq(0)' ).click();
856 QUnit.test( 'Test detection routine', 1, function ( assert ) {
859 '<table class="sortable">' +
860 '<caption>CAPTION</caption>' +
861 '<tr><th>THEAD</th></tr>' +
862 '<tr><td>1</td></tr>' +
863 '<tr class="sortbottom"><td>text</td></tr>' +
866 $table.tablesorter();
867 $table.find( '.headerSort:eq(0)' ).click();
870 $table.data( 'tablesorter' ).config.parsers[ 0 ].id,
872 'Correctly detected column content skipping sortbottom'
876 /** FIXME: the diff output is not very readeable. */
877 QUnit.test( 'bug 32047 - caption must be before thead', 1, function ( assert ) {
880 '<table class="sortable">' +
881 '<caption>CAPTION</caption>' +
882 '<tr><th>THEAD</th></tr>' +
883 '<tr><td>A</td></tr>' +
884 '<tr><td>B</td></tr>' +
885 '<tr class="sortbottom"><td>TFOOT</td></tr>' +
888 $table.tablesorter();
891 $table.children().get( 0 ).nodeName,
893 'First element after <thead> must be <caption> (bug 32047)'
897 QUnit.test( 'data-sort-value attribute, when available, should override sorting position', 3, function ( assert ) {
900 // Example 1: All cells except one cell without data-sort-value,
901 // which should be sorted at it's text content value.
903 '<table class="sortable"><thead><tr><th>Data</th></tr></thead>' +
905 '<tr><td>Cheetah</td></tr>' +
906 '<tr><td data-sort-value="Apple">Bird</td></tr>' +
907 '<tr><td data-sort-value="Bananna">Ferret</td></tr>' +
908 '<tr><td data-sort-value="Drupe">Elephant</td></tr>' +
909 '<tr><td data-sort-value="Cherry">Dolphin</td></tr>' +
912 $table.tablesorter().find( '.headerSort:eq(0)' ).click();
915 $table.find( 'tbody > tr' ).each( function ( i, tr ) {
916 $( tr ).find( 'td' ).each( function ( i, td ) {
918 data: $( td ).data( 'sortValue' ),
924 assert.deepEqual( data, [
945 ], 'Order matches expected order (based on data-sort-value attribute values)' );
949 '<table class="sortable"><thead><tr><th>Data</th></tr></thead>' +
951 '<tr><td>D</td></tr>' +
952 '<tr><td data-sort-value="E">A</td></tr>' +
953 '<tr><td>B</td></tr>' +
954 '<tr><td>G</td></tr>' +
955 '<tr><td data-sort-value="F">C</td></tr>' +
958 $table.tablesorter().find( '.headerSort:eq(0)' ).click();
961 $table.find( 'tbody > tr' ).each( function ( i, tr ) {
962 $( tr ).find( 'td' ).each( function ( i, td ) {
964 data: $( td ).data( 'sortValue' ),
970 assert.deepEqual( data, [
991 ], 'Order matches expected order (based on data-sort-value attribute values)' );
993 // Example 3: Test that live changes are used from data-sort-value,
994 // even if they change after the tablesorter is constructed (bug 38152).
996 '<table class="sortable"><thead><tr><th>Data</th></tr></thead>' +
998 '<tr><td>D</td></tr>' +
999 '<tr><td data-sort-value="1">A</td></tr>' +
1000 '<tr><td>B</td></tr>' +
1001 '<tr><td data-sort-value="2">G</td></tr>' +
1002 '<tr><td>C</td></tr>' +
1005 // initialize table sorter and sort once
1008 .find( '.headerSort:eq(0)' ).click();
1010 // Change the sortValue data properties (bug 38152)
1012 $table.find( 'td:contains(A)' ).data( 'sortValue', 3 );
1014 $table.find( 'td:contains(B)' ).data( 'sortValue', 1 );
1015 // - remove data, bring back attribute: 2
1016 $table.find( 'td:contains(G)' ).removeData( 'sortValue' );
1018 // Now sort again (twice, so it is back at Ascending)
1019 $table.find( '.headerSort:eq(0)' ).click();
1020 $table.find( '.headerSort:eq(0)' ).click();
1023 $table.find( 'tbody > tr' ).each( function ( i, tr ) {
1024 $( tr ).find( 'td' ).each( function ( i, td ) {
1026 data: $( td ).data( 'sortValue' ),
1027 text: $( td ).text()
1032 assert.deepEqual( data, [
1053 ], 'Order matches expected order, using the current sortValue in $.data()' );
1057 tableTest( 'bug 8115: sort numbers with commas (ascending)',
1058 [ 'Numbers' ], numbers, numbersAsc,
1059 function ( $table ) {
1060 $table.tablesorter();
1061 $table.find( '.headerSort:eq(0)' ).click();
1065 tableTest( 'bug 8115: sort numbers with commas (descending)',
1066 [ 'Numbers' ], numbers, reversed( numbersAsc ),
1067 function ( $table ) {
1068 $table.tablesorter();
1069 $table.find( '.headerSort:eq(0)' ).click().click();
1072 // TODO add numbers sorting tests for bug 8115 with a different language
1074 QUnit.test( 'bug 32888 - Tables inside a tableheader cell', 2, function ( assert ) {
1077 '<table class="sortable" id="mw-bug-32888">' +
1078 '<tr><th>header<table id="mw-bug-32888-2">' +
1079 '<tr><th>1</th><th>2</th></tr>' +
1080 '</table></th></tr>' +
1081 '<tr><td>A</td></tr>' +
1082 '<tr><td>B</td></tr>' +
1085 $table.tablesorter();
1088 $table.find( '> thead:eq(0) > tr > th.headerSort' ).length,
1090 'Child tables inside a headercell should not interfere with sortable headers (bug 32888)'
1093 $( '#mw-bug-32888-2' ).find( 'th.headerSort' ).length,
1095 'The headers of child tables inside a headercell should not be sortable themselves (bug 32888)'
1100 'Correct date sorting I',
1102 correctDateSorting1,
1103 correctDateSortingSorted1,
1104 function ( $table ) {
1105 mw.config.set( 'wgDefaultDateFormat', 'mdy' );
1107 $table.tablesorter();
1108 $table.find( '.headerSort:eq(0)' ).click();
1113 'Correct date sorting II',
1115 correctDateSorting2,
1116 correctDateSortingSorted2,
1117 function ( $table ) {
1118 mw.config.set( 'wgDefaultDateFormat', 'dmy' );
1120 $table.tablesorter();
1121 $table.find( '.headerSort:eq(0)' ).click();
1129 isoDateSortingSorted,
1130 function ( $table ) {
1131 mw.config.set( 'wgDefaultDateFormat', 'dmy' );
1133 $table.tablesorter();
1134 $table.find( '.headerSort:eq(0)' ).click();
1138 QUnit.test( 'Sorting images using alt text', 1, function ( assert ) {
1140 '<table class="sortable">' +
1141 '<tr><th>THEAD</th></tr>' +
1142 '<tr><td><img alt="2"/></td></tr>' +
1143 '<tr><td>1</td></tr>' +
1146 $table.tablesorter().find( '.headerSort:eq(0)' ).click();
1149 $table.find( 'td' ).first().text(),
1151 'Applied correct sorting order'
1155 QUnit.test( 'Sorting images using alt text (complex)', 1, function ( assert ) {
1157 '<table class="sortable">' +
1158 '<tr><th>THEAD</th></tr>' +
1159 '<tr><td><img alt="D" />A</td></tr>' +
1160 '<tr><td>CC</td></tr>' +
1161 '<tr><td><a><img alt="A" /></a>F</tr>' +
1162 '<tr><td><img alt="A" /><strong>E</strong></tr>' +
1163 '<tr><td><strong><img alt="A" />D</strong></tr>' +
1164 '<tr><td><img alt="A" />C</tr>' +
1167 $table.tablesorter().find( '.headerSort:eq(0)' ).click();
1170 $table.find( 'td' ).text(),
1172 'Applied correct sorting order'
1176 QUnit.test( 'Sorting images using alt text (with format autodetection)', 1, function ( assert ) {
1178 '<table class="sortable">' +
1179 '<tr><th>THEAD</th></tr>' +
1180 '<tr><td><img alt="1" />7</td></tr>' +
1181 '<tr><td>1<img alt="6" /></td></tr>' +
1182 '<tr><td>5</td></tr>' +
1183 '<tr><td>4</td></tr>' +
1186 $table.tablesorter().find( '.headerSort:eq(0)' ).click();
1189 $table.find( 'td' ).text(),
1191 'Applied correct sorting order'
1195 QUnit.test( 'bug 38911 - The row with the largest amount of columns should receive the sort indicators', 3, function ( assert ) {
1197 '<table class="sortable">' +
1199 '<tr><th rowspan="2" id="A1">A1</th><th colspan="2">B2a</th></tr>' +
1200 '<tr><th id="B2b">B2b</th><th id="C2b">C2b</th></tr>' +
1202 '<tr><td>A</td><td>Aa</td><td>Ab</td></tr>' +
1203 '<tr><td>B</td><td>Ba</td><td>Bb</td></tr>' +
1206 $table.tablesorter();
1209 $table.find( '#A1' ).attr( 'class' ),
1211 'The first column of the first row should be sortable'
1214 $table.find( '#B2b' ).attr( 'class' ),
1216 'The th element of the 2nd row of the 2nd column should be sortable'
1219 $table.find( '#C2b' ).attr( 'class' ),
1221 'The th element of the 2nd row of the 3rd column should be sortable'
1225 QUnit.test( 'rowspans in table headers should prefer the last row when rows are equal in length', 2, function ( assert ) {
1227 '<table class="sortable">' +
1229 '<tr><th rowspan="2" id="A1">A1</th><th>B2a</th></tr>' +
1230 '<tr><th id="B2b">B2b</th></tr>' +
1232 '<tr><td>A</td><td>Aa</td></tr>' +
1233 '<tr><td>B</td><td>Ba</td></tr>' +
1236 $table.tablesorter();
1239 $table.find( '#A1' ).attr( 'class' ),
1241 'The first column of the first row should be sortable'
1244 $table.find( '#B2b' ).attr( 'class' ),
1246 'The th element of the 2nd row of the 2nd column should be sortable'
1250 QUnit.test( 'holes in the table headers should not throw JS errors', 2, function ( assert ) {
1252 '<table class="sortable">' +
1254 '<tr><th id="A1">A1</th><th>B1</th><th id="C1" rowspan="2">C1</th></tr>' +
1255 '<tr><th id="A2">A2</th></tr>' +
1257 '<tr><td>A</td><td>Aa</td><td>Aaa</td></tr>' +
1258 '<tr><td>B</td><td>Ba</td><td>Bbb</td></tr>' +
1261 $table.tablesorter();
1262 assert.equal( $table.find( '#A2' ).data( 'headerIndex' ),
1264 'A2 should not be a sort header'
1266 assert.equal( $table.find( '#C1' ).data( 'headerIndex' ),
1268 'C1 should be a sort header'
1273 QUnit.test( 'td cells in thead should not be taken into account for longest row calculation', 2, function ( assert ) {
1275 '<table class="sortable">' +
1277 '<tr><th id="A1">A1</th><th>B1</th><td id="C1">C1</td></tr>' +
1278 '<tr><th id="A2">A2</th><th>B2</th><th id="C2">C2</th></tr>' +
1282 $table.tablesorter();
1283 assert.equal( $table.find( '#C2' ).data( 'headerIndex' ),
1285 'C2 should be a sort header'
1287 assert.equal( $table.find( '#C1' ).data( 'headerIndex' ),
1289 'C1 should not be a sort header'
1293 // bug 41889 - exploding rowspans in more complex cases
1295 'Rowspan exploding with row headers',
1296 '<table class="sortable">' +
1297 '<thead><tr><th id="sortme">n</th><th>foo</th><th>bar</th><th>baz</th></tr></thead>' +
1299 '<tr><td>1</td><th rowspan="2">foo</th><td rowspan="2">bar</td><td>baz</td></tr>' +
1300 '<tr><td>2</td><td>baz</td></tr>' +
1303 [ '1', 'foo', 'bar', 'baz' ],
1304 [ '2', 'foo', 'bar', 'baz' ]
1308 // bug 53211 - exploding rowspans in more complex cases
1310 'Rowspan exploding with row headers and colspans', 1, function ( assert ) {
1311 var $table = $( '<table class="sortable">' +
1312 '<thead><tr><th rowspan="2">n</th><th colspan="2">foo</th><th rowspan="2">baz</th></tr>' +
1313 '<tr><th>foo</th><th>bar</th></tr></thead>' +
1315 '<tr><td>1</td><td>foo</td><td>bar</td><td>baz</td></tr>' +
1316 '<tr><td>2</td><td>foo</td><td>bar</td><td>baz</td></tr>' +
1317 '</tbody></table>' );
1319 $table.tablesorter();
1320 assert.equal( $table.find( 'tr:eq(1) th:eq(1)' ).data( 'headerIndex' ),
1322 'Incorrect index of sort header'
1328 'Rowspan exploding with colspanned cells',
1329 '<table class="sortable">' +
1330 '<thead><tr><th id="sortme">n</th><th>foo</th><th>bar</th><th>baz</th></tr></thead>' +
1332 '<tr><td>1</td><td>foo</td><td>bar</td><td rowspan="2">baz</td></tr>' +
1333 '<tr><td>2</td><td colspan="2">foobar</td></tr>' +
1336 [ '1', 'foo', 'bar', 'baz' ],
1337 [ '2', 'foobar', 'baz' ]
1342 'Rowspan exploding with colspanned cells (2)',
1343 '<table class="sortable">' +
1344 '<thead><tr><th>n</th><th>foo</th><th>bar</th><th>baz</th><th id="sortme">n2</th></tr></thead>' +
1346 '<tr><td>1</td><td>foo</td><td>bar</td><td rowspan="2">baz</td><td>2</td></tr>' +
1347 '<tr><td>2</td><td colspan="2">foobar</td><td>1</td></tr>' +
1350 [ '2', 'foobar', 'baz', '1' ],
1351 [ '1', 'foo', 'bar', 'baz', '2' ]
1356 'Rowspan exploding with rightmost rows spanning most',
1357 '<table class="sortable">' +
1358 '<thead><tr><th id="sortme">n</th><th>foo</th><th>bar</th></tr></thead>' +
1360 '<tr><td>1</td><td rowspan="2">foo</td><td rowspan="4">bar</td></tr>' +
1361 '<tr><td>2</td></tr>' +
1362 '<tr><td>3</td><td rowspan="2">foo</td></tr>' +
1363 '<tr><td>4</td></tr>' +
1366 [ '1', 'foo', 'bar' ],
1367 [ '2', 'foo', 'bar' ],
1368 [ '3', 'foo', 'bar' ],
1369 [ '4', 'foo', 'bar' ]
1374 'Rowspan exploding with rightmost rows spanning most (2)',
1375 '<table class="sortable">' +
1376 '<thead><tr><th id="sortme">n</th><th>foo</th><th>bar</th><th>baz</th></tr></thead>' +
1378 '<tr><td>1</td><td rowspan="2">foo</td><td rowspan="4">bar</td><td>baz</td></tr>' +
1379 '<tr><td>2</td><td>baz</td></tr>' +
1380 '<tr><td>3</td><td rowspan="2">foo</td><td>baz</td></tr>' +
1381 '<tr><td>4</td><td>baz</td></tr>' +
1384 [ '1', 'foo', 'bar', 'baz' ],
1385 [ '2', 'foo', 'bar', 'baz' ],
1386 [ '3', 'foo', 'bar', 'baz' ],
1387 [ '4', 'foo', 'bar', 'baz' ]
1392 'Rowspan exploding with row-and-colspanned cells',
1393 '<table class="sortable">' +
1394 '<thead><tr><th id="sortme">n</th><th>foo1</th><th>foo2</th><th>bar</th><th>baz</th></tr></thead>' +
1396 '<tr><td>1</td><td rowspan="2">foo1</td><td rowspan="2">foo2</td><td rowspan="4">bar</td><td>baz</td></tr>' +
1397 '<tr><td>2</td><td>baz</td></tr>' +
1398 '<tr><td>3</td><td colspan="2" rowspan="2">foo</td><td>baz</td></tr>' +
1399 '<tr><td>4</td><td>baz</td></tr>' +
1402 [ '1', 'foo1', 'foo2', 'bar', 'baz' ],
1403 [ '2', 'foo1', 'foo2', 'bar', 'baz' ],
1404 [ '3', 'foo', 'bar', 'baz' ],
1405 [ '4', 'foo', 'bar', 'baz' ]
1410 'Rowspan exploding with uneven rowspan layout',
1411 '<table class="sortable">' +
1412 '<thead><tr><th id="sortme">n</th><th>foo1</th><th>foo2</th><th>foo3</th><th>bar</th><th>baz</th></tr></thead>' +
1414 '<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>' +
1415 '<tr><td>2</td><td rowspan="3">bar</td><td>baz</td></tr>' +
1416 '<tr><td>3</td><td rowspan="2">foo1</td><td rowspan="2">foo2</td><td rowspan="2">foo3</td><td>baz</td></tr>' +
1417 '<tr><td>4</td><td>baz</td></tr>' +
1420 [ '1', 'foo1', 'foo2', 'foo3', 'bar', 'baz' ],
1421 [ '2', 'foo1', 'foo2', 'foo3', 'bar', 'baz' ],
1422 [ '3', 'foo1', 'foo2', 'foo3', 'bar', 'baz' ],
1423 [ '4', 'foo1', 'foo2', 'foo3', 'bar', 'baz' ]
1427 QUnit.test( 'bug 105731 - incomplete rows in table body', 3, function ( assert ) {
1428 var $table, parsers;
1430 '<table class="sortable">' +
1431 '<tr><th>A</th><th>B</th></tr>' +
1432 '<tr><td>3</td></tr>' +
1433 '<tr><td>1</td><td>2</td></tr>' +
1436 $table.tablesorter();
1437 $table.find( '.headerSort:eq(0)' ).click();
1438 // now the first row have 2 columns
1439 $table.find( '.headerSort:eq(1)' ).click();
1441 parsers = $table.data( 'tablesorter' ).config.parsers;
1446 'detectParserForColumn() detect 2 parsers'
1452 'detectParserForColumn() detect parser.id "number" for second column'
1456 parsers[ 1 ].format( $table.find( 'tbody > tr > td:eq(1)' ).text() ),
1458 'empty cell is sorted as number -Infinity'
1462 QUnit.test( 'bug T114721 - use of expand-child class', 2, function ( assert ) {
1463 var $table, parsers;
1465 '<table class="sortable">' +
1466 '<tr><th>A</th><th>B</th></tr>' +
1467 '<tr><td>b</td><td>4</td></tr>' +
1468 '<tr class="expand-child"><td colspan="2">some text follow b</td></tr>' +
1469 '<tr><td>a</td><td>2</td></tr>' +
1470 '<tr class="expand-child"><td colspan="2">some text follow a</td></tr>' +
1471 '<tr class="expand-child"><td colspan="2">more text</td></tr>' +
1474 $table.tablesorter();
1475 $table.find( '.headerSort:eq(0)' ).click();
1478 tableExtract( $table ),
1481 [ 'some text follow a' ],
1484 [ 'some text follow b' ]
1486 'row with expand-child class follow above row'
1489 parsers = $table.data( 'tablesorter' ).config.parsers;
1493 'detectParserForColumn() detect parser.id "number" for second column'
1497 }( jQuery, mediaWiki ) );