(bug 36991) Fix jquery.tablesorter date sorting
authorBrad Jorsch <anomie.wikipedia@gmail.com>
Sun, 20 May 2012 18:10:09 +0000 (14:10 -0400)
committerTimo Tijhof <ttijhof@wikimedia.org>
Tue, 3 Jul 2012 17:05:01 +0000 (19:05 +0200)
jquery.tablesorter should extract date sort format from date string
instead of global config. Dates like "April 1 2012" and "1 April 2012" now sort correctly regardless of the content language's
DefaultDateFormat setting (exposed as wgDefaultDateFormat in
mw.config).

Previously jquery.tablesorter sorted dates like "1 Apr 2012" (DMY) or
"Apr 1 2012" (MDY) incorrectly. It just converted it to "1 4 2012"
and "4 1 2012", respectively, and then assumes MDY or DMY order based
on the global wiki configuration.

This patch fixes that.

Change-Id: I8061b1a7892633e34be4d4a0273a4dd5045fd2ee

RELEASE-NOTES-1.20
resources/jquery/jquery.tablesorter.js
tests/qunit/suites/resources/jquery/jquery.tablesorter.test.js

index 03728e4..755d703 100644 (file)
@@ -141,6 +141,9 @@ upgrade PHP if you have not done so prior to upgrading MediaWiki.
 * (bug 35082) mw.util.addPortletLink incorrectly adds link to mutiple <ul> tags.
 * (bug 36495) Sanitizer::fixDeprecatedAttributes should convert "align"
   attribute to margin or float instead of text-align (for non-table-cells).
+* (bug 36991) jquery.tablesorter should extract date sort format from date
+  string instead of global config. Dates like "April 1 2012" and "1 April 2012"
+  now sort correctly regardless of the content language's DefaultDateFormat.
 
 === API changes in 1.20 ===
 * (bug 34316) Add ability to retrieve maximum upload size from MediaWiki API.
index ea86b64..21e1f96 100644 (file)
 
        function buildDateTable() {
                var regex = [];
-               ts.monthNames = [
-                       [],
-                       []
-               ];
+               ts.monthNames = {};
 
                for ( var i = 1; i < 13; i++ ) {
-                       ts.monthNames[0][i] = mw.config.get( 'wgMonthNames' )[i].toLowerCase();
-                       ts.monthNames[1][i] = mw.config.get( 'wgMonthNamesShort' )[i].toLowerCase().replace( '.', '' );
-                       regex.push( $.escapeRE( ts.monthNames[0][i] ) );
-                       regex.push( $.escapeRE( ts.monthNames[1][i] ) );
+                       var name = mw.config.get( 'wgMonthNames' )[i].toLowerCase();
+                       ts.monthNames[name] = i;
+                       regex.push( $.escapeRE( name ) );
+                       name = mw.config.get( 'wgMonthNamesShort' )[i].toLowerCase().replace( '.', '' );
+                       ts.monthNames[name] = i;
+                       regex.push( $.escapeRE( name ) );
                }
 
                // Build piped string
 
                // Build RegEx
                // Any date formated with . , ' - or /
-               ts.dateRegex[0] = new RegExp( /^\s*\d{1,2}[\,\.\-\/'\s]{1,2}\d{1,2}[\,\.\-\/'\s]{1,2}\d{2,4}\s*?/i);
+               ts.dateRegex[0] = new RegExp( /^\s*(\d{1,2})[\,\.\-\/'\s]{1,2}(\d{1,2})[\,\.\-\/'\s]{1,2}(\d{2,4})\s*?/i);
 
                // Written Month name, dmy
-               ts.dateRegex[1] = new RegExp( '^\\s*\\d{1,2}[\\,\\.\\-\\/\'\\s]*(' + regex + ')' + '[\\,\\.\\-\\/\'\\s]*\\d{2,4}\\s*$', 'i' );
+               ts.dateRegex[1] = new RegExp( '^\\s*(\\d{1,2})[\\,\\.\\-\\/\'\\s]*(' + regex + ')' + '[\\,\\.\\-\\/\'\\s]*(\\d{2,4})\\s*$', 'i' );
 
                // Written Month name, mdy
-               ts.dateRegex[2] = new RegExp( '^\\s*(' + regex + ')' + '[\\,\\.\\-\\/\'\\s]*\\d{1,2}[\\,\\.\\-\\/\'\\s]*\\d{2,4}\\s*$', 'i' );
+               ts.dateRegex[2] = new RegExp( '^\\s*(' + regex + ')' + '[\\,\\.\\-\\/\'\\s]*(\\d{1,2})[\\,\\.\\-\\/\'\\s]*(\\d{2,4})\\s*$', 'i' );
 
        }
 
                        },
 
                        dateRegex: [],
