r90818 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r90817‎ | r90818 | r90819 >
Date:04:36, 26 June 2011
Author:krinkle
Status:ok (Comments)
Tags:
Comment:
Review and clean up of jquery.tablesorter.js + applying code conventions

* Dropping redundant "new function(){}" construction, instead using the closure we already have for the local scope.
* Adding more function documentation
* Whitespace contentions
* Passing jQuery object to the $.tablesorter.construct and creating jQuery plugin function in $.fn.tablesorter (per jQuery convention, this allows $.tablesorter.construct to be used directly without having to use .apply() to get the this-context right).
* Making use of the arguments that jQuery.fn.each passes by default in $.tablesorter.construct (this/that => table)
* Renaming a few single-letter variables to something more descriptive (c => $row, r => regex etc.)
* Changed order of local functions in order of calling and dependancy (fixed JSHint potential implied globals). Also makes reading/understanding them easier.
* Removed commented out code
* Added more line breaks to separate blocks
* Merge var-statements together
* Declare 'ts' shortcut on top of the local scope, define 'ts' shortcut directly after definition of $.tablesorter
* Adding public member placeholders, populated by private functions, to the initial object instead of inside the functions. This way the members can be seen centrally (dateRegex, monthNames)


* Syntax/JSHint fixes (Passes 100% now; Globals: mw, jQuery)
- 'list' used out of scope. In function buildParserCache: "var list" was defined under an if-condition, but returned outside of it, this fails in the 'else' case. Moved var list outside the if-condition
- Strict === comparison to 0, null, undefined, false, true, '' etc.
- Require curly braces around all blocks


