Index: trunk/phase3/skins/common/wikibits.js |
— | — | @@ -503,6 +503,8 @@ |
504 | 504 | var ts_image_none = "sort_none.gif"; |
505 | 505 | var ts_europeandate = wgContentLanguage != "en"; // The non-American-inclined can change to "true" |
506 | 506 | var ts_alternate_row_colors = false; |
| 507 | +var ts_number_transform_table = null; |
| 508 | +var ts_number_regex = null; |
507 | 509 | |
508 | 510 | function sortables_init() { |
509 | 511 | var idnum = 0; |
— | — | @@ -575,9 +577,14 @@ |
576 | 578 | table = table.parentNode; |
577 | 579 | if (!table) return; |
578 | 580 | |
579 | | - // Work out a type for the column |
580 | 581 | if (table.rows.length <= 1) return; |
581 | 582 | |
| 583 | + // Generate the number transform table if it's not done already |
| 584 | + if (ts_number_transform_table == null) { |
| 585 | + ts_initTransformTable(); |
| 586 | + } |
| 587 | + |
| 588 | + // Work out a type for the column |
582 | 589 | // Skip the first row if that's where the headings are |
583 | 590 | var rowStart = (table.tHead && table.tHead.rows.length > 0 ? 0 : 1); |
584 | 591 | |
— | — | @@ -590,22 +597,21 @@ |
591 | 598 | } |
592 | 599 | } |
593 | 600 | |
594 | | - var sortfn = ts_sort_caseinsensitive; |
595 | | - if (itm.match(/^\d\d[\/. -][a-zA-Z]{3}[\/. -]\d\d\d\d$/)) |
596 | | - sortfn = ts_sort_date; |
597 | | - else if (itm.match(/^\d\d[\/.-]\d\d[\/.-]\d\d\d\d$/)) |
598 | | - sortfn = ts_sort_date; |
599 | | - else if (itm.match(/^\d\d[\/.-]\d\d[\/.-]\d\d$/)) |
600 | | - sortfn = ts_sort_date; |
| 601 | + // TODO: bug 8226, localised date formats |
| 602 | + var sortfn = ts_sort_generic; |
| 603 | + var preprocessor = ts_toLowerCase; |
| 604 | + if (/^\d\d[\/. -][a-zA-Z]{3}[\/. -]\d\d\d\d$/.test(itm)) { |
| 605 | + preprocessor = ts_dateToSortKey; |
| 606 | + } else if (/^\d\d[\/.-]\d\d[\/.-]\d\d\d\d$/.test(itm)) { |
| 607 | + preprocessor = ts_dateToSortKey; |
| 608 | + } else if (/^\d\d[\/.-]\d\d[\/.-]\d\d$/.test(itm)) { |
| 609 | + preprocessor = ts_dateToSortKey; |
601 | 610 | // pound dollar euro yen currency cents |
602 | | - else if (itm.match(/(^[\u00a3$\u20ac\u00a4\u00a5]|\u00a2$)/)) |
603 | | - sortfn = ts_sort_currency; |
604 | | - // We allow a trailing percent sign, which we just strip. This works fine |
605 | | - // if percents and regular numbers aren't being mixed. |
606 | | - else if (itm.match(/^[+-]?\d[\d,]*(\.[\d,]*)?([eE][+-]?\d[\d,]*)?\%?$/) || |
607 | | - itm.match(/^[+-]?\.\d[\d,]*([eE][+-]?\d[\d,]*)?\%?$/) || |
608 | | - itm.match(/^0x[\da-f]+$/i)) |
609 | | - sortfn = ts_sort_numeric; |
| 611 | + } else if (/(^[\u00a3$\u20ac\u00a4\u00a5]|\u00a2$)/.test(itm)) { |
| 612 | + preprocessor = ts_currencyToSortKey; |
| 613 | + } else if (ts_number_regex.test(itm)) { |
| 614 | + preprocessor = ts_parseFloat; |
| 615 | + } |
610 | 616 | |
611 | 617 | var reverse = (span.getAttribute("sortdir") == 'down'); |
612 | 618 | |
— | — | @@ -614,8 +620,9 @@ |
615 | 621 | var row = table.rows[j]; |
616 | 622 | var keyText = ts_getInnerText(row.cells[column]); |
617 | 623 | var oldIndex = (reverse ? -j : j); |
| 624 | + var preprocessed = preprocessor( keyText ); |
618 | 625 | |
619 | | - newRows[newRows.length] = new Array(row, keyText, oldIndex); |
| 626 | + newRows[newRows.length] = new Array(row, preprocessed, oldIndex); |
620 | 627 | } |
621 | 628 | |
622 | 629 | newRows.sort(sortfn); |
— | — | @@ -654,6 +661,63 @@ |
655 | 662 | } |
656 | 663 | } |
657 | 664 | |
| 665 | +function ts_initTransformTable() { |
| 666 | + if ( typeof wgSeparatorTransformTable == "undefined" |
| 667 | + || ( wgSeparatorTransformTable[0] == '' && wgDigitTransformTable[2] == '' ) ) |
| 668 | + { |
| 669 | + digitClass = "[0-9,.]"; |
| 670 | + ts_number_transform_table = false; |
| 671 | + } else { |
| 672 | + ts_number_transform_table = {}; |
| 673 | + // Unpack the transform table |
| 674 | + // Separators |
| 675 | + ascii = wgSeparatorTransformTable[0].split("\t"); |
| 676 | + localised = wgSeparatorTransformTable[1].split("\t"); |
| 677 | + for ( var i = 0; i < ascii.length; i++ ) { |
| 678 | + ts_number_transform_table[localised[i]] = ascii[i]; |
| 679 | + } |
| 680 | + // Digits |
| 681 | + ascii = wgDigitTransformTable[0].split("\t"); |
| 682 | + localised = wgDigitTransformTable[1].split("\t"); |
| 683 | + for ( var i = 0; i < ascii.length; i++ ) { |
| 684 | + ts_number_transform_table[localised[i]] = ascii[i]; |
| 685 | + } |
| 686 | + |
| 687 | + // Construct regex for number identification |
| 688 | + digits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ',', '\\.']; |
| 689 | + maxDigitLength = 1; |
| 690 | + for ( var digit in ts_number_transform_table ) { |
| 691 | + // Escape regex metacharacters |
| 692 | + digits.push( |
| 693 | + digit.replace( /[\\\\$\*\+\?\.\(\)\|\{\}\[\]\-]/, |
| 694 | + function( s ) { return '\\' + s; } ) |
| 695 | + ); |
| 696 | + if (digit.length > maxDigitLength) { |
| 697 | + maxDigitLength = digit.length; |
| 698 | + } |
| 699 | + } |
| 700 | + if ( maxDigitLength > 1 ) { |
| 701 | + digitClass = '[' + digits.join( '', digits ) + ']'; |
| 702 | + } else { |
| 703 | + digitClass = '(' + digits.join( '|', digits ) + ')'; |
| 704 | + } |
| 705 | + } |
| 706 | + |
| 707 | + // We allow a trailing percent sign, which we just strip. This works fine |
| 708 | + // if percents and regular numbers aren't being mixed. |
| 709 | + ts_number_regex = new RegExp( |
| 710 | + "^(" + |
| 711 | + "[+-]?[0-9][0-9,]*(\\.[0-9,]*)?(E[+-]?[0-9][0-9,]*)?" + // Fortran-style scientific |
| 712 | + "|" + |
| 713 | + "[+-]?" + digitClass + "+%?" + // Generic localised |
| 714 | + ")$", "i" |
| 715 | + ); |
| 716 | +} |
| 717 | + |
| 718 | +function ts_toLowerCase( s ) { |
| 719 | + return s.toLowerCase(); |
| 720 | +} |
| 721 | + |
658 | 722 | function ts_dateToSortKey(date) { |
659 | 723 | // y2k notes: two digit years less than 50 are treated as 20XX, greater than 50 are treated as 19XX |
660 | 724 | if (date.length == 11) { |
— | — | @@ -695,40 +759,36 @@ |
696 | 760 | return "00000000"; |
697 | 761 | } |
698 | 762 | |
699 | | -function ts_parseFloat(num) { |
700 | | - if (!num) return 0; |
701 | | - num = parseFloat(num.replace(/,/g, "")); |
702 | | - return (isNaN(num) ? 0 : num); |
703 | | -} |
| 763 | +function ts_parseFloat( s ) { |
| 764 | + if ( !s ) { |
| 765 | + return 0; |
| 766 | + } |
| 767 | + if (ts_number_transform_table != false) { |
| 768 | + var newNum = '', c; |
| 769 | + |
| 770 | + for ( var p = 0; p < s.length; p++ ) { |
| 771 | + c = s.charAt( p ); |
| 772 | + if (c in ts_number_transform_table) { |
| 773 | + newNum += ts_number_transform_table[c]; |
| 774 | + } else { |
| 775 | + newNum += c; |
| 776 | + } |
| 777 | + } |
| 778 | + s = newNum; |
| 779 | + } |
704 | 780 | |
705 | | -function ts_sort_date(a,b) { |
706 | | - var aa = ts_dateToSortKey(a[1]); |
707 | | - var bb = ts_dateToSortKey(b[1]); |
708 | | - return (aa < bb ? -1 : aa > bb ? 1 : a[2] - b[2]); |
| 781 | + num = parseFloat(s.replace(/,/g, "")); |
| 782 | + return (isNaN(num) ? s : num); |
709 | 783 | } |
710 | 784 | |
711 | | -function ts_sort_currency(a,b) { |
712 | | - var aa = ts_parseFloat(a[1].replace(/[^0-9.,]/g,'')); |
713 | | - var bb = ts_parseFloat(b[1].replace(/[^0-9.,]/g,'')); |
714 | | - return (aa != bb ? aa - bb : a[2] - b[2]); |
| 785 | +function ts_currencyToSortKey( s ) { |
| 786 | + return ts_parseFloat(s.replace(/[^0-9.,]/g,'')); |
715 | 787 | } |
716 | 788 | |
717 | | -function ts_sort_numeric(a,b) { |
718 | | - var aa = ts_parseFloat(a[1]); |
719 | | - var bb = ts_parseFloat(b[1]); |
720 | | - return (aa != bb ? aa - bb : a[2] - b[2]); |
| 789 | +function ts_sort_generic(a, b) { |
| 790 | + return a[1] < b[1] ? -1 : a[1] > b[1] ? 1 : a[2] - b[2]; |
721 | 791 | } |
722 | 792 | |
723 | | -function ts_sort_caseinsensitive(a,b) { |
724 | | - var aa = a[1].toLowerCase(); |
725 | | - var bb = b[1].toLowerCase(); |
726 | | - return (aa < bb ? -1 : aa > bb ? 1 : a[2] - b[2]); |
727 | | -} |
728 | | - |
729 | | -function ts_sort_default(a,b) { |
730 | | - return (a[1] < b[1] ? -1 : a[1] > b[1] ? 1 : a[2] - b[2]); |
731 | | -} |
732 | | - |
733 | 793 | function ts_alternate(table) { |
734 | 794 | // Take object table and get all it's tbodies. |
735 | 795 | var tableBodies = table.getElementsByTagName("tbody"); |
Index: trunk/phase3/includes/DefaultSettings.php |
— | — | @@ -1399,7 +1399,7 @@ |
1400 | 1400 | * to ensure that client-side caches don't keep obsolete copies of global |
1401 | 1401 | * styles. |
1402 | 1402 | */ |
1403 | | -$wgStyleVersion = '182'; |
| 1403 | +$wgStyleVersion = '183'; |
1404 | 1404 | |
1405 | 1405 | |
1406 | 1406 | # Server-side caching: |
Index: trunk/phase3/includes/Skin.php |
— | — | @@ -341,6 +341,18 @@ |
342 | 342 | |
343 | 343 | $ns = $wgTitle->getNamespace(); |
344 | 344 | $nsname = isset( $wgCanonicalNamespaceNames[ $ns ] ) ? $wgCanonicalNamespaceNames[ $ns ] : $wgTitle->getNsText(); |
| 345 | + $separatorTransTable = $wgContLang->separatorTransformTable(); |
| 346 | + $separatorTransTable = $separatorTransTable ? $separatorTransTable : array(); |
| 347 | + $compactSeparatorTransTable = array( |
| 348 | + implode( "\t", array_keys( $separatorTransTable ) ), |
| 349 | + implode( "\t", $separatorTransTable ), |
| 350 | + ); |
| 351 | + $digitTransTable = $wgContLang->digitTransformTable(); |
| 352 | + $digitTransTable = $digitTransTable ? $digitTransTable : array(); |
| 353 | + $compactDigitTransTable = array( |
| 354 | + implode( "\t", array_keys( $digitTransTable ) ), |
| 355 | + implode( "\t", $digitTransTable ), |
| 356 | + ); |
345 | 357 | |
346 | 358 | $vars = array( |
347 | 359 | 'skin' => $data['skinname'], |
— | — | @@ -368,6 +380,8 @@ |
369 | 381 | 'wgVersion' => $wgVersion, |
370 | 382 | 'wgEnableAPI' => $wgEnableAPI, |
371 | 383 | 'wgEnableWriteAPI' => $wgEnableWriteAPI, |
| 384 | + 'wgSeparatorTransformTable' => $compactSeparatorTransTable, |
| 385 | + 'wgDigitTransformTable' => $compactDigitTransTable, |
372 | 386 | ); |
373 | 387 | |
374 | 388 | if( $wgUseAjax && $wgEnableMWSuggest && !$wgUser->getOption( 'disablesuggest', false )){ |
Index: trunk/phase3/RELEASE-NOTES |
— | — | @@ -289,6 +289,7 @@ |
290 | 290 | JavaScript is disabled. |
291 | 291 | * (bug 4253) Recentchanges IRC messages no longer include title in diff URLs |
292 | 292 | * Allow '0' to be an accesskey. |
| 293 | +* (bug 8063) Use language-dependent sorting in client-side sortable tables |
293 | 294 | |
294 | 295 | === API changes in 1.14 === |
295 | 296 | |