Import: Handle uploads with sha1 starting with 0 properly
[mediawiki.git] / tests / qunit / suites / resources / jquery / jquery.tablesorter.test.js
blobb09bb2825bc9de8444ea0389019d6f128e4cbd78
1 ( function ( $, mw ) {
2         var header = [ 'Planet', 'Radius (km)' ],
4                 // Data set "planets"
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 ],
14                 planetsRowspan,
15                 planetsRowspanII,
16                 planetsAscNameLegacy,
18                 // Data set "simple"
19                 a1 = [ 'A', '1' ],
20                 a2 = [ 'A', '2' ],
21                 a3 = [ 'A', '3' ],
22                 b1 = [ 'B', '1' ],
23                 b2 = [ 'B', '2' ],
24                 b3 = [ 'B', '3' ],
25                 simple = [ a2, b3, a1, a3, b2, b1 ],
26                 simpleAsc = [ a1, a2, a3, b1, b2, b3 ],
27                 simpleDescasc = [ b1, b2, b3, a1, a2, a3 ],
29                 // Data set "colspan"
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 ],
38                 // Data set "ipv4"
39                 ipv4 = [
40                         // Some randomly generated fake IPs
41                         [ '45.238.27.109' ],
42                         [ '44.172.9.22' ],
43                         [ '247.240.82.209' ],
44                         [ '204.204.132.158' ],
45                         [ '170.38.91.162' ],
46                         [ '197.219.164.9' ],
47                         [ '45.68.154.72' ],
48                         [ '182.195.149.80' ]
49                 ],
50                 ipv4Sorted = [
51                         // Sort order should go octet by octet
52                         [ '44.172.9.22' ],
53                         [ '45.68.154.72' ],
54                         [ '45.238.27.109' ],
55                         [ '170.38.91.162' ],
56                         [ '182.195.149.80' ],
57                         [ '197.219.164.9' ],
58                         [ '204.204.132.158' ],
59                         [ '247.240.82.209' ]
60                 ],
62                 // Data set "umlaut"
63                 umlautWords = [
64                         [ 'Günther' ],
65                         [ 'Peter' ],
66                         [ 'Björn' ],
67                         [ 'Bjorn' ],
68                         [ 'Apfel' ],
69                         [ 'Äpfel' ],
70                         [ 'Strasse' ],
71                         [ 'Sträßschen' ]
72                 ],
73                 umlautWordsSorted = [
74                         [ 'Äpfel' ],
75                         [ 'Apfel' ],
76                         [ 'Björn' ],
77                         [ 'Bjorn' ],
78                         [ 'Günther' ],
79                         [ 'Peter' ],
80                         [ 'Sträßschen' ],
81                         [ 'Strasse' ]
82                 ],
84                 complexMDYDates = [
85                         [ 'January, 19 2010' ],
86                         [ 'April 21 1991' ],
87                         [ '04 22 1991' ],
88                         [ '5.12.1990' ],
89                         [ 'December 12 \'10' ]
90                 ],
91                 complexMDYSorted = [
92                         [ '5.12.1990' ],
93                         [ 'April 21 1991' ],
94                         [ '04 22 1991' ],
95                         [ 'January, 19 2010' ],
96                         [ 'December 12 \'10' ]
97                 ],
99                 currencyUnsorted = [
100                         [ '1.02 $' ],
101                         [ '$ 3.00' ],
102                         [ '€ 2,99' ],
103                         [ '$ 1.00' ],
104                         [ '$3.50' ],
105                         [ '$ 1.50' ],
106                         [ '€ 0.99' ]
107                 ],
108                 currencySorted = [
109                         [ '€ 0.99' ],
110                         [ '$ 1.00' ],
111                         [ '1.02 $' ],
112                         [ '$ 1.50' ],
113                         [ '$ 3.00' ],
114                         [ '$3.50' ],
115                         // Comma's sort after dots
116                         // Not intentional but test to detect changes
117                         [ '€ 2,99' ]
118                 ],
120                 numbers = [
121                         [ '12' ],
122                         [ '7' ],
123                         [ '13,000' ],
124                         [ '9' ],
125                         [ '14' ],
126                         [ '8.0' ]
127                 ],
128                 numbersAsc = [
129                         [ '7' ],
130                         [ '8.0' ],
131                         [ '9' ],
132                         [ '12' ],
133                         [ '14' ],
134                         [ '13,000' ]
135                 ],
137                 correctDateSorting1 = [
138                         [ '01 January 2010' ],
139                         [ '05 February 2010' ],
140                         [ '16 January 2010' ]
141                 ],
142                 correctDateSortingSorted1 = [
143                         [ '01 January 2010' ],
144                         [ '16 January 2010' ],
145                         [ '05 February 2010' ]
146                 ],
148                 correctDateSorting2 = [
149                         [ 'January 01 2010' ],
150                         [ 'February 05 2010' ],
151                         [ 'January 16 2010' ]
152                 ],
153                 correctDateSortingSorted2 = [
154                         [ 'January 01 2010' ],
155                         [ 'January 16 2010' ],
156                         [ 'February 05 2010' ]
157                 ],
158                 isoDateSorting = [
159                         [ '2010-02-01' ],
160                         [ '2009-12-25T12:30:45.001Z' ],
161                         [ '2010-01-31' ],
162                         [ '2009' ],
163                         [ '2009-12-25T12:30:45' ],
164                         [ '2009-12-25T12:30:45.111' ],
165                         [ '2009-12-25T12:30:45+01:00' ]
166                 ],
167                 isoDateSortingSorted = [
168                         [ '2009' ],
169                         [ '2009-12-25T12:30:45' ],
170                         [ '2009-12-25T12:30:45+01:00' ],
171                         [ '2009-12-25T12:30:45.001Z' ],
172                         [ '2009-12-25T12:30:45.111' ],
173                         [ '2010-01-31' ],
174                         [ '2010-02-01' ]
175                 ];
177         QUnit.module( 'jquery.tablesorter', QUnit.newMwEnvironment( {
178                 setup: function () {
179                         this.liveMonths = mw.language.months;
180                         mw.language.months = {
181                                 keys: {
182                                         names: [ 'january', 'february', 'march', 'april', 'may_long', 'june',
183                                                 'july', 'august', 'september', 'october', 'november', 'december' ],
184                                         genitive: [ 'january-gen', 'february-gen', 'march-gen', 'april-gen', 'may-gen', 'june-gen',
185                                                 'july-gen', 'august-gen', 'september-gen', 'october-gen', 'november-gen', 'december-gen' ],
186                                         abbrev: [ 'jan', 'feb', 'mar', 'apr', 'may', 'jun',
187                                                 'jul', 'aug', 'sep', 'oct', 'nov', 'dec' ]
188                                 },
189                                 names: [ 'January', 'February', 'March', 'April', 'May', 'June',
190                                                 'July', 'August', 'September', 'October', 'November', 'December' ],
191                                 genitive: [ 'January', 'February', 'March', 'April', 'May', 'June',
192                                                 'July', 'August', 'September', 'October', 'November', 'December' ],
193                                 abbrev: [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
194                                                 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ]
195                         };
196                 },
197                 teardown: function () {
198                         mw.language.months = this.liveMonths;
199                 },
200                 config: {
201                         wgDefaultDateFormat: 'dmy',
202                         wgSeparatorTransformTable: [ '', '' ],
203                         wgDigitTransformTable: [ '', '' ],
204                         wgPageContentLanguage: 'en'
205                 }
206         } ) );
208         /**
209          * Create an HTML table from an array of row arrays containing text strings.
210          * First row will be header row. No fancy rowspan/colspan stuff.
211          *
212          * @param {string[]} header
213          * @param {string[][]} data
214          * @return {jQuery}
215          */
216         function tableCreate( header, data ) {
217                 var i,
218                         $table = $( '<table class="sortable"><thead></thead><tbody></tbody></table>' ),
219                         $thead = $table.find( 'thead' ),
220                         $tbody = $table.find( 'tbody' ),
221                         $tr = $( '<tr>' );
223                 $.each( header, function ( i, str ) {
224                         var $th = $( '<th>' );
225                         $th.text( str ).appendTo( $tr );
226                 } );
227                 $tr.appendTo( $thead );
229                 for ( i = 0; i < data.length; i++ ) {
230                         /*jshint loopfunc: true */
231                         $tr = $( '<tr>' );
232                         $.each( data[ i ], function ( j, str ) {
233                                 var $td = $( '<td>' );
234                                 $td.text( str ).appendTo( $tr );
235                         } );
236                         $tr.appendTo( $tbody );
237                 }
238                 return $table;
239         }
241         /**
242          * Extract text from table.
243          *
244          * @param {jQuery} $table
245          * @return {string[][]}
246          */
247         function tableExtract( $table ) {
248                 var data = [];
250                 $table.find( 'tbody' ).find( 'tr' ).each( function ( i, tr ) {
251                         var row = [];
252                         $( tr ).find( 'td,th' ).each( function ( i, td ) {
253                                 row.push( $( td ).text() );
254                         } );
255                         data.push( row );
256                 } );
257                 return data;
258         }
260         /**
261          * Run a table test by building a table with the given data,
262          * running some callback on it, then checking the results.
263          *
264          * @param {string} msg text to pass on to qunit for the comparison
265          * @param {string[]} header cols to make the table
266          * @param {string[][]} data rows/cols to make the table
267          * @param {string[][]} expected rows/cols to compare against at end
268          * @param {function($table)} callback something to do with the table before we compare
269          */
270         function tableTest( msg, header, data, expected, callback ) {
271                 QUnit.test( msg, 1, function ( assert ) {
272                         var extracted,
273                                 $table = tableCreate( header, data );
275                         // Give caller a chance to set up sorting and manipulate the table.
276                         callback( $table );
278                         // Table sorting is done synchronously; if it ever needs to change back
279                         // to asynchronous, we'll need a timeout or a callback here.
280                         extracted = tableExtract( $table );
281                         assert.deepEqual( extracted, expected, msg );
282                 } );
283         }
285         /**
286          * Run a table test by building a table with the given HTML,
287          * running some callback on it, then checking the results.
288          *
289          * @param {string} msg text to pass on to qunit for the comparison
290          * @param {string} html HTML to make the table
291          * @param {string[][]} expected Rows/cols to compare against at end
292          * @param {function($table)} callback Something to do with the table before we compare
293          */
294         function tableTestHTML( msg, html, expected, callback ) {
295                 QUnit.test( msg, 1, function ( assert ) {
296                         var extracted,
297                                 $table = $( html );
299                         // Give caller a chance to set up sorting and manipulate the table.
300                         if ( callback ) {
301                                 callback( $table );
302                         } else {
303                                 $table.tablesorter();
304                                 $table.find( '#sortme' ).click();
305                         }
307                         // Table sorting is done synchronously; if it ever needs to change back
308                         // to asynchronous, we'll need a timeout or a callback here.
309                         extracted = tableExtract( $table );
310                         assert.deepEqual( extracted, expected, msg );
311                 } );
312         }
314         function reversed( arr ) {
315                 // Clone array
316                 var arr2 = arr.slice( 0 );
318                 arr2.reverse();
320                 return arr2;
321         }
323         // Sample data set using planets named and their radius
325         tableTest(
326                 'Basic planet table: sorting initially - ascending by name',
327                 header,
328                 planets,
329                 planetsAscName,
330                 function ( $table ) {
331                         $table.tablesorter( { sortList: [
332                                 { 0: 'asc' }
333                         ] } );
334                 }
335         );
336         tableTest(
337                 'Basic planet table: sorting initially - descending by radius',
338                 header,
339                 planets,
340                 reversed( planetsAscRadius ),
341                 function ( $table ) {
342                         $table.tablesorter( { sortList: [
343                                 { 1: 'desc' }
344                         ] } );
345                 }
346         );
347         tableTest(
348                 'Basic planet table: ascending by name',
349                 header,
350                 planets,
351                 planetsAscName,
352                 function ( $table ) {
353                         $table.tablesorter();
354                         $table.find( '.headerSort:eq(0)' ).click();
355                 }
356         );
357         tableTest(
358                 'Basic planet table: ascending by name a second time',
359                 header,
360                 planets,
361                 planetsAscName,
362                 function ( $table ) {
363                         $table.tablesorter();
364                         $table.find( '.headerSort:eq(0)' ).click();
365                 }
366         );
367         tableTest(
368                 'Basic planet table: ascending by name (multiple clicks)',
369                 header,
370                 planets,
371                 planetsAscName,
372                 function ( $table ) {
373                         $table.tablesorter();
374                         $table.find( '.headerSort:eq(0)' ).click();
375                         $table.find( '.headerSort:eq(1)' ).click();
376                         $table.find( '.headerSort:eq(0)' ).click();
377                 }
378         );
379         tableTest(
380                 'Basic planet table: descending by name',
381                 header,
382                 planets,
383                 reversed( planetsAscName ),
384                 function ( $table ) {
385                         $table.tablesorter();
386                         $table.find( '.headerSort:eq(0)' ).click().click();
387                 }
388         );
389         tableTest(
390                 'Basic planet table: ascending radius',
391                 header,
392                 planets,
393                 planetsAscRadius,
394                 function ( $table ) {
395                         $table.tablesorter();
396                         $table.find( '.headerSort:eq(1)' ).click();
397                 }
398         );
399         tableTest(
400                 'Basic planet table: descending radius',
401                 header,
402                 planets,
403                 reversed( planetsAscRadius ),
404                 function ( $table ) {
405                         $table.tablesorter();
406                         $table.find( '.headerSort:eq(1)' ).click().click();
407                 }
408         );
409         tableTest(
410                 'Sorting multiple columns by passing sort list',
411                 header,
412                 simple,
413                 simpleAsc,
414                 function ( $table ) {
415                         $table.tablesorter(
416                                 { sortList: [
417                                         { 0: 'asc' },
418                                         { 1: 'asc' }
419                                 ] }
420                         );
421                 }
422         );
423         tableTest(
424                 'Sorting multiple columns by programmatically triggering sort()',
425                 header,
426                 simple,
427                 simpleDescasc,
428                 function ( $table ) {
429                         $table.tablesorter();
430                         $table.data( 'tablesorter' ).sort(
431                                 [
432                                         { 0: 'desc' },
433                                         { 1: 'asc' }
434                                 ]
435                         );
436                 }
437         );
438         tableTest(
439                 'Reset to initial sorting by triggering sort() without any parameters',
440                 header,
441                 simple,
442                 simpleAsc,
443                 function ( $table ) {
444                         $table.tablesorter(
445                                 { sortList: [
446                                         { 0: 'asc' },
447                                         { 1: 'asc' }
448                                 ] }
449                         );
450                         $table.data( 'tablesorter' ).sort(
451                                 [
452                                         { 0: 'desc' },
453                                         { 1: 'asc' }
454                                 ]
455                         );
456                         $table.data( 'tablesorter' ).sort();
457                 }
458         );
459         tableTest(
460                 'Sort via click event after having initialized the tablesorter with initial sorting',
461                 header,
462                 simple,
463                 simpleDescasc,
464                 function ( $table ) {
465                         $table.tablesorter(
466                                 { sortList: [ { 0: 'asc' }, { 1: 'asc' } ] }
467                         );
468                         $table.find( '.headerSort:eq(0)' ).click();
469                 }
470         );
471         tableTest(
472                 'Multi-sort via click event after having initialized the tablesorter with initial sorting',
473                 header,
474                 simple,
475                 simpleAsc,
476                 function ( $table ) {
477                         $table.tablesorter(
478                                 { sortList: [ { 0: 'desc' }, { 1: 'desc' } ] }
479                         );
480                         $table.find( '.headerSort:eq(0)' ).click();
482                         // Pretend to click while pressing the multi-sort key
483                         var event = $.Event( 'click' );
484                         event[ $table.data( 'tablesorter' ).config.sortMultiSortKey ] = true;
485                         $table.find( '.headerSort:eq(1)' ).trigger( event );
486                 }
487         );
488         QUnit.test( 'Reset sorting making table appear unsorted', 3, function ( assert ) {
489                 var $table = tableCreate( header, simple );
490                 $table.tablesorter(
491                         { sortList: [
492                                 { 0: 'desc' },
493                                 { 1: 'asc' }
494                         ] }
495                 );
496                 $table.data( 'tablesorter' ).sort( [] );
498                 assert.equal(
499                         $table.find( 'th.headerSortUp' ).length + $table.find( 'th.headerSortDown' ).length,
500                         0,
501                         'No sort specific sort classes addign to header cells'
502                 );
504                 assert.equal(
505                         $table.find( 'th' ).first().attr( 'title' ),
506                         mw.msg( 'sort-ascending' ),
507                         'First header cell has default title'
508                 );
510                 assert.equal(
511                         $table.find( 'th' ).first().attr( 'title' ),
512                         $table.find( 'th' ).last().attr( 'title' ),
513                         'Both header cells\' titles match'
514                 );
515         } );
517         // Sorting with colspans
519         tableTest( 'Sorting with colspanned headers: spanned column',
520                 header4,
521                 colspanInitial,
522                 [ aaa1, aab5, abc3, bbc2, caa4 ],
523                 function ( $table ) {
524                         // Make colspanned header for test
525                         $table.find( 'tr:eq(0) th:eq(1), tr:eq(0) th:eq(2)' ).remove();
526                         $table.find( 'tr:eq(0) th:eq(0)' ).attr( 'colspan', '3' );
528                         $table.tablesorter();
529                         $table.find( '.headerSort:eq(0)' ).click();
530                 }
531         );
532         tableTest( 'Sorting with colspanned headers: sort spanned column twice',
533                 header4,
534                 colspanInitial,
535                 [ caa4, bbc2, abc3, aab5, aaa1 ],
536                 function ( $table ) {
537                         // Make colspanned header for test
538                         $table.find( 'tr:eq(0) th:eq(1), tr:eq(0) th:eq(2)' ).remove();
539                         $table.find( 'tr:eq(0) th:eq(0)' ).attr( 'colspan', '3' );
541                         $table.tablesorter();
542                         $table.find( '.headerSort:eq(0)' ).click();
543                         $table.find( '.headerSort:eq(0)' ).click();
544                 }
545         );
546         tableTest( 'Sorting with colspanned headers: subsequent column',
547                 header4,
548                 colspanInitial,
549                 [ aaa1, bbc2, abc3, caa4, aab5 ],
550                 function ( $table ) {
551                         // Make colspanned header for test
552                         $table.find( 'tr:eq(0) th:eq(1), tr:eq(0) th:eq(2)' ).remove();
553                         $table.find( 'tr:eq(0) th:eq(0)' ).attr( 'colspan', '3' );
555                         $table.tablesorter();
556                         $table.find( '.headerSort:eq(1)' ).click();
557                 }
558         );
559         tableTest( 'Sorting with colspanned headers: sort subsequent column twice',
560                 header4,
561                 colspanInitial,
562                 [ aab5, caa4, abc3, bbc2, aaa1 ],
563                 function ( $table ) {
564                         // Make colspanned header for test
565                         $table.find( 'tr:eq(0) th:eq(1), tr:eq(0) th:eq(2)' ).remove();
566                         $table.find( 'tr:eq(0) th:eq(0)' ).attr( 'colspan', '3' );
568                         $table.tablesorter();
569                         $table.find( '.headerSort:eq(1)' ).click();
570                         $table.find( '.headerSort:eq(1)' ).click();
571                 }
572         );
574         QUnit.test( 'Basic planet table: one unsortable column', 3, function ( assert ) {
575                 var $table = tableCreate( header, planets ),
576                         $cell;
577                 $table.find( 'tr:eq(0) > th:eq(0)' ).addClass( 'unsortable' );
579                 $table.tablesorter();
580                 $table.find( 'tr:eq(0) > th:eq(0)' ).click();
582                 assert.deepEqual(
583                         tableExtract( $table ),
584                         planets,
585                         'table not sorted'
586                 );
588                 $cell = $table.find( 'tr:eq(0) > th:eq(0)' );
589                 $table.find( 'tr:eq(0) > th:eq(1)' ).click();
591                 assert.equal(
592                         $cell.hasClass( 'headerSortUp' ) || $cell.hasClass( 'headerSortDown' ),
593                         false,
594                         'after sort: no class headerSortUp or headerSortDown'
595                 );
597                 assert.equal(
598                         $cell.attr( 'title' ),
599                         undefined,
600                         'after sort: no title tag added'
601                 );
603         } );
605         // Regression tests!
606         tableTest(
607                 'Bug 28775: German-style (dmy) short numeric dates',
608                 [ 'Date' ],
609                 [
610                         // German-style dates are day-month-year
611                         [ '11.11.2011' ],
612                         [ '01.11.2011' ],
613                         [ '02.10.2011' ],
614                         [ '03.08.2011' ],
615                         [ '09.11.2011' ]
616                 ],
617                 [
618                         // Sorted by ascending date
619                         [ '03.08.2011' ],
620                         [ '02.10.2011' ],
621                         [ '01.11.2011' ],
622                         [ '09.11.2011' ],
623                         [ '11.11.2011' ]
624                 ],
625                 function ( $table ) {
626                         mw.config.set( 'wgDefaultDateFormat', 'dmy' );
627                         mw.config.set( 'wgPageContentLanguage', 'de' );
629                         $table.tablesorter();
630                         $table.find( '.headerSort:eq(0)' ).click();
631                 }
632         );
634         tableTest(
635                 'Bug 28775: American-style (mdy) short numeric dates',
636                 [ 'Date' ],
637                 [
638                         // American-style dates are month-day-year
639                         [ '11.11.2011' ],
640                         [ '01.11.2011' ],
641                         [ '02.10.2011' ],
642                         [ '03.08.2011' ],
643                         [ '09.11.2011' ]
644                 ],
645                 [
646                         // Sorted by ascending date
647                         [ '01.11.2011' ],
648                         [ '02.10.2011' ],
649                         [ '03.08.2011' ],
650                         [ '09.11.2011' ],
651                         [ '11.11.2011' ]
652                 ],
653                 function ( $table ) {
654                         mw.config.set( 'wgDefaultDateFormat', 'mdy' );
656                         $table.tablesorter();
657                         $table.find( '.headerSort:eq(0)' ).click();
658                 }
659         );
661         tableTest(
662                 'Bug 17141: IPv4 address sorting',
663                 [ 'IP' ],
664                 ipv4,
665                 ipv4Sorted,
666                 function ( $table ) {
667                         $table.tablesorter();
668                         $table.find( '.headerSort:eq(0)' ).click();
669                 }
670         );
671         tableTest(
672                 'Bug 17141: IPv4 address sorting (reverse)',
673                 [ 'IP' ],
674                 ipv4,
675                 reversed( ipv4Sorted ),
676                 function ( $table ) {
677                         $table.tablesorter();
678                         $table.find( '.headerSort:eq(0)' ).click().click();
679                 }
680         );
682         tableTest(
683                 'Accented Characters with custom collation',
684                 [ 'Name' ],
685                 umlautWords,
686                 umlautWordsSorted,
687                 function ( $table ) {
688                         mw.config.set( 'tableSorterCollation', {
689                                 ä: 'ae',
690                                 ö: 'oe',
691                                 ß: 'ss',
692                                 ü: 'ue'
693                         } );
695                         $table.tablesorter();
696                         $table.find( '.headerSort:eq(0)' ).click();
697                 }
698         );
700         QUnit.test( 'Rowspan not exploded on init', 1, function ( assert ) {
701                 var $table = tableCreate( header, planets );
703                 // Modify the table to have a multiple-row-spanning cell:
704                 // - Remove 2nd cell of 4th row, and, 2nd cell or 5th row.
705                 $table.find( 'tr:eq(3) td:eq(1), tr:eq(4) td:eq(1)' ).remove();
706                 // - Set rowspan for 2nd cell of 3rd row to 3.
707                 //   This covers the removed cell in the 4th and 5th row.
708                 $table.find( 'tr:eq(2) td:eq(1)' ).attr( 'rowspan', '3' );
710                 $table.tablesorter();
712                 assert.equal(
713                         $table.find( 'tr:eq(2) td:eq(1)' ).prop( 'rowSpan' ),
714                         3,
715                         'Rowspan not exploded'
716                 );
717         } );
719         planetsRowspan = [
720                 [ 'Earth', '6051.8' ],
721                 jupiter,
722                 [ 'Mars', '6051.8' ],
723                 mercury,
724                 saturn,
725                 venus
726         ];
727         planetsRowspanII = [ jupiter, mercury, saturn, venus, [ 'Venus', '6371.0' ], [ 'Venus', '3390.0' ] ];
729         tableTest(
730                 'Basic planet table: same value for multiple rows via rowspan',
731                 header,
732                 planets,
733                 planetsRowspan,
734                 function ( $table ) {
735                         // Modify the table to have a multiple-row-spanning cell:
736                         // - Remove 2nd cell of 4th row, and, 2nd cell or 5th row.
737                         $table.find( 'tr:eq(3) td:eq(1), tr:eq(4) td:eq(1)' ).remove();
738                         // - Set rowspan for 2nd cell of 3rd row to 3.
739                         //   This covers the removed cell in the 4th and 5th row.
740                         $table.find( 'tr:eq(2) td:eq(1)' ).attr( 'rowspan', '3' );
742                         $table.tablesorter();
743                         $table.find( '.headerSort:eq(0)' ).click();
744                 }
745         );
746         tableTest(
747                 'Basic planet table: same value for multiple rows via rowspan (sorting initially)',
748                 header,
749                 planets,
750                 planetsRowspan,
751                 function ( $table ) {
752                         // Modify the table to have a multiple-row-spanning cell:
753                         // - Remove 2nd cell of 4th row, and, 2nd cell or 5th row.
754                         $table.find( 'tr:eq(3) td:eq(1), tr:eq(4) td:eq(1)' ).remove();
755                         // - Set rowspan for 2nd 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(1)' ).attr( 'rowspan', '3' );
759                         $table.tablesorter( { sortList: [
760                                 { 0: 'asc' }
761                         ] } );
762                 }
763         );
764         tableTest(
765                 'Basic planet table: Same value for multiple rows via rowspan II',
766                 header,
767                 planets,
768                 planetsRowspanII,
769                 function ( $table ) {
770                         // Modify the table to have a multiple-row-spanning cell:
771                         // - Remove 1st cell of 4th row, and, 1st cell or 5th row.
772                         $table.find( 'tr:eq(3) td:eq(0), tr:eq(4) td:eq(0)' ).remove();
773                         // - Set rowspan for 1st cell of 3rd row to 3.
774                         //   This covers the removed cell in the 4th and 5th row.
775                         $table.find( 'tr:eq(2) td:eq(0)' ).attr( 'rowspan', '3' );
777                         $table.tablesorter();
778                         $table.find( '.headerSort:eq(0)' ).click();
779                 }
780         );
782         tableTest(
783                 'Complex date parsing I',
784                 [ 'date' ],
785                 complexMDYDates,
786                 complexMDYSorted,
787                 function ( $table ) {
788                         mw.config.set( 'wgDefaultDateFormat', 'mdy' );
790                         $table.tablesorter();
791                         $table.find( '.headerSort:eq(0)' ).click();
792                 }
793         );
795         tableTest(
796                 'Currency parsing I',
797                 [ 'currency' ],
798                 currencyUnsorted,
799                 currencySorted,
800                 function ( $table ) {
801                         $table.tablesorter();
802                         $table.find( '.headerSort:eq(0)' ).click();
803                 }
804         );
806         planetsAscNameLegacy = planetsAscName.slice( 0 );
807         planetsAscNameLegacy[ 4 ] = planetsAscNameLegacy[ 5 ];
808         planetsAscNameLegacy.pop();
810         tableTest(
811                 'Legacy compat with .sortbottom',
812                 header,
813                 planets,
814                 planetsAscNameLegacy,
815                 function ( $table ) {
816                         $table.find( 'tr:last' ).addClass( 'sortbottom' );
817                         $table.tablesorter();
818                         $table.find( '.headerSort:eq(0)' ).click();
819                 }
820         );
822         QUnit.test( 'Test detection routine', 1, function ( assert ) {
823                 var $table;
824                 $table = $(
825                         '<table class="sortable">' +
826                                 '<caption>CAPTION</caption>' +
827                                 '<tr><th>THEAD</th></tr>' +
828                                 '<tr><td>1</td></tr>' +
829                                 '<tr class="sortbottom"><td>text</td></tr>' +
830                                 '</table>'
831                 );
832                 $table.tablesorter();
833                 $table.find( '.headerSort:eq(0)' ).click();
835                 assert.equal(
836                         $table.data( 'tablesorter' ).config.parsers[ 0 ].id,
837                         'number',
838                         'Correctly detected column content skipping sortbottom'
839                 );
840         } );
842         /** FIXME: the diff output is not very readeable. */
843         QUnit.test( 'bug 32047 - caption must be before thead', 1, function ( assert ) {
844                 var $table;
845                 $table = $(
846                         '<table class="sortable">' +
847                                 '<caption>CAPTION</caption>' +
848                                 '<tr><th>THEAD</th></tr>' +
849                                 '<tr><td>A</td></tr>' +
850                                 '<tr><td>B</td></tr>' +
851                                 '<tr class="sortbottom"><td>TFOOT</td></tr>' +
852                                 '</table>'
853                 );
854                 $table.tablesorter();
856                 assert.equal(
857                         $table.children().get( 0 ).nodeName,
858                         'CAPTION',
859                         'First element after <thead> must be <caption> (bug 32047)'
860                 );
861         } );
863         QUnit.test( 'data-sort-value attribute, when available, should override sorting position', 3, function ( assert ) {
864                 var $table, data;
866                 // Example 1: All cells except one cell without data-sort-value,
867                 // which should be sorted at it's text content value.
868                 $table = $(
869                         '<table class="sortable"><thead><tr><th>Data</th></tr></thead>' +
870                                 '<tbody>' +
871                                 '<tr><td>Cheetah</td></tr>' +
872                                 '<tr><td data-sort-value="Apple">Bird</td></tr>' +
873                                 '<tr><td data-sort-value="Bananna">Ferret</td></tr>' +
874                                 '<tr><td data-sort-value="Drupe">Elephant</td></tr>' +
875                                 '<tr><td data-sort-value="Cherry">Dolphin</td></tr>' +
876                                 '</tbody></table>'
877                 );
878                 $table.tablesorter().find( '.headerSort:eq(0)' ).click();
880                 data = [];
881                 $table.find( 'tbody > tr' ).each( function ( i, tr ) {
882                         $( tr ).find( 'td' ).each( function ( i, td ) {
883                                 data.push( {
884                                         data: $( td ).data( 'sortValue' ),
885                                         text: $( td ).text()
886                                 } );
887                         } );
888                 } );
890                 assert.deepEqual( data, [
891                         {
892                                 data: 'Apple',
893                                 text: 'Bird'
894                         },
895                         {
896                                 data: 'Bananna',
897                                 text: 'Ferret'
898                         },
899                         {
900                                 data: undefined,
901                                 text: 'Cheetah'
902                         },
903                         {
904                                 data: 'Cherry',
905                                 text: 'Dolphin'
906                         },
907                         {
908                                 data: 'Drupe',
909                                 text: 'Elephant'
910                         }
911                 ], 'Order matches expected order (based on data-sort-value attribute values)' );
913                 // Example 2
914                 $table = $(
915                         '<table class="sortable"><thead><tr><th>Data</th></tr></thead>' +
916                                 '<tbody>' +
917                                 '<tr><td>D</td></tr>' +
918                                 '<tr><td data-sort-value="E">A</td></tr>' +
919                                 '<tr><td>B</td></tr>' +
920                                 '<tr><td>G</td></tr>' +
921                                 '<tr><td data-sort-value="F">C</td></tr>' +
922                                 '</tbody></table>'
923                 );
924                 $table.tablesorter().find( '.headerSort:eq(0)' ).click();
926                 data = [];
927                 $table.find( 'tbody > tr' ).each( function ( i, tr ) {
928                         $( tr ).find( 'td' ).each( function ( i, td ) {
929                                 data.push( {
930                                         data: $( td ).data( 'sortValue' ),
931                                         text: $( td ).text()
932                                 } );
933                         } );
934                 } );
936                 assert.deepEqual( data, [
937                         {
938                                 data: undefined,
939                                 text: 'B'
940                         },
941                         {
942                                 data: undefined,
943                                 text: 'D'
944                         },
945                         {
946                                 data: 'E',
947                                 text: 'A'
948                         },
949                         {
950                                 data: 'F',
951                                 text: 'C'
952                         },
953                         {
954                                 data: undefined,
955                                 text: 'G'
956                         }
957                 ], 'Order matches expected order (based on data-sort-value attribute values)' );
959                 // Example 3: Test that live changes are used from data-sort-value,
960                 // even if they change after the tablesorter is constructed (bug 38152).
961                 $table = $(
962                         '<table class="sortable"><thead><tr><th>Data</th></tr></thead>' +
963                                 '<tbody>' +
964                                 '<tr><td>D</td></tr>' +
965                                 '<tr><td data-sort-value="1">A</td></tr>' +
966                                 '<tr><td>B</td></tr>' +
967                                 '<tr><td data-sort-value="2">G</td></tr>' +
968                                 '<tr><td>C</td></tr>' +
969                                 '</tbody></table>'
970                 );
971                 // initialize table sorter and sort once
972                 $table
973                         .tablesorter()
974                         .find( '.headerSort:eq(0)' ).click();
976                 // Change the sortValue data properties (bug 38152)
977                 // - change data
978                 $table.find( 'td:contains(A)' ).data( 'sortValue', 3 );
979                 // - add data
980                 $table.find( 'td:contains(B)' ).data( 'sortValue', 1 );
981                 // - remove data, bring back attribute: 2
982                 $table.find( 'td:contains(G)' ).removeData( 'sortValue' );
984                 // Now sort again (twice, so it is back at Ascending)
985                 $table.find( '.headerSort:eq(0)' ).click();
986                 $table.find( '.headerSort:eq(0)' ).click();
988                 data = [];
989                 $table.find( 'tbody > tr' ).each( function ( i, tr ) {
990                         $( tr ).find( 'td' ).each( function ( i, td ) {
991                                 data.push( {
992                                         data: $( td ).data( 'sortValue' ),
993                                         text: $( td ).text()
994                                 } );
995                         } );
996                 } );
998                 assert.deepEqual( data, [
999                         {
1000                                 data: 1,
1001                                 text: 'B'
1002                         },
1003                         {
1004                                 data: 2,
1005                                 text: 'G'
1006                         },
1007                         {
1008                                 data: 3,
1009                                 text: 'A'
1010                         },
1011                         {
1012                                 data: undefined,
1013                                 text: 'C'
1014                         },
1015                         {
1016                                 data: undefined,
1017                                 text: 'D'
1018                         }
1019                 ], 'Order matches expected order, using the current sortValue in $.data()' );
1021         } );
1023         tableTest( 'bug 8115: sort numbers with commas (ascending)',
1024                 [ 'Numbers' ], numbers, numbersAsc,
1025                 function ( $table ) {
1026                         $table.tablesorter();
1027                         $table.find( '.headerSort:eq(0)' ).click();
1028                 }
1029         );
1031         tableTest( 'bug 8115: sort numbers with commas (descending)',
1032                 [ 'Numbers' ], numbers, reversed( numbersAsc ),
1033                 function ( $table ) {
1034                         $table.tablesorter();
1035                         $table.find( '.headerSort:eq(0)' ).click().click();
1036                 }
1037         );
1038         // TODO add numbers sorting tests for bug 8115 with a different language
1040         QUnit.test( 'bug 32888 - Tables inside a tableheader cell', 2, function ( assert ) {
1041                 var $table;
1042                 $table = $(
1043                         '<table class="sortable" id="mw-bug-32888">' +
1044                                 '<tr><th>header<table id="mw-bug-32888-2">' +
1045                                 '<tr><th>1</th><th>2</th></tr>' +
1046                                 '</table></th></tr>' +
1047                                 '<tr><td>A</td></tr>' +
1048                                 '<tr><td>B</td></tr>' +
1049                                 '</table>'
1050                 );
1051                 $table.tablesorter();
1053                 assert.equal(
1054                         $table.find( '> thead:eq(0) > tr > th.headerSort' ).length,
1055                         1,
1056                         'Child tables inside a headercell should not interfere with sortable headers (bug 32888)'
1057                 );
1058                 assert.equal(
1059                         $( '#mw-bug-32888-2' ).find( 'th.headerSort' ).length,
1060                         0,
1061                         'The headers of child tables inside a headercell should not be sortable themselves (bug 32888)'
1062                 );
1063         } );
1065         tableTest(
1066                 'Correct date sorting I',
1067                 [ 'date' ],
1068                 correctDateSorting1,
1069                 correctDateSortingSorted1,
1070                 function ( $table ) {
1071                         mw.config.set( 'wgDefaultDateFormat', 'mdy' );
1073                         $table.tablesorter();
1074                         $table.find( '.headerSort:eq(0)' ).click();
1075                 }
1076         );
1078         tableTest(
1079                 'Correct date sorting II',
1080                 [ 'date' ],
1081                 correctDateSorting2,
1082                 correctDateSortingSorted2,
1083                 function ( $table ) {
1084                         mw.config.set( 'wgDefaultDateFormat', 'dmy' );
1086                         $table.tablesorter();
1087                         $table.find( '.headerSort:eq(0)' ).click();
1088                 }
1089         );
1091         tableTest(
1092                 'ISO date sorting',
1093                 [ 'isoDate' ],
1094                 isoDateSorting,
1095                 isoDateSortingSorted,
1096                 function ( $table ) {
1097                         mw.config.set( 'wgDefaultDateFormat', 'dmy' );
1099                         $table.tablesorter();
1100                         $table.find( '.headerSort:eq(0)' ).click();
1101                 }
1102         );
1104         QUnit.test( 'Sorting images using alt text', 1, function ( assert ) {
1105                 var $table = $(
1106                         '<table class="sortable">' +
1107                                 '<tr><th>THEAD</th></tr>' +
1108                                 '<tr><td><img alt="2"/></td></tr>' +
1109                                 '<tr><td>1</td></tr>' +
1110                                 '</table>'
1111                 );
1112                 $table.tablesorter().find( '.headerSort:eq(0)' ).click();
1114                 assert.equal(
1115                         $table.find( 'td' ).first().text(),
1116                         '1',
1117                         'Applied correct sorting order'
1118                 );
1119         } );
1121         QUnit.test( 'Sorting images using alt text (complex)', 1, function ( assert ) {
1122                 var $table = $(
1123                         '<table class="sortable">' +
1124                                 '<tr><th>THEAD</th></tr>' +
1125                                 '<tr><td><img alt="D" />A</td></tr>' +
1126                                 '<tr><td>CC</td></tr>' +
1127                                 '<tr><td><a><img alt="A" /></a>F</tr>' +
1128                                 '<tr><td><img alt="A" /><strong>E</strong></tr>' +
1129                                 '<tr><td><strong><img alt="A" />D</strong></tr>' +
1130                                 '<tr><td><img alt="A" />C</tr>' +
1131                                 '</table>'
1132                 );
1133                 $table.tablesorter().find( '.headerSort:eq(0)' ).click();
1135                 assert.equal(
1136                         $table.find( 'td' ).text(),
1137                         'CDEFCCA',
1138                         'Applied correct sorting order'
1139                 );
1140         } );
1142         QUnit.test( 'Sorting images using alt text (with format autodetection)', 1, function ( assert ) {
1143                 var $table = $(
1144                         '<table class="sortable">' +
1145                                 '<tr><th>THEAD</th></tr>' +
1146                                 '<tr><td><img alt="1" />7</td></tr>' +
1147                                 '<tr><td>1<img alt="6" /></td></tr>' +
1148                                 '<tr><td>5</td></tr>' +
1149                                 '<tr><td>4</td></tr>' +
1150                                 '</table>'
1151                 );
1152                 $table.tablesorter().find( '.headerSort:eq(0)' ).click();
1154                 assert.equal(
1155                         $table.find( 'td' ).text(),
1156                         '4517',
1157                         'Applied correct sorting order'
1158                 );
1159         } );
1161         QUnit.test( 'bug 38911 - The row with the largest amount of columns should receive the sort indicators', 3, function ( assert ) {
1162                 var $table = $(
1163                         '<table class="sortable">' +
1164                                 '<thead>' +
1165                                 '<tr><th rowspan="2" id="A1">A1</th><th colspan="2">B2a</th></tr>' +
1166                                 '<tr><th id="B2b">B2b</th><th id="C2b">C2b</th></tr>' +
1167                                 '</thead>' +
1168                                 '<tr><td>A</td><td>Aa</td><td>Ab</td></tr>' +
1169                                 '<tr><td>B</td><td>Ba</td><td>Bb</td></tr>' +
1170                                 '</table>'
1171                 );
1172                 $table.tablesorter();
1174                 assert.equal(
1175                         $table.find( '#A1' ).attr( 'class' ),
1176                         'headerSort',
1177                         'The first column of the first row should be sortable'
1178                 );
1179                 assert.equal(
1180                         $table.find( '#B2b' ).attr( 'class' ),
1181                         'headerSort',
1182                         'The th element of the 2nd row of the 2nd column should be sortable'
1183                 );
1184                 assert.equal(
1185                         $table.find( '#C2b' ).attr( 'class' ),
1186                         'headerSort',
1187                         'The th element of the 2nd row of the 3rd column should be sortable'
1188                 );
1189         } );
1191         QUnit.test( 'rowspans in table headers should prefer the last row when rows are equal in length', 2, function ( assert ) {
1192                 var $table = $(
1193                         '<table class="sortable">' +
1194                                 '<thead>' +
1195                                 '<tr><th rowspan="2" id="A1">A1</th><th>B2a</th></tr>' +
1196                                 '<tr><th id="B2b">B2b</th></tr>' +
1197                                 '</thead>' +
1198                                 '<tr><td>A</td><td>Aa</td></tr>' +
1199                                 '<tr><td>B</td><td>Ba</td></tr>' +
1200                                 '</table>'
1201                 );
1202                 $table.tablesorter();
1204                 assert.equal(
1205                         $table.find( '#A1' ).attr( 'class' ),
1206                         'headerSort',
1207                         'The first column of the first row should be sortable'
1208                 );
1209                 assert.equal(
1210                         $table.find( '#B2b' ).attr( 'class' ),
1211                         'headerSort',
1212                         'The th element of the 2nd row of the 2nd column should be sortable'
1213                 );
1214         } );
1216         QUnit.test( 'holes in the table headers should not throw JS errors', 2, function ( assert ) {
1217                 var $table = $(
1218                         '<table class="sortable">' +
1219                                 '<thead>' +
1220                                 '<tr><th id="A1">A1</th><th>B1</th><th id="C1" rowspan="2">C1</th></tr>' +
1221                                 '<tr><th id="A2">A2</th></tr>' +
1222                                 '</thead>' +
1223                                 '<tr><td>A</td><td>Aa</td><td>Aaa</td></tr>' +
1224                                 '<tr><td>B</td><td>Ba</td><td>Bbb</td></tr>' +
1225                                 '</table>'
1226                 );
1227                 $table.tablesorter();
1228                 assert.equal( $table.find( '#A2' ).data( 'headerIndex' ),
1229                         undefined,
1230                         'A2 should not be a sort header'
1231                 );
1232                 assert.equal( $table.find( '#C1' ).data( 'headerIndex' ),
1233                         2,
1234                         'C1 should be a sort header'
1235                 );
1236         } );
1238         // bug 53527
1239         QUnit.test( 'td cells in thead should not be taken into account for longest row calculation', 2, function ( assert ) {
1240                 var $table = $(
1241                         '<table class="sortable">' +
1242                                 '<thead>' +
1243                                 '<tr><th id="A1">A1</th><th>B1</th><td id="C1">C1</td></tr>' +
1244                                 '<tr><th id="A2">A2</th><th>B2</th><th id="C2">C2</th></tr>' +
1245                                 '</thead>' +
1246                                 '</table>'
1247                 );
1248                 $table.tablesorter();
1249                 assert.equal( $table.find( '#C2' ).data( 'headerIndex' ),
1250                         2,
1251                         'C2 should be a sort header'
1252                 );
1253                 assert.equal( $table.find( '#C1' ).data( 'headerIndex' ),
1254                         undefined,
1255                         'C1 should not be a sort header'
1256                 );
1257         } );
1259         // bug 41889 - exploding rowspans in more complex cases
1260         tableTestHTML(
1261                 'Rowspan exploding with row headers',
1262                 '<table class="sortable">' +
1263                         '<thead><tr><th id="sortme">n</th><th>foo</th><th>bar</th><th>baz</th></tr></thead>' +
1264                         '<tbody>' +
1265                         '<tr><td>1</td><th rowspan="2">foo</th><td rowspan="2">bar</td><td>baz</td></tr>' +
1266                         '<tr><td>2</td><td>baz</td></tr>' +
1267                         '</tbody></table>',
1268                 [
1269                         [ '1', 'foo', 'bar', 'baz' ],
1270                         [ '2', 'foo', 'bar', 'baz' ]
1271                 ]
1272         );
1274         // bug 53211 - exploding rowspans in more complex cases
1275         QUnit.test(
1276                 'Rowspan exploding with row headers and colspans', 1, function ( assert ) {
1277                         var $table = $( '<table class="sortable">' +
1278                                 '<thead><tr><th rowspan="2">n</th><th colspan="2">foo</th><th rowspan="2">baz</th></tr>' +
1279                                 '<tr><th>foo</th><th>bar</th></tr></thead>' +
1280                                 '<tbody>' +
1281                                 '<tr><td>1</td><td>foo</td><td>bar</td><td>baz</td></tr>' +
1282                                 '<tr><td>2</td><td>foo</td><td>bar</td><td>baz</td></tr>' +
1283                                 '</tbody></table>' );
1285                         $table.tablesorter();
1286                         assert.equal( $table.find( 'tr:eq(1) th:eq(1)' ).data( 'headerIndex' ),
1287                                 2,
1288                                 'Incorrect index of sort header'
1289                         );
1290                 }
1291         );
1293         tableTestHTML(
1294                 'Rowspan exploding with colspanned cells',
1295                 '<table class="sortable">' +
1296                         '<thead><tr><th id="sortme">n</th><th>foo</th><th>bar</th><th>baz</th></tr></thead>' +
1297                         '<tbody>' +
1298                         '<tr><td>1</td><td>foo</td><td>bar</td><td rowspan="2">baz</td></tr>' +
1299                         '<tr><td>2</td><td colspan="2">foobar</td></tr>' +
1300                         '</tbody></table>',
1301                 [
1302                         [ '1', 'foo', 'bar', 'baz' ],
1303                         [ '2', 'foobar', 'baz' ]
1304                 ]
1305         );
1307         tableTestHTML(
1308                 'Rowspan exploding with colspanned cells (2)',
1309                 '<table class="sortable">' +
1310                         '<thead><tr><th>n</th><th>foo</th><th>bar</th><th>baz</th><th id="sortme">n2</th></tr></thead>' +
1311                         '<tbody>' +
1312                         '<tr><td>1</td><td>foo</td><td>bar</td><td rowspan="2">baz</td><td>2</td></tr>' +
1313                         '<tr><td>2</td><td colspan="2">foobar</td><td>1</td></tr>' +
1314                         '</tbody></table>',
1315                 [
1316                         [ '2', 'foobar', 'baz', '1' ],
1317                         [ '1', 'foo', 'bar', 'baz', '2' ]
1318                 ]
1319         );
1321         tableTestHTML(
1322                 'Rowspan exploding with rightmost rows spanning most',
1323                 '<table class="sortable">' +
1324                         '<thead><tr><th id="sortme">n</th><th>foo</th><th>bar</th></tr></thead>' +
1325                         '<tbody>' +
1326                         '<tr><td>1</td><td rowspan="2">foo</td><td rowspan="4">bar</td></tr>' +
1327                         '<tr><td>2</td></tr>' +
1328                         '<tr><td>3</td><td rowspan="2">foo</td></tr>' +
1329                         '<tr><td>4</td></tr>' +
1330                         '</tbody></table>',
1331                 [
1332                         [ '1', 'foo', 'bar' ],
1333                         [ '2', 'foo', 'bar' ],
1334                         [ '3', 'foo', 'bar' ],
1335                         [ '4', 'foo', 'bar' ]
1336                 ]
1337         );
1339         tableTestHTML(
1340                 'Rowspan exploding with rightmost rows spanning most (2)',
1341                 '<table class="sortable">' +
1342                         '<thead><tr><th id="sortme">n</th><th>foo</th><th>bar</th><th>baz</th></tr></thead>' +
1343                         '<tbody>' +
1344                         '<tr><td>1</td><td rowspan="2">foo</td><td rowspan="4">bar</td><td>baz</td></tr>' +
1345                         '<tr><td>2</td><td>baz</td></tr>' +
1346                         '<tr><td>3</td><td rowspan="2">foo</td><td>baz</td></tr>' +
1347                         '<tr><td>4</td><td>baz</td></tr>' +
1348                         '</tbody></table>',
1349                 [
1350                         [ '1', 'foo', 'bar', 'baz' ],
1351                         [ '2', 'foo', 'bar', 'baz' ],
1352                         [ '3', 'foo', 'bar', 'baz' ],
1353                         [ '4', 'foo', 'bar', 'baz' ]
1354                 ]
1355         );
1357         tableTestHTML(
1358                 'Rowspan exploding with row-and-colspanned cells',
1359                 '<table class="sortable">' +
1360                         '<thead><tr><th id="sortme">n</th><th>foo1</th><th>foo2</th><th>bar</th><th>baz</th></tr></thead>' +
1361                         '<tbody>' +
1362                         '<tr><td>1</td><td rowspan="2">foo1</td><td rowspan="2">foo2</td><td rowspan="4">bar</td><td>baz</td></tr>' +
1363                         '<tr><td>2</td><td>baz</td></tr>' +
1364                         '<tr><td>3</td><td colspan="2" rowspan="2">foo</td><td>baz</td></tr>' +
1365                         '<tr><td>4</td><td>baz</td></tr>' +
1366                         '</tbody></table>',
1367                 [
1368                         [ '1', 'foo1', 'foo2', 'bar', 'baz' ],
1369                         [ '2', 'foo1', 'foo2', 'bar', 'baz' ],
1370                         [ '3', 'foo', 'bar', 'baz' ],
1371                         [ '4', 'foo', 'bar', 'baz' ]
1372                 ]
1373         );
1375         tableTestHTML(
1376                 'Rowspan exploding with uneven rowspan layout',
1377                 '<table class="sortable">' +
1378                         '<thead><tr><th id="sortme">n</th><th>foo1</th><th>foo2</th><th>foo3</th><th>bar</th><th>baz</th></tr></thead>' +
1379                         '<tbody>' +
1380                         '<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>' +
1381                         '<tr><td>2</td><td rowspan="3">bar</td><td>baz</td></tr>' +
1382                         '<tr><td>3</td><td rowspan="2">foo1</td><td rowspan="2">foo2</td><td rowspan="2">foo3</td><td>baz</td></tr>' +
1383                         '<tr><td>4</td><td>baz</td></tr>' +
1384                         '</tbody></table>',
1385                 [
1386                         [ '1', 'foo1', 'foo2', 'foo3', 'bar', 'baz' ],
1387                         [ '2', 'foo1', 'foo2', 'foo3', 'bar', 'baz' ],
1388                         [ '3', 'foo1', 'foo2', 'foo3', 'bar', 'baz' ],
1389                         [ '4', 'foo1', 'foo2', 'foo3', 'bar', 'baz' ]
1390                 ]
1391         );
1393         QUnit.test( 'bug 105731 - incomplete rows in table body', 3, function ( assert ) {
1394                 var $table, parsers;
1395                 $table = $(
1396                         '<table class="sortable">' +
1397                                 '<tr><th>A</th><th>B</th></tr>' +
1398                                 '<tr><td>3</td></tr>' +
1399                                 '<tr><td>1</td><td>2</td></tr>' +
1400                                 '</table>'
1401                 );
1402                 $table.tablesorter();
1403                 $table.find( '.headerSort:eq(0)' ).click();
1404                 // now the first row have 2 columns
1405                 $table.find( '.headerSort:eq(1)' ).click();
1407                 parsers = $table.data( 'tablesorter' ).config.parsers;
1409                 assert.equal(
1410                         parsers.length,
1411                         2,
1412                         'detectParserForColumn() detect 2 parsers'
1413                 );
1415                 assert.equal(
1416                         parsers[ 1 ].id,
1417                         'number',
1418                         'detectParserForColumn() detect parser.id "number" for second column'
1419                 );
1421                 assert.equal(
1422                         parsers[ 1 ].format( $table.find( 'tbody > tr > td:eq(1)' ).text() ),
1423                         0,
1424                         'empty cell is sorted as number 0'
1425                 );
1426         } );
1428         QUnit.test( 'bug T114721 - use of expand-child class', 2, function ( assert ) {
1429                 var $table, parsers;
1430                 $table = $(
1431                         '<table class="sortable">' +
1432                                 '<tr><th>A</th><th>B</th></tr>' +
1433                                 '<tr><td>b</td><td>4</td></tr>' +
1434                                 '<tr class="expand-child"><td colspan="2">some text follow b</td></tr>' +
1435                                 '<tr><td>a</td><td>2</td></tr>' +
1436                                 '<tr class="expand-child"><td colspan="2">some text follow a</td></tr>' +
1437                                 '<tr class="expand-child"><td colspan="2">more text</td></tr>' +
1438                                 '</table>'
1439                 );
1440                 $table.tablesorter();
1441                 $table.find( '.headerSort:eq(0)' ).click();
1443                 assert.deepEqual(
1444                         tableExtract( $table ),
1445                         [
1446                                 [ 'a', '2' ],
1447                                 [ 'some text follow a' ],
1448                                 [ 'more text' ],
1449                                 [ 'b', '4' ],
1450                                 [ 'some text follow b' ]
1451                         ],
1452                         'row with expand-child class follow above row'
1453                 );
1455                 parsers = $table.data( 'tablesorter' ).config.parsers;
1456                 assert.equal(
1457                         parsers[ 1 ].id,
1458                         'number',
1459                         'detectParserForColumn() detect parser.id "number" for second column'
1460                 );
1461         } );
1463 }( jQuery, mediaWiki ) );