-                       monthNames: [],
+                       monthNames: {},
 
                        /**
                         * @param $tables {jQuery}
                format: function( s, table ) {
                        s = $.trim( s.toLowerCase() );
 
-                       for ( var i = 1, j = 0; i < 13 && j < 2; i++ ) {
-                               s = s.replace( ts.monthNames[j][i], i );
-                               if ( i == 12 ) {
-                                       j++;
-                                       i = 0;
+                       var match;
+                       if ( ( match = s.match( ts.dateRegex[0] ) ) !== null ) {
+                               if ( mw.config.get( 'wgDefaultDateFormat' ) == 'mdy' || mw.config.get( 'wgContentLanguage' ) == 'en' ) {
+                                       s = [ match[3], match[1], match[2] ];
+                               } else if ( mw.config.get( 'wgDefaultDateFormat' ) == 'dmy' ) {
+                                       s = [ match[3], match[2], match[1] ];
                                }
+                       } else if ( ( match = s.match( ts.dateRegex[1] ) ) !== null ) {
+                               s = [ match[3], '' + ts.monthNames[match[2]], match[1] ];
+                       } else if ( ( match = s.match( ts.dateRegex[2] ) ) !== null ) {
+                               s = [ match[3], '' + ts.monthNames[match[1]], match[2] ];
+                       } else {
+                               // Should never get here
+                               return '99999999';
                        }
 
-                       s = s.replace( /[\-\.\,' ]/g, '/' );
-
-                       // Replace double slashes
-                       s = s.replace( /\/\//g, '/' );
-                       s = s.replace( /\/\//g, '/' );
-                       s = s.split( '/' );
-
                        // Pad Month and Day
-                       if ( s[0] && s[0].length == 1 ) {
-                               s[0] = '0' + s[0];
-                       }
-                       if ( s[1] && s[1].length == 1 ) {
+                       if ( s[1].length == 1 ) {
                                s[1] = '0' + s[1];
                        }
-                       var y;
+                       if ( s[2].length == 1 ) {
+                               s[2] = '0' + s[2];
+                       }
 
-                       if ( !s[2] ) {
-                               // Fix yearless dates
-                               s[2] = 2000;
-                       } else if ( ( y = parseInt( s[2], 10) ) < 100 ) {
+                       var y;
+                       if ( ( y = parseInt( s[0], 10) ) < 100 ) {
                                // Guestimate years without centuries
                                if ( y < 30 ) {
-                                       s[2] = 2000 + y;
+                                       s[0] = 2000 + y;
                                } else {
-                                       s[2] = 1900 + y;
+                                       s[0] = 1900 + y;
                                }
                        }
-                       // Resort array depending on preferences
-                       if ( mw.config.get( 'wgDefaultDateFormat' ) == 'mdy' || mw.config.get( 'wgContentLanguage' ) == 'en' ) {
-                               s.push( s.shift() );
-                               s.push( s.shift() );
-                       } else if ( mw.config.get( 'wgDefaultDateFormat' ) == 'dmy' ) {
-                               var d = s.shift();
-                               s.push( s.shift() );
-                               s.push(d);
+                       while ( s[0].length < 4 ) {
+                               s[0] = '0' + s[0];
                        }
                        return parseInt( s.join( '' ), 10 );
                },
index f028dbc..3a02695 100644 (file)
@@ -549,4 +549,54 @@ test( 'bug 32888 - Tables inside a tableheader cell', function() {
        );
 });
 
+var correctDateSorting1 = [
+       ['01 January 2010'],
+       ['05 February 2010'],
+       ['16 January 2010'],
+];
+
+var correctDateSortingSorted1 = [
+       ['01 January 2010'],
+       ['16 January 2010'],
+       ['05 February 2010'],
+];
+
+tableTest(
+       'Correct date sorting I',
+       ['date'],
+       correctDateSorting1,
+       correctDateSortingSorted1,
+       function ( $table ) {
+               mw.config.set( 'wgDefaultDateFormat', 'mdy' );
+
+               $table.tablesorter();
+               $table.find( '.headerSort:eq(0)' ).click();
+       }
+);
+
+var correctDateSorting2 = [
+       ['January 01 2010'],
+       ['February 05 2010'],
+       ['January 16 2010'],
+];
+
+var correctDateSortingSorted2 = [
+       ['January 01 2010'],
+       ['January 16 2010'],
+       ['February 05 2010'],
+];
+
+tableTest(
+       'Correct date sorting II',
+       ['date'],
+       correctDateSorting2,
+       correctDateSortingSorted2,
+       function ( $table ) {
+               mw.config.set( 'wgDefaultDateFormat', 'dmy' );
+
+               $table.tablesorter();
+               $table.find( '.headerSort:eq(0)' ).click();
+       }
+);
+
 })( jQuery );