* Performance improvements (see also http://www.mediawiki.org/wiki/JSPERF)
- Using dot notation (obj.member = {}), instead of $.extend(obj, { member: .. }) for single additions. No need for $.extend
- Object literal {foo}, instead of new function(){ this.foo }
- Strict/fast comparison to undefined, without typeof and/or string evaluation
- cacheRegexs() is uselses if if re-creates the cache every time. Using static cache instead (which was likely the intention)
Modified paths:
  • /trunk/phase3/resources/jquery/jquery.tablesorter.js (modified) (history)

Diff [purge]

Index: trunk/phase3/resources/jquery/jquery.tablesorter.js
@@ -1,37 +1,38 @@
2 -/*
3 - *
 2+/**
43 * TableSorter for MediaWiki
5 - *
 4+ *
65 * Written 2011 Leo Koppelkamm
76 * Based on tablesorter.com plugin, written (c) 2007 Christian Bach.
87 *
98 * Dual licensed under the MIT and GPL licenses:
109 * http://www.opensource.org/licenses/mit-license.php
1110 * http://www.gnu.org/licenses/gpl.html
12 - *
 11+ *
 12+ * @depends on mw.config (wgDigitTransformTable, wgMonthNames, wgMonthNamesShort,
 13+ * wgDefaultDateFormat, wgContentLanguage)
1314 */
1415 /**
15 - *
 16+ *
1617 * @description Create a sortable table with multi-column sorting capabilitys
17 - *
 18+ *
1819 * @example $( 'table' ).tablesorter();
1920 * @desc Create a simple tablesorter interface.
2021 *
2122 * @option String cssHeader ( optional ) A string of the class name to be appended
2223 * to sortable tr elements in the thead of the table. Default value:
2324 * "header"
24 - *
 25+ *
2526 * @option String cssAsc ( optional ) A string of the class name to be appended to
2627 * sortable tr elements in the thead on a ascending sort. Default value:
2728 * "headerSortUp"
28 - *
 29+ *
2930 * @option String cssDesc ( optional ) A string of the class name to be appended
3031 * to sortable tr elements in the thead on a descending sort. Default
3132 * value: "headerSortDown"
32 - *
 33+ *
3334 * @option String sortInitialOrder ( optional ) A string of the inital sorting
3435 * order can be asc or desc. Default value: "asc"
35 - *
 36+ *
3637 * @option String sortMultisortKey ( optional ) A string of the multi-column sort
3738 * key. Default value: "shiftKey"
3839 *
@@ -41,525 +42,534 @@
4243 * @option Boolean cancelSelection ( optional ) Boolean flag indicating if
4344 * tablesorter should cancel selection of the table headers text.
4445 * Default value: true
45 - *
 46+ *
4647 * @option Boolean debug ( optional ) Boolean flag indicating if tablesorter
4748 * should display debuging information usefull for development.
48 - *
 49+ *
4950 * @type jQuery
50 - *
 51+ *
5152 * @name tablesorter
52 - *
 53+ *
5354 * @cat Plugins/Tablesorter
54 - *
 55+ *
5556 * @author Christian Bach/christian.bach@polyester.se
5657 */
5758
58 -( function ($) {
59 - $.extend( {
60 - tablesorter: new
 59+( function( $ ) {
6160
62 - function () {
 61+ /* Local scope */
6362
64 - var parsers = [];
 63+ var ts,
 64+ parsers = [];
6565
66 - this.defaults = {
67 - cssHeader: "headerSort",
68 - cssAsc: "headerSortUp",
69 - cssDesc: "headerSortDown",
70 - cssChildRow: "expand-child",
71 - sortInitialOrder: "asc",
72 - sortMultiSortKey: "shiftKey",
73 - sortLocaleCompare: false,
74 - parsers: {},
75 - widgets: [],
76 - headers: {},
77 - cancelSelection: true,
78 - sortList: [],
79 - headerList: [],
80 - selectorHeaders: 'thead tr:eq(0) th',
81 - debug: false
82 - };
 66+ /* Parser utility functions */
8367
84 - /* parsers utils */
 68+ function getParserById( name ) {
 69+ var len = parsers.length;
 70+ for ( var i = 0; i < len; i++ ) {
 71+ if ( parsers[i].id.toLowerCase() === name.toLowerCase() ) {
 72+ return parsers[i];
 73+ }
 74+ }
 75+ return false;
 76+ }
8577
86 - function buildParserCache( table, $headers ) {
87 - var rows = table.tBodies[0].rows,
88 - sortType;
 78+ function getElementText( node ) {
 79+ if ( node.hasAttribute && node.hasAttribute( 'data-sort-value' ) ) {
 80+ return node.getAttribute( 'data-sort-value' );
 81+ } else {
 82+ return $( node ).text();
 83+ }
 84+ }
8985
90 - if ( rows[0] ) {
 86+ function getTextFromRowAndCellIndex( rows, rowIndex, cellIndex ) {
 87+ if ( rows[rowIndex] && rows[rowIndex].cells[cellIndex] ) {
 88+ return $.trim( getElementText( rows[rowIndex].cells[cellIndex] ) );
 89+ } else {
 90+ return '';
 91+ }
 92+ }
9193
92 - var list = [],
93 - cells = rows[0].cells,
94 - l = cells.length;
 94+ function detectParserForColumn( table, rows, cellIndex ) {
 95+ var l = parsers.length,
 96+ nodeValue,
 97+ // Start with 1 because 0 is the fallback parser
 98+ i = 1,
 99+ rowIndex = 0,
 100+ concurrent = 0,
 101+ needed = ( rows.length > 4 ) ? 5 : rows.length;
95102
96 - for ( var i = 0; i < l; i++ ) {
97 - var p = false;
98 - sortType = $headers.eq(i).data('sort-type');
99 - if ( typeof sortType != 'undefined' ) {
100 - p = getParserById( sortType );
101 - }
102 -
103 - if (p === false) {
104 - p = detectParserForColumn( table, rows, i );
105 - }
106 -
107 - list.push(p);
 103+ while( i < l ) {
 104+ nodeValue = getTextFromRowAndCellIndex( rows, rowIndex, cellIndex );
 105+ if ( nodeValue !== '') {
 106+ if ( parsers[i].is( nodeValue, table ) ) {
 107+ concurrent++;
 108+ rowIndex++;
 109+ if ( concurrent >= needed ) {
 110+ // Confirmed the parser for multiple cells, let's return it
 111+ return parsers[i];
108112 }
109 - }
110 - return list;
111 - }
112 -
113 - function detectParserForColumn( table, rows, cellIndex ) {
114 - var l = parsers.length,
115 - nodeValue,
116 - // Start with 1 because 0 is the fallback parser
117 - i = 1,
118 - rowIndex = 0,
119 - concurrent = 0,
120 - needed = (rows.length > 4 ) ? 5 : rows.length;
121 - while( i<l ) {
122 - nodeValue = getTextFromRowAndCellIndex( rows, rowIndex, cellIndex );
123 - if ( nodeValue != '') {
124 - if ( parsers[i].is( nodeValue, table ) ) {
125 - concurrent++;
126 - rowIndex++;
127 - if (concurrent >= needed ) {
128 - // Confirmed the parser for multiple cells, let's return it
129 - return parsers[i];
130 - }
131 - } else {
132 - // Check next parser, reset rows
133 - i++;
134 - rowIndex = 0;
135 - concurrent = 0;
136 - }
137 - } else {
138 - // Empty cell
139 - rowIndex++;
140 - if ( rowIndex > rows.length ) {
141 - rowIndex = 0;
142 - i++;
143 - }
144 - }
145 - }
146 -
147 - // 0 is always the generic parser ( text )
148 - return parsers[0];
149 - }
150 -
151 - function getTextFromRowAndCellIndex( rows, rowIndex, cellIndex ) {
152 - if ( rows[rowIndex] && rows[rowIndex].cells[cellIndex] ) {
153 - return $.trim( getElementText( rows[rowIndex].cells[cellIndex] ) );
154113 } else {
155 - return '';
 114+ // Check next parser, reset rows
 115+ i++;
 116+ rowIndex = 0;
 117+ concurrent = 0;
156118 }
157 - }
158 -
159 - function getParserById( name ) {
160 - var l = parsers.length;
161 - for ( var i = 0; i < l; i++ ) {
162 - if ( parsers[i].id.toLowerCase() == name.toLowerCase() ) {
163 - return parsers[i];
164 - }
 119+ } else {
 120+ // Empty cell
 121+ rowIndex++;
 122+ if ( rowIndex > rows.length ) {
 123+ rowIndex = 0;
 124+ i++;
165125 }
166 - return false;
167126 }
 127+ }
168128
169 - /* utils */
 129+ // 0 is always the generic parser (text)
 130+ return parsers[0];
 131+ }
170132
171 - function buildCache( table ) {
172 - // if ( table.config.debug ) {
173 - // var cacheTime = new Date();
174 - // }
175 - var totalRows = ( table.tBodies[0] && table.tBodies[0].rows.length ) || 0,
176 - totalCells = ( table.tBodies[0].rows[0] && table.tBodies[0].rows[0].cells.length ) || 0,
177 - parsers = table.config.parsers,
178 - cache = {
179 - row: [],
180 - normalized: []
181 - };
 133+ function buildParserCache( table, $headers ) {
 134+ var rows = table.tBodies[0].rows,
 135+ sortType,
 136+ parsers = [];
182137
183 - for ( var i = 0; i < totalRows; ++i ) {
 138+ if ( rows[0] ) {
184139
185 - // Add the table data to main data array
186 - var c = $( table.tBodies[0].rows[i] ),
187 - cols = [];
 140+ var cells = rows[0].cells,
 141+ len = cells.length,
 142+ i, parser;
188143
189 - // if this is a child row, add it to the last row's children and
190 - // continue to the next row
191 - if ( c.hasClass( table.config.cssChildRow ) ) {
192 - cache.row[cache.row.length - 1] = cache.row[cache.row.length - 1].add(c);
193 - // go to the next for loop
194 - continue;
195 - }
 144+ for ( i = 0; i < len; i++ ) {
 145+ parser = false;
 146+ sortType = $headers.eq( i ).data( 'sort-type' );
 147+ if ( sortType !== undefined ) {
 148+ parser = getParserById( sortType );
 149+ }
196150
197 - cache.row.push(c);
 151+ if ( parser === false ) {
 152+ parser = detectParserForColumn( table, rows, i );
 153+ }
198154
199 - for ( var j = 0; j < totalCells; ++j ) {
200 - cols.push( parsers[j].format( getElementText( c[0].cells[j] ), table, c[0].cells[j] ) );
201 - }
 155+ parsers.push( parser );
 156+ }
 157+ }
 158+ return parsers;
 159+ }
202160
203 - cols.push( cache.normalized.length ); // add position for rowCache
204 - cache.normalized.push( cols );
205 - cols = null;
206 - }
 161+ /* Other utility functions */
207162
208 - // if ( table.config.debug ) {
209 - // benchmark( "Building cache for " + totalRows + " rows:", cacheTime );
210 - // }
211 - return cache;
 163+ function buildCache( table ) {
 164+ var totalRows = ( table.tBodies[0] && table.tBodies[0].rows.length ) || 0,
 165+ totalCells = ( table.tBodies[0].rows[0] && table.tBodies[0].rows[0].cells.length ) || 0,
 166+ parsers = table.config.parsers,
 167+ cache = {
 168+ row: [],
 169+ normalized: []
 170+ };
 171+
 172+ for ( var i = 0; i < totalRows; ++i ) {
 173+
 174+ // Add the table data to main data array
 175+ var $row = $( table.tBodies[0].rows[i] ),
 176+ cols = [];
 177+
 178+ // if this is a child row, add it to the last row's children and
 179+ // continue to the next row
 180+ if ( $row.hasClass( table.config.cssChildRow ) ) {
 181+ cache.row[cache.row.length - 1] = cache.row[cache.row.length - 1].add( $row );
 182+ // go to the next for loop
 183+ continue;
212184 }
213185
214 - function getElementText( node ) {
215 - if ( node.hasAttribute && node.hasAttribute( "data-sort-value" ) ) {
216 - return node.getAttribute( "data-sort-value" );
217 - } else {
218 - return $( node ).text();
219 - }
 186+ cache.row.push( $row );
 187+
 188+ for ( var j = 0; j < totalCells; ++j ) {
 189+ cols.push( parsers[j].format( getElementText( $row[0].cells[j] ), table, $row[0].cells[j] ) );
220190 }
221191
222 - function appendToTable( table, cache ) {
223 - // if ( table.config.debug ) {
224 - // var appendTime = new Date()
225 - // }
226 - var c = cache,
227 - r = c.row,
228 - n = c.normalized,
229 - totalRows = n.length,
230 - checkCell = (n[0].length - 1),
231 - tableBody = $( table.tBodies[0] ),
232 - fragment = document.createDocumentFragment();
 192+ cols.push( cache.normalized.length ); // add position for rowCache
 193+ cache.normalized.push( cols );
 194+ cols = null;
 195+ }
233196
234 - for ( var i = 0; i < totalRows; i++ ) {
235 - var pos = n[i][checkCell];
 197+ return cache;
 198+ }
236199
237 - var l = r[pos].length;
 200+ function appendToTable( table, cache ) {
 201+ var row = cache.row,
 202+ normalized = cache.normalized,
 203+ totalRows = normalized.length,
 204+ checkCell = ( normalized[0].length - 1 ),
 205+ fragment = document.createDocumentFragment();
238206
239 - for ( var j = 0; j < l; j++ ) {
240 - fragment.appendChild( r[pos][j] );
241 - }
 207+ for ( var i = 0; i < totalRows; i++ ) {
 208+ var pos = normalized[i][checkCell];
242209
243 - }
244 - tableBody[0].appendChild( fragment );
245 - // if ( table.config.debug ) {
246 - // benchmark( "Rebuilt table:", appendTime );
247 - // }
 210+ var l = row[pos].length;
 211+
 212+ for ( var j = 0; j < l; j++ ) {
 213+ fragment.appendChild( row[pos][j] );
248214 }
249215
250 - function buildHeaders( table, msg ) {
251 - var maxSeen = 0;
252 - var longest;
253 - // if ( table.config.debug ) {
254 - // var time = new Date();
255 - // }
256 - //var header_index = computeTableHeaderCellIndexes( table );
257 - var realCellIndex = 0;
258 - var $tableHeaders = $( "thead:eq(0) tr", table );
259 - if ( $tableHeaders.length > 1 ) {
260 - $tableHeaders.each(function() {
261 - if (this.cells.length > maxSeen) {
262 - maxSeen = this.cells.length;
263 - longest = this;
264 - }
265 - });
266 - $tableHeaders = $( longest );
 216+ }
 217+ table.tBodies[0].appendChild( fragment );
 218+ }
 219+
 220+ function buildHeaders( table, msg ) {
 221+ var maxSeen = 0,
 222+ longest,
 223+ realCellIndex = 0,
 224+ $tableHeaders = $( 'thead:eq(0) tr', table );
 225+ if ( $tableHeaders.length > 1 ) {
 226+ $tableHeaders.each(function() {
 227+ if ( this.cells.length > maxSeen ) {
 228+ maxSeen = this.cells.length;
 229+ longest = this;
267230 }
268 - $tableHeaders = $tableHeaders.find('th').each( function ( index ) {
269 - //var normalIndex = allCells.index( this );
270 - //var realCellIndex = 0;
271 - this.column = realCellIndex;
 231+ });
 232+ $tableHeaders = $( longest );
 233+ }
 234+ $tableHeaders = $tableHeaders.find( 'th' ).each( function( index ) {
 235+ this.column = realCellIndex;
272236
273 - var colspan = this.colspan;
274 - colspan = colspan ? parseInt( colspan, 10 ) : 1;
275 - realCellIndex += colspan;
 237+ var colspan = this.colspan;
 238+ colspan = colspan ? parseInt( colspan, 10 ) : 1;
 239+ realCellIndex += colspan;
276240
277 - //this.column = header_index[this.parentNode.rowIndex + "-" + this.cellIndex];
278 - this.order = 0;
279 - this.count = 0;
 241+ this.order = 0;
 242+ this.count = 0;
280243
281 - if ( $( this ).is( '.unsortable, .mw-unsortable' ) ) this.sortDisabled = true;
 244+ if ( $( this ).is( '.unsortable, .mw-unsortable' ) ) {
 245+ this.sortDisabled = true;
 246+ }
282247
283 - if ( !this.sortDisabled ) {
284 - var $th = $( this ).addClass( table.config.cssHeader ).attr( 'title', msg[1] );
285 -
286 - //if ( table.config.onRenderHeader ) table.config.onRenderHeader.apply($th);
287 - }
 248+ if ( !this.sortDisabled ) {
 249+ var $th = $( this ).addClass( table.config.cssHeader ).attr( 'title', msg[1] );
 250+ }
288251
289 - // add cell to headerList
290 - table.config.headerList[index] = this;
291 - } );
 252+ // add cell to headerList
 253+ table.config.headerList[index] = this;
 254+ } );
292255
293 - return $tableHeaders;
 256+ return $tableHeaders;
294257
 258+ }
 259+
 260+ function isValueInArray( v, a ) {
 261+ var l = a.length;
 262+ for ( var i = 0; i < l; i++ ) {
 263+ if ( a[i][0] == v ) {
 264+ return true;
295265 }
 266+ }
 267+ return false;
 268+ }
296269
297 - function isValueInArray( v, a ) {
298 - var l = a.length;
299 - for ( var i = 0; i < l; i++ ) {
300 - if ( a[i][0] == v ) {
301 - return true;
302 - }
303 - }
304 - return false;
 270+ function setHeadersCss( table, $headers, list, css, msg ) {
 271+ // Remove all header information
 272+ $headers.removeClass( css[0] ).removeClass( css[1] );
 273+
 274+ var h = [];
 275+ $headers.each( function( offset ) {
 276+ if ( !this.sortDisabled ) {
 277+ h[this.column] = $( this );
305278 }
 279+ } );
306280
307 - function setHeadersCss( table, $headers, list, css, msg ) {
308 - // remove all header information
309 - $headers.removeClass( css[0] ).removeClass( css[1] );
 281+ var l = list.length;
 282+ for ( var i = 0; i < l; i++ ) {
 283+ h[ list[i][0] ].addClass( css[ list[i][1] ] ).attr( 'title', msg[ list[i][1] ] );
 284+ }
 285+ }
310286
311 - var h = [];
312 - $headers.each( function ( offset ) {
313 - if ( !this.sortDisabled ) {
314 - h[this.column] = $( this );
315 - }
316 - } );
 287+ function sortText( a, b ) {
 288+ return ( (a < b) ? false : ((a > b) ? true : 0) );
 289+ }
317290
318 - var l = list.length;
319 - for ( var i = 0; i < l; i++ ) {
320 - h[ list[i][0] ].addClass( css[ list[i][1] ] ).attr( 'title', msg[ list[i][1] ] );
321 - }
322 - }
 291+ function sortTextDesc( a, b ) {
 292+ return ( (b < a) ? false : ((b > a) ? true : 0) );
 293+ }
323294
324 - function checkSorting (array1, array2, sortList) {
325 - var col, fn, ret;
326 - for ( var i = 0, len = sortList.length; i < len; i++ ) {
327 - col = sortList[i][0];
328 - fn = ( sortList[i][1] ) ? sortTextDesc : sortText;
329 - ret = fn.call( this, array1[col], array2[col] );
330 - if ( ret !== 0 ) {
331 - return ret;
332 - }
333 - }
 295+ function checkSorting( array1, array2, sortList ) {
 296+ var col, fn, ret;
 297+ for ( var i = 0, len = sortList.length; i < len; i++ ) {
 298+ col = sortList[i][0];
 299+ fn = ( sortList[i][1] ) ? sortTextDesc : sortText;
 300+ ret = fn.call( this, array1[col], array2[col] );
 301+ if ( ret !== 0 ) {
334302 return ret;
335303 }
 304+ }
 305+ return ret;
 306+ }
336307
337 - // Merge sort algorithm
338 - // Based on http://en.literateprograms.org/Merge_sort_(JavaScript)
339 - function mergeSortHelper(array, begin, beginRight, end, sortList) {
340 - for (; begin < beginRight; ++begin) {
341 - if (checkSorting( array[begin], array[beginRight], sortList )) {
342 - var v = array[begin];
343 - array[begin] = array[beginRight];
344 - var begin2 = beginRight;
345 - while ( begin2 + 1 < end && checkSorting( v, array[begin2 + 1], sortList ) ) {
346 - var tmp = array[begin2];
347 - array[begin2] = array[begin2 + 1];
348 - array[begin2 + 1] = tmp;
349 - ++begin2;
350 - }
351 - array[begin2] = v;
352 - }
 308+ // Merge sort algorithm
 309+ // Based on http://en.literateprograms.org/Merge_sort_(JavaScript)
 310+ function mergeSortHelper( array, begin, beginRight, end, sortList ) {
 311+ for ( ; begin < beginRight; ++begin ) {
 312+ if ( checkSorting( array[begin], array[beginRight], sortList ) ) {
 313+ var v = array[begin];
 314+ array[begin] = array[beginRight];
 315+ var begin2 = beginRight;
 316+ while ( begin2 + 1 < end && checkSorting( v, array[begin2 + 1], sortList ) ) {
 317+ var tmp = array[begin2];
 318+ array[begin2] = array[begin2 + 1];
 319+ array[begin2 + 1] = tmp;
 320+ ++begin2;
353321 }
 322+ array[begin2] = v;
354323 }
 324+ }
 325+ }
355326
356 - function mergeSort(array, begin, end, sortList) {
357 - var size = end - begin;
358 - if (size < 2) return;
 327+ function mergeSort(array, begin, end, sortList) {
 328+ var size = end - begin;
 329+ if ( size < 2 ) {
 330+ return;
 331+ }
359332
360 - var beginRight = begin + Math.floor(size / 2);
 333+ var beginRight = begin + Math.floor(size / 2);
361334
362 - mergeSort(array, begin, beginRight, sortList);
363 - mergeSort(array, beginRight, end, sortList);
364 - mergeSortHelper(array, begin, beginRight, end, sortList);
365 - }
 335+ mergeSort( array, begin, beginRight, sortList );
 336+ mergeSort( array, beginRight, end, sortList );
 337+ mergeSortHelper( array, begin, beginRight, end, sortList );
 338+ }
366339
367 - function multisort( table, sortList, cache ) {
368 - //var sortTime = new Date();
369 -
370 - var i = sortList.length;
371 - mergeSort(cache.normalized, 0, cache.normalized.length, sortList);
 340+ function multisort( table, sortList, cache ) {
 341+ var i = sortList.length;
 342+ mergeSort( cache.normalized, 0, cache.normalized.length, sortList );
372343
373 - //benchmark( "Sorting in dir " + order + " time:", sortTime );
374 -
375 - return cache;
376 - }
 344+ return cache;
 345+ }
377346
378 - function sortText( a, b ) {
379 - return ((a < b) ? false : ((a > b) ? true : 0));
380 - }
 347+ function buildTransformTable() {
 348+ var digits = '0123456789,.'.split( '' );
 349+ var separatorTransformTable = mw.config.get( 'wgSeparatorTransformTable' );
 350+ var digitTransformTable = mw.config.get( 'wgDigitTransformTable' );
 351+ if ( separatorTransformTable === null || ( separatorTransformTable[0] === '' && digitTransformTable[2] === '' ) ) {
 352+ ts.transformTable = false;
 353+ } else {
 354+ ts.transformTable = {};
381355
382 - function sortTextDesc( a, b ) {
383 - return ((b < a) ? false : ((b > a) ? true : 0));
 356+ // Unpack the transform table
 357+ var ascii = separatorTransformTable[0].split( "\t" ).concat( digitTransformTable[0].split( "\t" ) );
 358+ var localised = separatorTransformTable[1].split( "\t" ).concat( digitTransformTable[1].split( "\t" ) );
 359+
 360+ // Construct regex for number identification
 361+ for ( var i = 0; i < ascii.length; i++ ) {
 362+ ts.transformTable[localised[i]] = ascii[i];
 363+ digits.push( $.escapeRE( localised[i] ) );
384364 }
 365+ }
 366+ var digitClass = '[' + digits.join( '', digits ) + ']';
385367
386 - function buildTransformTable() {
387 - var digits = '0123456789,.'.split('');
388 - var separatorTransformTable = mw.config.get( 'wgSeparatorTransformTable' );
389 - var digitTransformTable = mw.config.get( 'wgDigitTransformTable' );
390 - if ( separatorTransformTable == null || ( separatorTransformTable[0] == '' && digitTransformTable[2] == '' ) ) {
391 - ts.transformTable = false;
392 - } else {
393 - ts.transformTable = {};
 368+ // We allow a trailing percent sign, which we just strip. This works fine
 369+ // if percents and regular numbers aren't being mixed.
 370+ ts.numberRegex = new RegExp("^(" + "[-+\u2212]?[0-9][0-9,]*(\\.[0-9,]*)?(E[-+\u2212]?[0-9][0-9,]*)?" + // Fortran-style scientific
 371+ "|" + "[-+\u2212]?" + digitClass + "+[\\s\\xa0]*%?" + // Generic localised
 372+ ")$", "i");
 373+ }
394374
395 - // Unpack the transform table
396 - var ascii = separatorTransformTable[0].split( "\t" ).concat( digitTransformTable[0].split( "\t" ) );
397 - var localised = separatorTransformTable[1].split( "\t" ).concat( digitTransformTable[1].split( "\t" ) );
 375+ function buildDateTable() {
 376+ var regex = [];
 377+ ts.monthNames = [
 378+ [],
 379+ []
 380+ ];
398381
399 - // Construct regex for number identification
400 - for ( var i = 0; i < ascii.length; i++ ) {
401 - ts.transformTable[localised[i]] = ascii[i];
402 - digits.push( $.escapeRE( localised[i] ) );
403 - }
404 - }
405 - var digitClass = '[' + digits.join( '', digits ) + ']';
 382+ for ( var i = 1; i < 13; i++ ) {
 383+ ts.monthNames[0][i] = mw.config.get( 'wgMonthNames' )[i].toLowerCase();
 384+ ts.monthNames[1][i] = mw.config.get( 'wgMonthNamesShort' )[i].toLowerCase().replace( '.', '' );
 385+ regex.push( $.escapeRE( ts.monthNames[0][i] ) );
 386+ regex.push( $.escapeRE( ts.monthNames[1][i] ) );
 387+ }
406388
407 - // We allow a trailing percent sign, which we just strip. This works fine
408 - // if percents and regular numbers aren't being mixed.
409 - ts.numberRegex = new RegExp("^(" + "[-+\u2212]?[0-9][0-9,]*(\\.[0-9,]*)?(E[-+\u2212]?[0-9][0-9,]*)?" + // Fortran-style scientific
410 - "|" + "[-+\u2212]?" + digitClass + "+[\\s\\xa0]*%?" + // Generic localised
411 - ")$", "i");
412 - }
 389+ // Build piped string
 390+ regex = regex.join( '|' );
413391
414 - function buildDateTable() {
415 - var r = '';
416 - ts.monthNames = [
417 - [],
418 - []
419 - ];
420 - ts.dateRegex = [];
 392+ // Build RegEx
 393+ // Any date formated with . , ' - or /
 394+ ts.dateRegex[0] = new RegExp( /^\s*\d{1,2}[\,\.\-\/'\s]{1,2}\d{1,2}[\,\.\-\/'\s]{1,2}\d{2,4}\s*?/i);
421395
422 - for ( var i = 1; i < 13; i++ ) {
423 - ts.monthNames[0][i] = mw.config.get( 'wgMonthNames' )[i].toLowerCase();
424 - ts.monthNames[1][i] = mw.config.get( 'wgMonthNamesShort' )[i].toLowerCase().replace( '.', '' );
425 - r += $.escapeRE( ts.monthNames[0][i] ) + '|';
426 - r += $.escapeRE( ts.monthNames[1][i] ) + '|';
427 - }
 396+ // Written Month name, dmy
 397+ ts.dateRegex[1] = new RegExp( '^\\s*\\d{1,2}[\\,\\.\\-\\/\'\\s]*(' + regex + ')' + '[\\,\\.\\-\\/\'\\s]*\\d{2,4}\\s*$', 'i' );
428398
429 - //Remove trailing pipe
430 - r = r.slice( 0, -1 );
 399+ // Written Month name, mdy
 400+ ts.dateRegex[2] = new RegExp( '^\\s*(' + regex + ')' + '[\\,\\.\\-\\/\'\\s]*\\d{1,2}[\\,\\.\\-\\/\'\\s]*\\d{2,4}\\s*$', 'i' );
431401
432 - //Build RegEx
433 - //Any date formated with . , ' - or /
434 - ts.dateRegex[0] = new RegExp(/^\s*\d{1,2}[\,\.\-\/'\s]{1,2}\d{1,2}[\,\.\-\/'\s]{1,2}\d{2,4}\s*?/i);
 402+ }
435403
436 - //Written Month name, dmy
437 - ts.dateRegex[1] = new RegExp('^\\s*\\d{1,2}[\\,\\.\\-\\/\'\\s]*(' + r + ')' + '[\\,\\.\\-\\/\'\\s]*\\d{2,4}\\s*$', 'i');
 404+ function explodeRowspans( $table ) {
 405+ // Split multi row cells into multiple cells with the same content
 406+ $table.find( '[rowspan]' ).each(function() {
 407+ var rowSpan = this.rowSpan;
 408+ this.rowSpan = 1;
 409+ var cell = $( this );
 410+ var next = cell.parent().nextAll();
 411+ for ( var i = 0; i < rowSpan - 1; i++ ) {
 412+ var td = next.eq( i ).find( 'td' );
 413+ if ( !td.length ) {
 414+ next.eq( i ).append( cell.clone() );
 415+ } else if ( this.cellIndex === 0 ) {
 416+ td.eq( this.cellIndex ).before( cell.clone() );
 417+ } else {
 418+ td.eq( this.cellIndex - 1 ).after( cell.clone() );
 419+ }
 420+ }
 421+ });
 422+ }
438423
439 - //Written Month name, mdy
440 - ts.dateRegex[2] = new RegExp('^\\s*(' + r + ')' + '[\\,\\.\\-\\/\'\\s]*\\d{1,2}[\\,\\.\\-\\/\'\\s]*\\d{2,4}\\s*$', 'i');
 424+ function buildCollationTable() {
 425+ ts.collationTable = mw.config.get( 'tableSorterCollation' );
 426+ ts.collationRegex = null;
 427+ if ( ts.collationTable ) {
 428+ var keys = [];
441429
 430+ // Build array of key names
 431+ for ( var key in ts.collationTable ) {
 432+ if ( ts.collationTable.hasOwnProperty(key) ) { //to be safe
 433+ keys.push(key);
 434+ }
442435 }
443 -
444 - function explodeRowspans( $table ) {
445 - // Split multi row cells into multiple cells with the same content
446 - $table.find( '[rowspan]' ).each(function() {
447 - var rowSpan = this.rowSpan;
448 - this.rowSpan = 1;
449 - var cell = $( this );
450 - var next = cell.parent().nextAll();
451 - for ( var i = 0; i < rowSpan - 1; i++ ) {
452 - var td = next.eq( i ).find( 'td' );
453 - if ( !td.length ) {
454 - next.eq( i ).append( cell.clone() );
455 - } else if ( this.cellIndex == 0 ) {
456 - td.eq( this.cellIndex ).before( cell.clone() );
457 - } else {
458 - td.eq( this.cellIndex - 1 ).after( cell.clone() );
459 - }
460 - }
461 - });
 436+ if (keys.length) {
 437+ ts.collationRegex = new RegExp( '[' + keys.join( '' ) + ']', 'ig' );
462438 }
 439+ }
 440+ }
463441
464 - function buildCollationTable() {
465 - ts.collationTable = mw.config.get('tableSorterCollation');
466 - ts.collationRegex = null;
467 - if ( ts.collationTable ) {
468 - var keys = [];
 442+ function cacheRegexs() {
 443+ if ( ts.rgx ) {
 444+ return;
 445+ }
 446+ ts.rgx = {
 447+ IPAddress: [
 448+ new RegExp( /^\d{1,3}[\.]\d{1,3}[\.]\d{1,3}[\.]\d{1,3}$/)
 449+ ],
 450+ currency: [
 451+ new RegExp( /^[£$€?.]/),
 452+ new RegExp( /[£$€]/g)
 453+ ],
 454+ url: [
 455+ new RegExp( /^(https?|ftp|file):\/\/$/),
 456+ new RegExp( /(https?|ftp|file):\/\//)
 457+ ],
 458+ isoDate: [
 459+ new RegExp( /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/)
 460+ ],
 461+ usLongDate: [
 462+ 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)))$/)
 463+ ],
 464+ time: [
 465+ new RegExp( /^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/)
 466+ ]
 467+ };
 468+ }
469469
470 - //Build array of key names
471 - for ( var key in ts.collationTable ) {
472 - if ( ts.collationTable.hasOwnProperty(key) ) { //to be safe
473 - keys.push(key);
474 - }
 470+ /* Public scope */
 471+
 472+ $.tablesorter = {
 473+
 474+ defaultOptions: {
 475+ cssHeader: 'headerSort',
 476+ cssAsc: 'headerSortUp',
 477+ cssDesc: 'headerSortDown',
 478+ cssChildRow: 'expand-child',
 479+ sortInitialOrder: 'asc',
 480+ sortMultiSortKey: 'shiftKey',
 481+ sortLocaleCompare: false,
 482+ parsers: {},
 483+ widgets: [],
 484+ headers: {},
 485+ cancelSelection: true,
 486+ sortList: [],
 487+ headerList: [],
 488+ selectorHeaders: 'thead tr:eq(0) th',
 489+ debug: false
 490+ },
 491+
 492+ dateRegex: [],
 493+ monthNames: [],
 494+
 495+ /**
 496+ * @param $tables {jQuery}
 497+ * @param settings {Object} (optional)
 498+ */
 499+ construct: function( $tables, settings ) {
 500+ return $tables.each( function( i, table ) {
 501+
 502+ // Quit if no thead or tbody.
 503+ if ( !table.tHead || !table.tBodies ) {
 504+ return;
475505 }
476 - if (keys.length) {
477 - ts.collationRegex = new RegExp( '[' + keys.join('') + ']', 'ig' );
478 - }
479 - }
480 - }
 506+ // Declare and cache.
 507+ var $document, $headers, cache, config, sortOrder,
 508+ $table = $( table ),
 509+ shiftDown = 0,
 510+ firstTime = true;
481511
482 - function cacheRegexs() {
483 - ts.rgx = {
484 - IPAddress: [new RegExp(/^\d{1,3}[\.]\d{1,3}[\.]\d{1,3}[\.]\d{1,3}$/)],
485 - currency: [new RegExp(/^[£$€?.]/), new RegExp(/[£$€]/g)],
486 - url: [new RegExp(/^(https?|ftp|file):\/\/$/), new RegExp(/(https?|ftp|file):\/\//)],
487 - isoDate: [new RegExp(/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/)],
488 - 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)))$/)],
489 - time: [new RegExp(/^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/)]
490 - };
491 - } /* public methods */
492 - this.construct = function ( settings ) {
493 - return this.each( function () {
494 - // if no thead or tbody quit.
495 - if ( !this.tHead || !this.tBodies ) return;
496 - // declare
497 - var $this, $document, $headers, cache, config, shiftDown = 0,
498 - sortOrder, firstTime = true, that = this;
499 - // new blank config object
500 - this.config = {};
501 - // merge and extend.
502 - config = $.extend( this.config, $.tablesorter.defaults, settings );
 512+ // New config object.
 513+ table.config = {};
503514
504 - // store common expression for speed
505 - $this = $( this );
506 - // save the settings where they read
507 - $.data( this, "tablesorter", config );
 515+ // Merge and extend.
 516+ config = $.extend( table.config, $.tablesorter.defaultOptions, settings );
508517
509 - // get the css class names, could be done else where.
 518+ // Save the settings where they read
 519+ $.data( table, 'tablesorter', config );
 520+
 521+ // Get the CSS class names, could be done else where.
510522 var sortCSS = [ config.cssDesc, config.cssAsc ];
511523 var sortMsg = [ mw.msg( 'sort-descending' ), mw.msg( 'sort-ascending' ) ];
512524
513 - // build headers
514 - $headers = buildHeaders( this, sortMsg );
 525+ // Build headers
 526+ $headers = buildHeaders( table, sortMsg );
 527+
515528 // Grab and process locale settings
516529 buildTransformTable();
517530 buildDateTable();
518531 buildCollationTable();
519532
520 - //Precaching regexps can bring 10 fold
521 - //performance improvements in some browsers
 533+ // Precaching regexps can bring 10 fold
 534+ // performance improvements in some browsers.
522535 cacheRegexs();
523536
524 - // apply event handling to headers
 537+ // Apply event handling to headers
525538 // this is to big, perhaps break it out?
526 - $headers.click(
 539+ $headers.click( function( e ) {
527540
528 - function (e) {
529 - //var clickTime= new Date();
530 - if (firstTime) {
 541+ if ( firstTime ) {
531542 firstTime = false;
532 - explodeRowspans( $this );
 543+ explodeRowspans( $table );
533544 // try to auto detect column type, and store in tables config
534 - that.config.parsers = buildParserCache( that, $headers );
 545+ table.config.parsers = buildParserCache( table, $headers );
535546 // build the cache for the tbody cells
536 - cache = buildCache( that );
 547+ cache = buildCache( table );
537548 }
538 - var totalRows = ( $this[0].tBodies[0] && $this[0].tBodies[0].rows.length ) || 0;
539 - if ( !this.sortDisabled && totalRows > 0 ) {
540 - // Only call sortStart if sorting is
541 - // enabled.
542 - //$this.trigger( "sortStart" );
 549+ var totalRows = ( $table[0].tBodies[0] && $table[0].tBodies[0].rows.length ) || 0;
 550+ if ( !table.sortDisabled && totalRows > 0 ) {
543551
544 - // store exp, for speed
 552+ // Cache jQuery object
545553 var $cell = $( this );
546 - // get current column index
 554+
 555+ // Get current column index
547556 var i = this.column;
548 - // get current column sort order
 557+
 558+ // Get current column sort order
549559 this.order = this.count % 2;
550560 this.count++;
551 - // user only whants to sort on one
552 - // column
 561+
 562+ // User only wants to sort on one column
553563 if ( !e[config.sortMultiSortKey] ) {
554 - // flush the sort list
 564+ // Flush the sort list
555565 config.sortList = [];
556 - // add column to sort list
 566+ // Add column to sort list
557567 config.sortList.push( [i, this.order] );
558 - // multi column sorting
 568+
 569+ // Multi column sorting
559570 } else {
560 - // the user has clicked on an already sorted column.
 571+ // The user has clicked on an already sorted column.
561572 if ( isValueInArray( i, config.sortList ) ) {
562 - // revers the sorting direction
563 - // for all tables.
 573+ // Reverse the sorting direction for all tables.
564574 for ( var j = 0; j < config.sortList.length; j++ ) {
565575 var s = config.sortList[j],
566576 o = config.headerList[s[0]];
@@ -570,79 +580,50 @@
571581 }
572582 }
573583 } else {
574 - // add column to sort list array
 584+ // Add column to sort list array
575585 config.sortList.push( [i, this.order] );
576586 }
577587 }
578588
579 - // set css for headers
580 - setHeadersCss( $this[0], $headers, config.sortList, sortCSS, sortMsg );
581 - appendToTable(
582 - $this[0], multisort(
583 - $this[0], config.sortList, cache ) );
584 - //benchmark( "Sorting " + totalRows + " rows:", clickTime );
 589+ // Set CSS for headers
 590+ setHeadersCss( $table[0], $headers, config.sortList, sortCSS, sortMsg );
 591+ appendToTable(
 592+ $table[0], multisort( $table[0], config.sortList, cache )
 593+ );
585594
586 - // stop normal event by returning false
 595+ // Stop normal event by returning false
587596 return false;
588597 }
589 - // cancel selection
590 - } ).mousedown( function () {
 598+
 599+ // Cancel selection
 600+ } ).mousedown( function() {
591601 if ( config.cancelSelection ) {
592 - this.onselectstart = function () {
 602+ this.onselectstart = function() {
593603 return false;
594604 };
595605 return false;
596606 }
597607 } );
598 - // apply easy methods that trigger binded events
599 - //Can't think of any use for these in a mw context
600 - // $this.bind( "update", function () {
601 - // var me = this;
602 - // setTimeout( function () {
603 - // // rebuild parsers.
604 - // me.config.parsers = buildParserCache(
605 - // me, $headers );
606 - // // rebuild the cache map
607 - // cache = buildCache(me);
608 - // }, 1 );
609 - // } ).bind( "updateCell", function ( e, cell ) {
610 - // var config = this.config;
611 - // // get position from the dom.
612 - // var pos = [( cell.parentNode.rowIndex - 1 ), cell.cellIndex];
613 - // // update cache
614 - // cache.normalized[pos[0]][pos[1]] = config.parsers[pos[1]].format(
615 - // getElementText( cell ), cell );
616 - // } ).bind( "sorton", function ( e, list ) {
617 - // $( this ).trigger( "sortStart" );
618 - // config.sortList = list;
619 - // // update and store the sortlist
620 - // var sortList = config.sortList;
621 - // // update header count index
622 - // updateHeaderSortCount( this, sortList );
623 - // // set css for headers
624 - // setHeadersCss( this, $headers, sortList, sortCSS );
625 - // // sort the table and append it to the dom
626 - // appendToTable( this, multisort( this, sortList, cache ) );
627 - // } ).bind( "appendCache", function () {
628 - // appendToTable( this, cache );
629 - // } );
 608+
630609 } );
631 - };
632 - this.addParser = function ( parser ) {
633 - var l = parsers.length,
 610+ },
 611+
 612+ addParser: function( parser ) {
 613+ var l = parsers.length,
634614 a = true;
635615 for ( var i = 0; i < l; i++ ) {
636616 if ( parsers[i].id.toLowerCase() == parser.id.toLowerCase() ) {
637617 a = false;
638618 }
639619 }
640 - if (a) {
 620+ if ( a ) {
641621 parsers.push( parser );
642622 }
643 - };
644 - this.formatDigit = function (s) {
645 - if ( ts.transformTable != false ) {
646 - var out = '',
 623+ },
 624+
 625+ formatDigit: function( s ) {
 626+ if ( ts.transformTable !== false ) {
 627+ var out = '',
647628 c;
648629 for ( var p = 0; p < s.length; p++ ) {
649630 c = s.charAt(p);
@@ -654,134 +635,137 @@
655636 }
656637 s = out;
657638 }
658 - var i = parseFloat( s.replace(/[, ]/g, '').replace( "\u2212", '-' ) );
 639+ var i = parseFloat( s.replace( /[, ]/g, '' ).replace( "\u2212", '-' ) );
659640 return ( isNaN(i)) ? 0 : i;
660 - };
661 - this.formatFloat = function (s) {
 641+ },
 642+
 643+ formatFloat: function( s ) {
662644 var i = parseFloat(s);
663645 return ( isNaN(i)) ? 0 : i;
664 - };
665 - this.formatInt = function (s) {
 646+ },
 647+
 648+ formatInt: function( s ) {
666649 var i = parseInt( s, 10 );
667650 return ( isNaN(i)) ? 0 : i;
668 - };
669 - this.clearTableBody = function ( table ) {
 651+ },
 652+
 653+ clearTableBody: function( table ) {
670654 if ( $.browser.msie ) {
671 - function empty() {
672 - while ( this.firstChild )
673 - this.removeChild( this.firstChild );
674 - }
675 - empty.apply( table.tBodies[0] );
 655+ var empty = function( el ) {
 656+ while ( el.firstChild ) {
 657+ el.removeChild( el.firstChild );
 658+ }
 659+ };
 660+ empty( table.tBodies[0] );
676661 } else {
677 - table.tBodies[0].innerHTML = "";
 662+ table.tBodies[0].innerHTML = '';
678663 }
679 - };
680 - }
681 - } );
 664+ }
 665+ };
682666
683 - // extend plugin scope
684 - $.fn.extend( {
685 - tablesorter: $.tablesorter.construct
686 - } );
 667+ // Shortcut
 668+ ts = $.tablesorter;
687669
688 - // make shortcut
689 - var ts = $.tablesorter;
 670+ // Register as jQuery prototype method
 671+ $.fn.tablesorter = function( settings ) {
 672+ return ts.construct( this, settings );
 673+ };
690674
691 - // add default parsers
 675+ // Add default parsers
692676 ts.addParser( {
693 - id: "text",
694 - is: function (s) {
 677+ id: 'text',
 678+ is: function( s ) {
695679 return true;
696680 },
697 - format: function (s) {
 681+ format: function( s ) {
698682 s = $.trim( s.toLowerCase() );
699683 if ( ts.collationRegex ) {
700684 var tsc = ts.collationTable;
701 - s = s.replace( ts.collationRegex, function ( match ) {
 685+ s = s.replace( ts.collationRegex, function( match ) {
702686 var r = tsc[match] ? tsc[match] : tsc[match.toUpperCase()];
703687 return r.toLowerCase();
704688 } );
705689 }
706690 return s;
707691 },
708 - type: "text"
 692+ type: 'text'
709693 } );
710694
711695 ts.addParser( {
712 - id: "IPAddress",
713 - is: function (s) {
 696+ id: 'IPAddress',
 697+ is: function( s ) {
714698 return ts.rgx.IPAddress[0].test(s);
715699 },
716 - format: function (s) {
717 - var a = s.split("."),
718 - r = "",
 700+ format: function( s ) {
 701+ var a = s.split( '.' ),
 702+ r = '',
719703 l = a.length;
720704 for ( var i = 0; i < l; i++ ) {
721705 var item = a[i];
722706 if ( item.length == 1 ) {
723 - r += "00" + item;
 707+ r += '00' + item;
724708 } else if ( item.length == 2 ) {
725 - r += "0" + item;
 709+ r += '0' + item;
726710 } else {
727711 r += item;
728712 }
729713 }
730714 return $.tablesorter.formatFloat(r);
731715 },
732 - type: "numeric"
 716+ type: 'numeric'
733717 } );
734718
735719 ts.addParser( {
736 - id: "currency",
737 - is: function (s) {
 720+ id: 'currency',
 721+ is: function( s ) {
738722 return ts.rgx.currency[0].test(s);
739723 },
740 - format: function (s) {
741 - return $.tablesorter.formatDigit( s.replace( ts.rgx.currency[1], "" ) );
 724+ format: function( s ) {
 725+ return $.tablesorter.formatDigit( s.replace( ts.rgx.currency[1], '' ) );
742726 },
743 - type: "numeric"
 727+ type: 'numeric'
744728 } );
745729
746730 ts.addParser( {
747 - id: "url",
748 - is: function (s) {
 731+ id: 'url',
 732+ is: function( s ) {
749733 return ts.rgx.url[0].test(s);
750734 },
751 - format: function (s) {
 735+ format: function( s ) {
752736 return $.trim( s.replace( ts.rgx.url[1], '' ) );
753737 },
754 - type: "text"
 738+ type: 'text'
755739 } );
756740
757741 ts.addParser( {
758 - id: "isoDate",
759 - is: function (s) {
 742+ id: 'isoDate',
 743+ is: function( s ) {
760744 return ts.rgx.isoDate[0].test(s);
761745 },
762 - format: function (s) {
763 - return $.tablesorter.formatFloat((s != "") ? new Date(s.replace(
764 - new RegExp(/-/g), "/")).getTime() : "0");
 746+ format: function( s ) {
 747+ return $.tablesorter.formatFloat((s !== '') ? new Date(s.replace(
 748+ new RegExp( /-/g), '/')).getTime() : '0' );
765749 },
766 - type: "numeric"
 750+ type: 'numeric'
767751 } );
768752
769753 ts.addParser( {
770 - id: "usLongDate",
771 - is: function (s) {
 754+ id: 'usLongDate',
 755+ is: function( s ) {
772756 return ts.rgx.usLongDate[0].test(s);
773757 },
774 - format: function (s) {
 758+ format: function( s ) {
775759 return $.tablesorter.formatFloat( new Date(s).getTime() );
776760 },
777 - type: "numeric"
 761+ type: 'numeric'
778762 } );
779763
780764 ts.addParser( {
781 - id: "date",
782 - is: function (s) {
 765+ id: 'date',
 766+ is: function( s ) {
783767 return ( ts.dateRegex[0].test(s) || ts.dateRegex[1].test(s) || ts.dateRegex[2].test(s ));
784768 },
785 - format: function ( s, table ) {
 769+ format: function( s, table ) {
786770 s = $.trim( s.toLowerCase() );
787771
788772 for ( var i = 1, j = 0; i < 13 && j < 2; i++ ) {
@@ -792,61 +776,67 @@
793777 }
794778 }
795779
796 - s = s.replace(/[\-\.\,' ]/g, "/");
 780+ s = s.replace( /[\-\.\,' ]/g, '/' );
797781
798 - //Replace double slashes
799 - s = s.replace(/\/\//g, "/");
800 - s = s.replace(/\/\//g, "/");
801 - s = s.split('/');
 782+ // Replace double slashes
 783+ s = s.replace( /\/\//g, '/' );
 784+ s = s.replace( /\/\//g, '/' );
 785+ s = s.split( '/' );
802786
803 - //Pad Month and Day
804 - if ( s[0] && s[0].length == 1 ) s[0] = "0" + s[0];
805 - if ( s[1] && s[1].length == 1 ) s[1] = "0" + s[1];
 787+ // Pad Month and Day
 788+ if ( s[0] && s[0].length == 1 ) {
 789+ s[0] = '0' + s[0];
 790+ }
 791+ if ( s[1] && s[1].length == 1 ) {
 792+ s[1] = '0' + s[1];
 793+ }
806794 var y;
807795
808796 if ( !s[2] ) {
809 - //Fix yearless dates
 797+ // Fix yearless dates
810798 s[2] = 2000;
811799 } else if ( ( y = parseInt( s[2], 10) ) < 100 ) {
812 - //Guestimate years without centuries
 800+ // Guestimate years without centuries
813801 if ( y < 30 ) {
814802 s[2] = 2000 + y;
815803 } else {
816804 s[2] = 1900 + y;
817805 }
818806 }
819 - //Resort array depending on preferences
820 - if ( mw.config.get( 'wgDefaultDateFormat' ) == "mdy" || mw.config.get('wgContentLanguage') == 'en' ) {
 807+ // Resort array depending on preferences
 808+ if ( mw.config.get( 'wgDefaultDateFormat' ) == 'mdy' || mw.config.get( 'wgContentLanguage' ) == 'en' ) {
821809 s.push( s.shift() );
822810 s.push( s.shift() );
823 - } else if ( mw.config.get( 'wgDefaultDateFormat' ) == "dmy" ) {
 811+ } else if ( mw.config.get( 'wgDefaultDateFormat' ) == 'dmy' ) {
824812 var d = s.shift();
825813 s.push( s.shift() );
826814 s.push(d);
827815 }
828 - return parseInt( s.join(''), 10 );
 816+ return parseInt( s.join( '' ), 10 );
829817 },
830 - type: "numeric"
 818+ type: 'numeric'
831819 } );
 820+
832821 ts.addParser( {
833 - id: "time",
834 - is: function (s) {
 822+ id: 'time',
 823+ is: function( s ) {
835824 return ts.rgx.time[0].test(s);
836825 },
837 - format: function (s) {
838 - return $.tablesorter.formatFloat( new Date( "2000/01/01 " + s ).getTime() );
 826+ format: function( s ) {
 827+ return $.tablesorter.formatFloat( new Date( '2000/01/01 ' + s ).getTime() );
839828 },
840 - type: "numeric"
 829+ type: 'numeric'
841830 } );
 831+
842832 ts.addParser( {
843 - id: "number",
844 - is: function ( s, table ) {
845 - return $.tablesorter.numberRegex.test( $.trim(s ));
 833+ id: 'number',
 834+ is: function( s, table ) {
 835+ return $.tablesorter.numberRegex.test( $.trim( s ));
846836 },
847 - format: function (s) {
 837+ format: function( s ) {
848838 return $.tablesorter.formatDigit(s);
849839 },
850 - type: "numeric"
 840+ type: 'numeric'
851841 } );
852 -
 842+
853843 } )( jQuery );

Comments

#Comment by Catrope (talk | contribs)   15:26, 16 August 2011

Aaargh, please don't move functions and change them in the same commit, because it produces a diff that's horrendously difficult to review. When you commit something, please consider what the resulting diff would look like and split things up in multiple commits if that's needed to preserve the sanity of your reviewers.

#Comment by Catrope (talk | contribs)   15:07, 17 August 2011
+				new RegExp( /^\d{1,3}[\.]\d{1,3}[\.]\d{1,3}[\.]\d{1,3}$/)

Why would you use new RegExp() here? You only need that for dynamic string input, otherwise you can just pass in the regex directly.

+			// Replace double slashes
+			s = s.replace( /\/\//g, '/' );
+			s = s.replace( /\/\//g, '/' );

Why would you collapse double slashes twice? Did this mean to do .replace( /\/\/+/g, '/' ) ?

#Comment by Dantman (talk | contribs)   15:25, 17 August 2011

...regexps using literal /regexp/i syntax are compiled around when the script is parsed, unless you are using new RegExp, which you should ONLY be using if you absolutely have to build a regexp dynamically by concatenating strings together.

Of course new RegExp(/regexp/i) completely negates every built in performance optimisation that browser vendors have worked into the language and makes absolutely no sense.

...as a ES dev... I weep...

Status & tagging log