--- /dev/null
+/*
+ *
+ * TableSorter for MediaWiki
+ *
+ * Written 2011 Leo Koppelkamm
+ * Based on tablesorter.com plugin, written (c) 2007 Christian Bach.
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ */
+/**
+ *
+ * @description Create a sortable table with multi-column sorting capabilitys
+ *
+ * @example $( 'table' ).tablesorter();
+ * @desc Create a simple tablesorter interface.
+ *
+ * @option String cssHeader ( optional ) A string of the class name to be appended
+ * to sortable tr elements in the thead of the table. Default value:
+ * "header"
+ *
+ * @option String cssAsc ( optional ) A string of the class name to be appended to
+ * sortable tr elements in the thead on a ascending sort. Default value:
+ * "headerSortUp"
+ *
+ * @option String cssDesc ( optional ) A string of the class name to be appended
+ * to sortable tr elements in the thead on a descending sort. Default
+ * value: "headerSortDown"
+ *
+ * @option String sortInitialOrder ( optional ) A string of the inital sorting
+ * order can be asc or desc. Default value: "asc"
+ *
+ * @option String sortMultisortKey ( optional ) A string of the multi-column sort
+ * key. Default value: "shiftKey"
+ *
+ * @option Boolean sortLocaleCompare ( optional ) Boolean flag indicating whatever
+ * to use String.localeCampare method or not. Set to false.
+ *
+ * @option Boolean cancelSelection ( optional ) Boolean flag indicating if
+ * tablesorter should cancel selection of the table headers text.
+ * Default value: true
+ *
+ * @option Boolean debug ( optional ) Boolean flag indicating if tablesorter
+ * should display debuging information usefull for development.
+ *
+ * @type jQuery
+ *
+ * @name tablesorter
+ *
+ * @cat Plugins/Tablesorter
+ *
+ * @author Christian Bach/christian.bach@polyester.se
+ */
+
+( function ($) {
+ $.extend( {
+ tablesorter: new
+
+ function () {
+
+ var parsers = [];
+
+ this.defaults = {
+ cssHeader: "headerSort",
+ cssAsc: "headerSortUp",
+ cssDesc: "headerSortDown",
+ cssChildRow: "expand-child",
+ sortInitialOrder: "asc",
+ sortMultiSortKey: "shiftKey",
+ sortLocaleCompare: false,
+ parsers: {},
+ widgets: [],
+ headers: {},
+ cancelSelection: true,
+ sortList: [],
+ headerList: [],
+ selectorHeaders: 'thead tr:eq(0) th',
+ debug: false
+ };
+
+ /* debuging utils */
+ //
+ // function benchmark( s, d ) {
+ // alert( s + "," + ( new Date().getTime() - d.getTime() ) + "ms" );
+ // }
+ //
+ // this.benchmark = benchmark;
+ //
+ //
+ /* parsers utils */
+
+ function buildParserCache( table, $headers ) {
+ var rows = table.tBodies[0].rows;
+
+ if ( rows[0] ) {
+
+ var list = [],
+ cells = rows[0].cells,
+ l = cells.length;
+
+ for ( var i = 0; i < l; i++ ) {
+
+ if ( $headers.eq(i).is( '[class*="sort-"]' ) ) {
+ p = getParserById($headers.eq(i).attr('class').replace(/.*?sort-(.*?) .*/, '$1'));
+ } else {
+ p = detectParserForColumn( table, rows, -1, i );
+ }
+ // if ( table.config.debug ) {
+ // console.log( "column:" + i + " parser:" + p.id + "\n" );
+ // }
+ list.push(p);
+ }
+ }
+ return list;
+ }
+
+ function detectParserForColumn( table, rows, rowIndex, cellIndex ) {
+ var l = parsers.length,
+ node = false,
+ nodeValue = false,
+ keepLooking = true;
+ while ( nodeValue == '' && keepLooking ) {
+ rowIndex++;
+ if ( rows[rowIndex] ) {
+ node = getNodeFromRowAndCellIndex( rows, rowIndex, cellIndex );
+ nodeValue = trimAndGetNodeText( table.config, node );
+ // if ( table.config.debug ) {
+ // console.log( 'Checking if value was empty on row:' + rowIndex );
+ // }
+ } else {
+ keepLooking = false;
+ }
+ }
+ for ( var i = 1; i < l; i++ ) {
+ if ( parsers[i].is( nodeValue, table, node ) ) {
+ return parsers[i];
+ }
+ }
+ // 0 is always the generic parser ( text )
+ return parsers[0];
+ }
+
+ function getNodeFromRowAndCellIndex( rows, rowIndex, cellIndex ) {
+ return rows[rowIndex].cells[cellIndex];
+ }
+
+ function trimAndGetNodeText( config, node ) {
+ return $.trim( getElementText( config, node ) );
+ }
+
+ function getParserById( name ) {
+ var l = parsers.length;
+ for ( var i = 0; i < l; i++ ) {
+ if ( parsers[i].id.toLowerCase() == name.toLowerCase() ) {
+ return parsers[i];
+ }
+ }
+ return false;
+ }
+
+ /* utils */
+
+ function buildCache( table ) {
+
+ // if ( table.config.debug ) {
+ // var cacheTime = new Date();
+ // }
+ var totalRows = ( table.tBodies[0] && table.tBodies[0].rows.length ) || 0,
+ totalCells = ( table.tBodies[0].rows[0] && table.tBodies[0].rows[0].cells.length ) || 0,
+ parsers = table.config.parsers,
+ cache = {
+ row: [],
+ normalized: []
+ };
+
+ for ( var i = 0; i < totalRows; ++i ) {
+
+ // Add the table data to main data array
+ var c = $( table.tBodies[0].rows[i] ),
+ cols = [];
+
+ // if this is a child row, add it to the last row's children and
+ // continue to the next row
+ if ( c.hasClass( table.config.cssChildRow ) ) {
+ cache.row[cache.row.length - 1] = cache.row[cache.row.length - 1].add(c);
+ // go to the next for loop
+ continue;
+ }
+
+ cache.row.push(c);
+
+ for ( var j = 0; j < totalCells; ++j ) {
+ cols.push( parsers[j].format( getElementText( table.config, c[0].cells[j] ), table, c[0].cells[j] ) );
+ }
+
+ cols.push( cache.normalized.length ); // add position for rowCache
+ cache.normalized.push( cols );
+ cols = null;
+ }
+
+ // if ( table.config.debug ) {
+ // benchmark( "Building cache for " + totalRows + " rows:", cacheTime );
+ // }
+ return cache;
+ }
+
+ function getElementText( config, node ) {
+ return $( node ).text();
+ }
+
+ function appendToTable( table, cache ) {
+
+ // if ( table.config.debug ) {
+ // var appendTime = new Date()
+ // }
+ var c = cache,
+ r = c.row,
+ n = c.normalized,
+ totalRows = n.length,
+ checkCell = (n[0].length - 1),
+ tableBody = $( table.tBodies[0] ),
+ fragment = document.createDocumentFragment();
+
+ for ( var i = 0; i < totalRows; i++ ) {
+ var pos = n[i][checkCell];
+
+ var l = r[pos].length;
+
+ for ( var j = 0; j < l; j++ ) {
+ fragment.appendChild( r[pos][j] );
+ }
+
+ }
+ tableBody[0].appendChild( fragment );
+ // if ( table.config.debug ) {
+ // benchmark( "Rebuilt table:", appendTime );
+ // }
+ }
+
+ function buildHeaders( table ) {
+
+ // if ( table.config.debug ) {
+ // var time = new Date();
+ // }
+ //var header_index = computeTableHeaderCellIndexes( table );
+ var realCellIndex = 0;
+
+ $tableHeaders = $( table.config.selectorHeaders, table ).each( function ( index ) {
+ //var normalIndex = allCells.index( this );
+ //var realCellIndex = 0;
+ this.column = realCellIndex;
+
+ var colspan = this.colspan;
+ colspan = colspan ? parseInt( colspan ) : 1;
+ realCellIndex += colspan;
+
+ //this.column = header_index[this.parentNode.rowIndex + "-" + this.cellIndex];
+ this.order = 0;
+ this.count = 0;
+
+ if ( $( this ).is( '.unsortable' ) ) this.sortDisabled = true;
+
+ if ( !this.sortDisabled ) {
+ var $th = $( this ).addClass( table.config.cssHeader );
+ //if ( table.config.onRenderHeader ) table.config.onRenderHeader.apply($th);
+ }
+
+ // add cell to headerList
+ table.config.headerList[index] = this;
+ } );
+
+ // if ( table.config.debug ) {
+ // benchmark( "Built headers:", time );
+ // console.log( $tableHeaders );
+ // }
+ //
+ return $tableHeaders;
+
+ }
+
+ // // from:
+ // // http://www.javascripttoolbox.com/lib/table/examples.php
+ // // http://www.javascripttoolbox.com/temp/table_cellindex.html
+ //
+ // function computeTableHeaderCellIndexes(t) {
+ // var matrix = [];
+ // var lookup = {};
+ // var thead = t.getElementsByTagName( 'THEAD' )[0];
+ // var trs = thead.getElementsByTagName( 'TR' );
+ //
+ // for ( var i = 0; i < trs.length; i++ ) {
+ // var cells = trs[i].cells;
+ // for ( var j = 0; j < cells.length; j++ ) {
+ // var c = cells[j];
+ //
+ // var rowIndex = c.parentNode.rowIndex;
+ // var cellId = rowIndex + "-" + c.cellIndex;
+ // var rowSpan = c.rowSpan || 1;
+ // var colSpan = c.colSpan || 1;
+ // var firstAvailCol;
+ // if ( typeof( matrix[rowIndex] ) == "undefined" ) {
+ // matrix[rowIndex] = [];
+ // }
+ // // Find first available column in the first row
+ // for ( var k = 0; k < matrix[rowIndex].length + 1; k++ ) {
+ // if ( typeof( matrix[rowIndex][k] ) == "undefined" ) {
+ // firstAvailCol = k;
+ // break;
+ // }
+ // }
+ // lookup[cellId] = firstAvailCol;
+ // for ( var k = rowIndex; k < rowIndex + rowSpan; k++ ) {
+ // if ( typeof( matrix[k] ) == "undefined" ) {
+ // matrix[k] = [];
+ // }
+ // var matrixrow = matrix[k];
+ // for ( var l = firstAvailCol; l < firstAvailCol + colSpan; l++ ) {
+ // matrixrow[l] = "x";
+ // }
+ // }
+ // }
+ // }
+ // return lookup;
+ // }
+ // function checkCellColSpan( table, rows, row ) {
+ // var arr = [],
+ // r = table.tHead.rows,
+ // c = r[row].cells;
+ //
+ // for ( var i = 0; i < c.length; i++ ) {
+ // var cell = c[i];
+ //
+ // if ( cell.colSpan > 1 ) {
+ // arr = arr.concat( checkCellColSpan( table, headerArr, row++ ) );
+ // } else {
+ // if ( table.tHead.length == 1 || ( cell.rowSpan > 1 || !r[row + 1] ) ) {
+ // arr.push( cell );
+ // }
+ // // headerArr[row] = ( i+row );
+ // }
+ // }
+ // return arr;
+ // }
+ //
+ // function checkHeaderOptions( table, i ) {
+ // if ( ( table.config.headers[i] ) && ( table.config.headers[i].sorter === false ) ) {
+ // return true;
+ // }
+ // return false;
+ // }
+ // function formatSortingOrder(v) {
+ // if ( typeof(v) != "Number" ) {
+ // return ( v.toLowerCase() == "desc" ) ? 1 : 0;
+ // } else {
+ // return ( v == 1 ) ? 1 : 0;
+ // }
+ // }
+
+ function isValueInArray( v, a ) {
+ var l = a.length;
+ for ( var i = 0; i < l; i++ ) {
+ if ( a[i][0] == v ) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ function setHeadersCss( table, $headers, list, css ) {
+ // remove all header information
+ $headers.removeClass( css[0] ).removeClass( css[1] );
+
+ var h = [];
+ $headers.each( function ( offset ) {
+ if ( !this.sortDisabled ) {
+ h[this.column] = $( this );
+ }
+ } );
+
+ var l = list.length;
+ for ( var i = 0; i < l; i++ ) {
+ h[list[i][0]].addClass( css[list[i][1]] );
+ }
+ }
+
+ // function updateHeaderSortCount( table, sortList ) {
+ // var c = table.config,
+ // l = sortList.length;
+ // for ( var i = 0; i < l; i++ ) {
+ // var s = sortList[i],
+ // o = c.headerList[s[0]];
+ // o.count = s[1];
+ // o.count++;
+ // }
+ // }
+ /* sorting methods */
+
+ function multisort( table, sortList, cache ) {
+ // if ( table.config.debug ) {
+ // var sortTime = new Date();
+ // }
+ var dynamicExp = "var sortWrapper = function(a,b) {",
+ l = sortList.length;
+
+ // TODO: inline functions.
+ for ( var i = 0; i < l; i++ ) {
+
+ var c = sortList[i][0];
+ var order = sortList[i][1];
+ var s = "";
+ if ( table.config.parsers[c].type == "text" ) {
+ if ( order == 0 ) {
+ s = makeSortFunction( "text", "asc", c );
+ } else {
+ s = makeSortFunction( "text", "desc", c );
+ }
+ } else {
+ if ( order == 0 ) {
+ s = makeSortFunction( "numeric", "asc", c );
+ } else {
+ s = makeSortFunction( "numeric", "desc", c );
+ }
+ }
+ var e = "e" + i;
+
+ dynamicExp += "var " + e + " = " + s; // + "(a[" + c + "],b[" + c + "]); ";
+ dynamicExp += "if(" + e + ") { return " + e + "; } ";
+ dynamicExp += "else { ";
+ }
+
+ // if value is the same keep original order
+ var orgOrderCol = cache.normalized[0].length - 1;
+ dynamicExp += "return a[" + orgOrderCol + "]-b[" + orgOrderCol + "];";
+
+ for ( var i = 0; i < l; i++ ) {
+ dynamicExp += "}; ";
+ }
+
+ dynamicExp += "return 0; ";
+ dynamicExp += "}; ";
+
+ // if ( table.config.debug ) {
+ // benchmark( "Evaling expression:" + dynamicExp, new Date() );
+ // }
+ eval( dynamicExp );
+ cache.normalized.sort( sortWrapper );
+
+ // if ( table.config.debug ) {
+ // benchmark( "Sorting on " + sortList.toString() + " and dir " + order + " time:", sortTime );
+ // }
+ return cache;
+ }
+
+ function makeSortFunction( type, direction, index ) {
+ var a = "a[" + index + "]",
+ b = "b[" + index + "]";
+ if (type == 'text' && direction == 'asc') {
+ return "(" + a + " == " + b + " ? 0 : (" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : (" + a + " < " + b + ") ? -1 : 1 )));";
+ } else if (type == 'text' && direction == 'desc') {
+ return "(" + a + " == " + b + " ? 0 : (" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : (" + b + " < " + a + ") ? -1 : 1 )));";
+ } else if (type == 'numeric' && direction == 'asc') {
+ return "(" + a + " === null && " + b + " === null) ? 0 :(" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : " + a + " - " + b + "));";
+ } else if (type == 'numeric' && direction == 'desc') {
+ return "(" + a + " === null && " + b + " === null) ? 0 :(" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : " + b + " - " + a + "));";
+ }
+ }
+
+ function makeSortText(i) {
+ return "((a[" + i + "] < b[" + i + "]) ? -1 : ((a[" + i + "] > b[" + i + "]) ? 1 : 0));";
+ }
+
+ function makeSortTextDesc(i) {
+ return "((b[" + i + "] < a[" + i + "]) ? -1 : ((b[" + i + "] > a[" + i + "]) ? 1 : 0));";
+ }
+
+ function makeSortNumeric(i) {
+ return "a[" + i + "]-b[" + i + "];";
+ }
+
+ function makeSortNumericDesc(i) {
+ return "b[" + i + "]-a[" + i + "];";
+ }
+
+ function sortText( a, b ) {
+ if ( table.config.sortLocaleCompare ) return a.localeCompare(b);
+ return ((a < b) ? -1 : ((a > b) ? 1 : 0));
+ }
+
+ function sortTextDesc( a, b ) {
+ if ( table.config.sortLocaleCompare ) return b.localeCompare(a);
+ return ((b < a) ? -1 : ((b > a) ? 1 : 0));
+ }
+
+ function sortNumeric( a, b ) {
+ return a - b;
+ }
+
+ function sortNumericDesc( a, b ) {
+ return b - a;
+ }
+
+ function buildTransformTable() {
+ var digits = '0123456789,.'.split('');
+
+ if ( typeof wgSeparatorTransformTable == 'undefined' || ( wgSeparatorTransformTable[0] == '' && wgDigitTransformTable[2] == '' ) ) {
+ ts.transformTable = false;
+ } else {
+ ts.transformTable = {};
+
+ // Unpack the transform table
+ var ascii = wgSeparatorTransformTable[0].split( "\t" ).concat( wgDigitTransformTable[0].split( "\t" ) );
+ var localised = wgSeparatorTransformTable[1].split( "\t" ).concat( wgDigitTransformTable[1].split( "\t" ) );
+
+ // Construct regex for number identification
+ for ( var i = 0; i < ascii.length; i++ ) {
+ ts.transformTable[localised[i]] = ascii[i];
+ digits.push( $.escapeRE( localised[i] ) );
+ }
+ }
+ var digitClass = '[' + digits.join( '', digits ) + ']';
+
+ // We allow a trailing percent sign, which we just strip. This works fine
+ // if percents and regular numbers aren't being mixed.
+ ts.numberRegex = new RegExp("^(" + "[-+\u2212]?[0-9][0-9,]*(\\.[0-9,]*)?(E[-+\u2212]?[0-9][0-9,]*)?" + // Fortran-style scientific
+ "|" + "[-+\u2212]?" + digitClass + "+%?" + // Generic localised
+ ")$", "i");
+ }
+
+ function buildDateTable() {
+ var r = '';
+ ts.monthNames = [
+ [],
+ []
+ ];
+ ts.dateRegex = [];
+
+ for ( i = 1; i < 13; i++ ) {
+ ts.monthNames[0][i] = wgMonthNames[i].toLowerCase();
+ ts.monthNames[1][i] = wgMonthNamesShort[i].toLowerCase().replace( '.', '' );
+ r += $.escapeRE( ts.monthNames[0][i] ) + '|';
+ r += $.escapeRE( ts.monthNames[1][i] ) + '|';
+ }
+
+ //Remove trailing pipe
+ r = r.slice( 0, -1 );
+
+ //Build RegEx
+ //Any date formated with . , ' - or /
+ ts.dateRegex[0] = new RegExp(/^\s*\d{1,2}[\,\.\-\/'\s]*\d{1,2}[\,\.\-\/'\s]*\d{2,4}\s*?/i);
+
+ //Written Month name, dmy
+ ts.dateRegex[1] = new RegExp('^\\s*\\d{1,2}[\\,\\.\\-\\/\'\\s]*(' + r + ')' + '[\\,\\.\\-\\/\'\\s]*\\d{2,4}\\s*$', 'i');
+
+ //Written Month name, mdy
+ ts.dateRegex[2] = new RegExp('^\\s*(' + r + ')' + '[\\,\\.\\-\\/\'\\s]*\\d{1,2}[\\,\\.\\-\\/\'\\s]*\\d{2,4}\\s*$', 'i');
+
+ }
+
+ function buildCollationTable() {
+ if ( typeof tableSorterCollation == "object" ) {
+ ts.collationRegex = [];
+
+ //Build array of key names
+ for ( var key in tableSorterCollation ) {
+ if ( tableSorterCollation.hasOwnProperty(key) ) { //to be safe
+ ts.collationRegex.push(key);
+ }
+ }
+ ts.collationRegex = new RegExp( '[' + ts.collationRegex.join('') + ']', 'ig' );
+ }
+ }
+
+ function cacheRegexs() {
+ ts.rgx = {
+ IPAddress: [new RegExp(/^\d{1,3}[\.]\d{1,3}[\.]\d{1,3}[\.]\d{1,3}$/)],
+ currency: [new RegExp(/^[£$€?.]/), new RegExp(/[£$€]/g)],
+ url: [new RegExp(/^(https?|ftp|file):\/\/$/), new RegExp(/(https?|ftp|file):\/\//)],
+ isoDate: [new RegExp(/^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/)],
+ usLongDate: [new RegExp(/^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2}) (([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/)],
+ time: [new RegExp(/^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/)]
+ };
+ } /* public methods */
+ this.construct = function ( settings ) {
+ return this.each( function () {
+ // if no thead or tbody quit.
+ if ( !this.tHead || !this.tBodies ) return;
+ // declare
+ var $this, $document, $headers, cache, config, shiftDown = 0,
+ sortOrder;
+
+ // new blank config object
+ this.config = {};
+ // merge and extend.
+ config = $.extend( this.config, $.tablesorter.defaults, settings );
+
+ // store common expression for speed
+ $this = $( this );
+ // save the settings where they read
+ $.data( this, "tablesorter", config );
+ // build headers
+ $headers = buildHeaders( this );
+ // Grab and process locale settings
+ buildTransformTable();
+ buildDateTable();
+ buildCollationTable();
+
+ //Precaching regexps can bring 10 fold
+ //performance improvements in some browsers
+ cacheRegexs();
+
+ // try to auto detect column type, and store in tables config
+ this.config.parsers = buildParserCache( this, $headers );
+ // build the cache for the tbody cells
+ cache = buildCache( this );
+ // get the css class names, could be done else where.
+ var sortCSS = [config.cssDesc, config.cssAsc];
+ // apply event handling to headers
+ // this is to big, perhaps break it out?
+ $headers.click(
+
+ function (e) {
+ //var clickTime= new Date();
+ var totalRows = ( $this[0].tBodies[0] && $this[0].tBodies[0].rows.length ) || 0;
+ if ( !this.sortDisabled && totalRows > 0 ) {
+ // Only call sortStart if sorting is
+ // enabled.
+ //$this.trigger( "sortStart" );
+ // store exp, for speed
+ var $cell = $( this );
+ // get current column index
+ var i = this.column;
+ // get current column sort order
+ this.order = this.count % 2;
+ this.count++;
+ // user only whants to sort on one
+ // column
+ if ( !e[config.sortMultiSortKey] ) {
+ // flush the sort list
+ config.sortList = [];
+ // add column to sort list
+ config.sortList.push( [i, this.order] );
+ // multi column sorting
+ } else {
+ // the user has clicked on an all
+ // ready sortet column.
+ if ( isValueInArray( i, config.sortList ) ) {
+ // revers the sorting direction
+ // for all tables.
+ for ( var j = 0; j < config.sortList.length; j++ ) {
+ var s = config.sortList[j],
+ o = config.headerList[s[0]];
+ if ( s[0] == i ) {
+ o.count = s[1];
+ o.count++;
+ s[1] = o.count % 2;
+ }
+ }
+ } else {
+ // add column to sort list array
+ config.sortList.push( [i, this.order] );
+ }
+ }
+ setTimeout( function () {
+ // set css for headers
+ setHeadersCss( $this[0], $headers, config.sortList, sortCSS );
+ appendToTable(
+ $this[0], multisort(
+ $this[0], config.sortList, cache ) );
+ //benchmark( "Sorting " + totalRows + " rows:", clickTime );
+ }, 1 );
+ // stop normal event by returning false
+ return false;
+ }
+ // cancel selection
+ } ).mousedown( function () {
+ if ( config.cancelSelection ) {
+ this.onselectstart = function () {
+ return false;
+ };
+ return false;
+ }
+ } );
+ // apply easy methods that trigger binded events
+ //Can't think of any use for these in a mw context
+ // $this.bind( "update", function () {
+ // var me = this;
+ // setTimeout( function () {
+ // // rebuild parsers.
+ // me.config.parsers = buildParserCache(
+ // me, $headers );
+ // // rebuild the cache map
+ // cache = buildCache(me);
+ // }, 1 );
+ // } ).bind( "updateCell", function ( e, cell ) {
+ // var config = this.config;
+ // // get position from the dom.
+ // var pos = [( cell.parentNode.rowIndex - 1 ), cell.cellIndex];
+ // // update cache
+ // cache.normalized[pos[0]][pos[1]] = config.parsers[pos[1]].format(
+ // getElementText( config, cell ), cell );
+ // } ).bind( "sorton", function ( e, list ) {
+ // $( this ).trigger( "sortStart" );
+ // config.sortList = list;
+ // // update and store the sortlist
+ // var sortList = config.sortList;
+ // // update header count index
+ // updateHeaderSortCount( this, sortList );
+ // // set css for headers
+ // setHeadersCss( this, $headers, sortList, sortCSS );
+ // // sort the table and append it to the dom
+ // appendToTable( this, multisort( this, sortList, cache ) );
+ // } ).bind( "appendCache", function () {
+ // appendToTable( this, cache );
+ // } );
+ } );
+ };
+ this.addParser = function ( parser ) {
+ var l = parsers.length,
+ a = true;
+ for ( var i = 0; i < l; i++ ) {
+ if ( parsers[i].id.toLowerCase() == parser.id.toLowerCase() ) {
+ a = false;
+ }
+ }
+ if (a) {
+ parsers.push( parser );
+ }
+ };
+ this.formatDigit = function (s) {
+ if ( ts.transformTable != false ) {
+ var out = '',
+ c;
+ for ( var p = 0; p < s.length; p++ ) {
+ c = s.charAt(p);
+ if ( c in ts.transformTable ) {
+ out += ts.transformTable[c];
+ } else {
+ out += c;
+ }
+ }
+ s = out;
+ }
+ var i = parseFloat( s.replace(/[, ]/g, '').replace( "\u2212", '-' ) );
+ return ( isNaN(i)) ? 0 : i;
+ };
+ this.formatFloat = function (s) {
+ var i = parseFloat(s);
+ return ( isNaN(i)) ? 0 : i;
+ };
+ this.formatInt = function (s) {
+ var i = parseInt(s);
+ return ( isNaN(i)) ? 0 : i;
+ };
+ this.clearTableBody = function ( table ) {
+ if ( $.browser.msie ) {
+ function empty() {
+ while ( this.firstChild )
+ this.removeChild( this.firstChild );
+ }
+ empty.apply( table.tBodies[0] );
+ } else {
+ table.tBodies[0].innerHTML = "";
+ }
+ };
+ }
+ } );
+
+ // extend plugin scope
+ $.fn.extend( {
+ tablesorter: $.tablesorter.construct
+ } );
+
+ // make shortcut
+ var ts = $.tablesorter;
+
+ // add default parsers
+ ts.addParser( {
+ id: "text",
+ is: function (s) {
+ return true;
+ },
+ format: function (s) {
+ s = $.trim( s.toLowerCase() );
+ if ( ts.collationRegex ) {
+ var tsc = tableSorterCollation;
+ s = s.replace( ts.collationRegex, function ( match ) {
+ var r = tsc[match] ? tsc[match] : tsc[match.toUpperCase()];
+ return r.toLowerCase();
+ } );
+ }
+ return s;
+ },
+ type: "text"
+ } );
+
+ ts.addParser( {
+ id: "IPAddress",
+ is: function (s) {
+ return ts.rgx.IPAddress[0].test(s);
+ },
+ format: function (s) {
+ var a = s.split("."),
+ r = "",
+ l = a.length;
+ for ( var i = 0; i < l; i++ ) {
+ var item = a[i];
+ if ( item.length == 2 ) {
+ r += "0" + item;
+ } else {
+ r += item;
+ }
+ }
+ return $.tablesorter.formatFloat(r);
+ },
+ type: "numeric"
+ } );
+
+ ts.addParser( {
+ id: "number",
+ is: function ( s, table ) {
+ return $.tablesorter.numberRegex.test( $.trim(s ));
+ },
+ format: function (s) {
+ return $.tablesorter.formatDigit(s);
+ },
+ type: "numeric"
+ } );
+
+ ts.addParser( {
+ id: "currency",
+ is: function (s) {
+ return ts.rgx.currency[0].test(s);
+ },
+ format: function (s) {
+ return $.tablesorter.formatDigit( s.replace( ts.rgx.currency[1], "" ) );
+ },
+ type: "numeric"
+ } );
+
+ ts.addParser( {
+ id: "url",
+ is: function (s) {
+ return ts.rgx.url[0].test(s);
+ },
+ format: function (s) {
+ return $.trim( s.replace( ts.rgx.url[1], '' ) );
+ },
+ type: "text"
+ } );
+
+ ts.addParser( {
+ id: "isoDate",
+ is: function (s) {
+ return ts.rgx.isoDate[0].test(s);
+ },
+ format: function (s) {
+ return $.tablesorter.formatFloat((s != "") ? new Date(s.replace(
+ new RegExp(/-/g), "/")).getTime() : "0");
+ },
+ type: "numeric"
+ } );
+
+ ts.addParser( {
+ id: "usLongDate",
+ is: function (s) {
+ return ts.rgx.usLongDate[0].test(s);
+ },
+ format: function (s) {
+ return $.tablesorter.formatFloat( new Date(s).getTime() );
+ },
+ type: "numeric"
+ } );
+
+ ts.addParser( {
+ id: "date",
+ is: function (s) {
+ return ( ts.dateRegex[0].test(s) || ts.dateRegex[1].test(s) || ts.dateRegex[2].test(s ));
+ },
+ format: function ( s, table ) {
+ s = s.toLowerCase();
+
+ for ( i = 1, j = 0; i < 13 && j < 2; i++ ) {
+ s = s.replace( ts.monthNames[j][i], i );
+ if ( i == 12 ) {
+ j++;
+ i = 0;
+ }
+ }
+
+ 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].length == 1 ) s[0] = "0" + s[0];
+ if ( s[1].length == 1 ) s[1] = "0" + s[1];
+
+ if ( !s[2] ) {
+ //Fix yearless dates
+ s[2] = 2000;
+ } else if ( ( y = parseInt( s[2] ) ) < 100 ) {
+ //Guestimate years without centuries
+ if ( y < 30 ) {
+ s[2] = 2000 + y;
+ } else {
+ s[2] = 1900 + y;
+ }
+ }
+ //Resort array depending on preferences
+ if ( wgDefaultDateFormat == "mdy" ) {
+ s.push( s.shift() );
+ s.push( s.shift() );
+ } else if ( wgDefaultDateFormat == "dmy" ) {
+ var d = s.shift();
+ s.push( s.shift() );
+ s.push(d);
+ }
+ return parseInt( s.join('') );
+ },
+ type: "numeric"
+ } );
+ ts.addParser( {
+ id: "time",
+ is: function (s) {
+ return ts.rgx.time[0].test(s);
+ },
+ format: function (s) {
+ return $.tablesorter.formatFloat( new Date( "2000/01/01 " + s ).getTime() );
+ },
+ type: "numeric"
+ } );
+} )( jQuery );
\ No newline at end of file