1/* 2 SortTable 3 4 Instructions: 5 Used from dokuwiki 6 Click on the headers to sort 7 8 Thanks to many, many people for contributions and suggestions. 9 Currently licensed as X11: 10 http://www.kryogenix.org/code/browser/licence.html 11 12 v2.1 (7th April 2007) 13 * originally by Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/ 14 15 v2.1b (19 Feb 2008) 16 * first Otto Vainio (otto@valjakko.net) revision 17 * Fixed some jslint errors to support DokuWiki (http://www.splitbrain.org) js compression 18 * function reinitsort() 19 * sorttable.reinit 20 21 v2.2 (27.11.2008) 22 * Changed line 77 document.getElementsByTagName('table') to div.getElementsByTagName('table') 23 to allow multiple sortable tables in same page (Thanks to Hans Sampiemon) 24 25 v2.3 (14.1.2009) 26 * Added option for default sorting. 27 * Use dokuwiki event registration. 28 29 v2.4 (27.1.2009) 30 * Cleaned some jlint errors to make this workable, when css+js compress is set in dokuwiki 31 32 v2.5 (10.5.2011) 33 * Fixed problems with secionediting, footnotes and edittable 34 35 v2.6 (18.7.2013) 36 * Added support for jQuery and dokuwiki Weatherwax -> 37 38 v2.7 (28.5.2014) 39 * Fixed problem with first row not getting sorted 40 41 v2.8 (30.5.2014) 42 * Fixed problem with first row not getting sorted in default sort. Added option "sumrow" to prevent sum line sort. 43 44 v2.9 (13.8.2014) 45 * Fixed problem with header row being sorted in earlier versions of dokuwiki. Added option for sorting back to default 46 47 v2.11 (6.7.2015) 48 * Added ip address sort. (Thanks Chefkeks) 49 50 v2.12 (14.12.2015) 51 * PHP 7 compatibility and issue #8. Default sort for columns > 9 52 53 v2.13 54 * revision by Vaxquis; fixes some (most) of the current issues 55 */ 56 57// 58 59var stIsIE = /*@cc_on!@*/false; 60//var tableid = 0; 61 62var sorttable = { 63 reinit: function () { 64 arguments.callee.done = true; 65 // kill the timer 66 //if (_timer) {clearInterval(_timer);} 67 68 if ( !document.createElement || !document.getElementsByTagName ) { 69 return; 70 } 71 72// sorttable.DATE_RE = /^(\d\d?)[\/\.\-](\d\d?)[\/\.\-]((\d\d)?\d\d)$/; 73 sorttable.DATE_RE = /^(\d\d?)[\/\.\-](\d\d?)[\/\.\-]((\d\d)?\d\d)((\d\d?)[:\.]?(\d\d?))?$/; 74 75 var elems = document.getElementsByTagName( "table" ); 76 var elem; 77 for( var i = 0; i < elems.length; i++ ) { 78 elem = elems[i]; 79 if ( elem.className.search( /\bsortable\b/ ) !== -1 ) { 80 sorttable.makeSortable( elem ); 81 } 82 } 83 elems = document.getElementsByTagName( "div" ); 84 for( var i = 0; i < elems.length; i++ ) { 85 elem = elems[i]; 86 if ( elem.className.search( /\bsortable\b/ ) !== -1 ) { 87 sorttable.makeSortableDiv( elem ); 88 } 89 } 90 }, 91 init: function () { 92 if ( arguments.callee.done ) { 93 return; 94 } 95 sorttable.reinit(); 96 }, 97 makeSortableDiv: function ( div ) { 98 var childTables = div.getElementsByTagName( "table" ); 99 var elem; 100 for( var i = 0; i < childTables.length; i++ ) { 101 elem = childTables[i]; 102 var colid = div.className; 103 var patt1 = /\bcol_\d_[a-z]+/gi; 104 var overs = []; 105 if ( colid.search( patt1 ) !== -1 ) { 106 var overrides = colid.match( patt1 ); 107 for( var i = 0; i < overrides.length; i++ ) { 108 var entry = overrides[i]; 109 if ( entry !== "" ) { 110 try { 111 var tmp = entry.split( "_" ); 112 var ind = tmp[1]; 113 var val = tmp[2]; 114 overs[ind] = val; 115 } catch( e ) { 116 } 117 } 118 } 119 colid = colid.replace( patt1, '' ); 120 } 121 var patt2 = /\bsortbottom_?\d?/gi; 122 var bottoms = 0; 123 if ( colid.search( patt2 ) !== -1 ) { 124 var bs = colid.match( patt2 ); 125 try { 126 var tmp = bs[0].split( "_" ); 127 //var ind = tmp[1]; 128 var val = 1; 129 if ( tmp.length > 1 ) { 130 val = tmp[1]; 131 } 132 bottoms = val; 133 } catch( e ) { 134 } 135 } 136 var patt2ph = /\bthreephase/gi; 137 var ph2 = true; 138 if ( colid.search( patt2ph ) !== -1 ) { 139 ph2 = false; 140 } 141 142 sorttable.makeSortable( elem, overs, bottoms, ph2 ); 143 var pattdefault = /\bsortr?\d\d?/gi; 144 if ( colid.search( pattdefault ) !== -1 ) { 145 var mi = colid.match( pattdefault ); 146 colid = mi[0].replace( 'sort', '' ); 147 if ( colid !== '' ) { 148 colid = colid.trim(); 149 } 150 var revs = false; 151 if ( colid.search( /\br/ ) !== -1 ) { 152 revs = true; 153 colid = colid.replace( 'r', '' ); 154 } 155 sorttable.defaultSort( elem, colid, revs ); 156 } 157 } 158 }, 159 defaultSort: function ( table, colid, revs ) { 160// theadrow = table.tHead.rows[0].cells; 161 var havetHead = table.tHead; 162 var sindex = 1; 163 if ( havetHead ) { 164 sindex = 0; 165 } 166 var theadrow = table.rows[0].cells; 167 colid--; 168 var colname = "col" + colid; 169 // remove sorttable_sorted classes 170 var thiscell = false; 171 for( var i = 0; i < theadrow.length; i++ ) { 172 var cell = theadrow[i]; 173 var colclass = cell.className; 174 var classname = colclass.split( " " ); 175// if (cell.className==colname) 176 if ( classname[0] === colname ) { 177 thiscell = cell; 178 } 179// if (cell.nodeType == 1) { // an element 180// cell.className = cell.className.replace('sorttable_sorted_reverse',''); 181// cell.className = cell.className.replace('sorttable_sorted',''); 182// } 183 } 184 if ( thiscell === false ) { 185 return; 186 } 187 var sortfwdind = document.getElementById( 'sorttable_sortfwdind' ); 188 if ( sortfwdind ) { 189 sortfwdind.parentNode.removeChild( sortfwdind ); 190 } 191 var sortrevind = document.getElementById( 'sorttable_sortrevind' ); 192 if ( sortrevind ) { 193 sortrevind.parentNode.removeChild( sortrevind ); 194 } 195 196 thiscell.className += ' sorttable_sorted'; 197 sortfwdind = document.createElement( 'span' ); 198 sortfwdind.id = "sorttable_sortfwdind"; 199 sortfwdind.innerHTML = stIsIE ? ' <font face="webdings">6</font>' : ' ▾'; 200 thiscell.appendChild( sortfwdind ); 201 202 // build an array to sort. This is a Schwartzian transform thing, 203 // i.e., we "decorate" each row with the actual sort key, 204 // sort based on the sort keys, and then put the rows back in order 205 // which is a lot faster because you only do getInnerText once per row 206 var row_array = []; 207 var col = thiscell.sorttable_columnindex; 208 var rows = thiscell.sorttable_tbody.rows; 209 for( var j = sindex; j < rows.length; j++ ) { 210 row_array[row_array.length] = [sorttable.getInnerText( rows[j].cells[col] ), rows[j]]; 211 } 212 /* If you want a stable sort, uncomment the following line */ 213 //sorttable.shaker_sort(row_array, this.sorttable_sortfunction); 214 /* and comment out this one */ 215 row_array.sort( thiscell.sorttable_sortfunction ); 216 217 var tb = thiscell.sorttable_tbody; 218 for( var jj = 0; jj < row_array.length; jj++ ) { 219 tb.appendChild( row_array[jj][1] ); 220 } 221 222 //delete row_array; 223 // If reverse sort wanted, then doit 224 if ( revs ) { 225 // reverse the table, which is quicker 226 sorttable.reverse( thiscell.sorttable_tbody, sindex ); 227 thiscell.className = thiscell.className.replace( 'sorttable_sorted', 228 'sorttable_sorted_reverse' ); 229 thiscell.removeChild( document.getElementById( 'sorttable_sortfwdind' ) ); 230 sortrevind = document.createElement( 'span' ); 231 sortrevind.id = "sorttable_sortrevind"; 232 sortrevind.innerHTML = stIsIE ? ' <font face="webdings">5</font>' : ' ▴'; 233 thiscell.appendChild( sortrevind ); 234 } 235 }, 236 makeSortable: function ( table, overrides, bottoms, ph2 ) { 237// tableid++; 238 /* 239 if (table.getElementsByTagName('thead').length === 0) { 240 // table doesn't have a tHead. Since it should have, create one and 241 // put the first table row in it. 242 the = document.createElement('thead'); 243 the.appendChild(table.rows[0]); 244 table.insertBefore(the,table.firstChild); 245 } 246 */ 247 // Safari doesn't support table.tHead, sigh 248 /* 249 if (table.tHead === null) {table.tHead = table.getElementsByTagName('thead')[0];} 250 251 if (table.tHead.rows.length != 1) {return;} // can't cope with two header rows 252 */ 253// table.tHead.className += ' tableid'+tableid; 254 255 // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as 256 // "total" rows, for example). This is B&R, since what you're supposed 257 // to do is put them in a tfoot. So, if there are sortbottom rows, 258 // for backwards compatibility, move them to tfoot (creating it if needed). 259 260 var sortbottomrows = []; 261 if ( bottoms > 0 ) { 262 var frombottom = table.rows.length - bottoms; 263 for( var i = table.rows.length - 1; i >= frombottom; i-- ) { 264// if (bottoms<frombottom) { 265 sortbottomrows[sortbottomrows.length] = table.rows[i]; 266// } 267// frombottom++; 268 } 269 if ( sortbottomrows ) { 270 var tfo; 271 if ( table.tFoot === null ) { 272 // table doesn't have a tfoot. Create one. 273 tfo = document.createElement( 'tfoot' ); 274 table.appendChild( tfo ); 275 } 276 for( var ii = sortbottomrows.length - 1; ii >= 0; ii-- ) { 277 tfo.appendChild( sortbottomrows[ii] ); 278 } 279 //delete sortbottomrows; 280 } 281 } 282 // work through each column and calculate its type 283 var havetHead = table.tHead; 284 var sindex = 1; 285 if ( havetHead ) { 286 sindex = 0; 287 } 288 var headrow = table.rows[0].cells; 289// for (var i=0; i<headrow.length; i++) { 290 for( var i = 0; i < headrow.length; i++ ) { 291 // manually override the type with a sorttable_type attribute 292 var colOptions = ""; 293 if ( overrides[i + 1] ) 294 { 295 colOptions = overrides[i + 1]; 296 } 297 if ( !colOptions.match( /\bnosort\b/ ) ) { // skip this col 298 var mtch = colOptions.match( /\b[a-z0-9]+\b/ ); 299 var override; 300 if ( mtch ) { 301 override = mtch[0]; 302 } 303 if ( mtch && typeof sorttable["sort_" + override] === 'function' ) { 304 headrow[i].sorttable_sortfunction = sorttable["sort_" + override]; 305 } else { 306 headrow[i].sorttable_sortfunction = sorttable.guessType( table, i ); 307 } 308 /* 309 if (!headrow[i].className.match(/\bsorttable_nosort\b/)) { // skip this col 310 mtch = headrow[i].className.match(/\bsorttable_([a-z0-9]+)\b/); 311 if (mtch) { override = mtch[1]; } 312 if (mtch && typeof sorttable["sort_"+override] == 'function') { 313 headrow[i].sorttable_sortfunction = sorttable["sort_"+override]; 314 } else { 315 headrow[i].sorttable_sortfunction = sorttable.guessType(table,i); 316 } 317 */ 318 // make it clickable to sort 319 headrow[i].sorttable_columnindex = i; 320 headrow[i].sorttable_tbody = table.tBodies[0]; 321 headrow[i].sindex = sindex; 322// dean_addEvent(headrow[i],"click", function(e) { 323// addEvent(headrow[i],"click", function(e) { 324 jQuery( headrow[i] ).click( function () { 325 326 var theadrow = this.parentNode; 327 var sortrevind, sortfwdind; 328 if ( this.className.search( /\bsorttable_sorted\b/ ) !== -1 ) { 329 // if we're already sorted by this column, just 330 // reverse the table, which is quicker 331 sorttable.reverse( this.sorttable_tbody, this.sindex ); 332 this.className = this.className.replace( 'sorttable_sorted', 333 'sorttable_sorted_reverse' ); 334 sortfwdind = document.getElementById( 'sorttable_sortfwdind' ); 335 if ( sortfwdind ) { 336 sortfwdind.parentNode.removeChild( sortfwdind ); 337 } 338// this.removeChild(document.getElementById('sorttable_sortfwdind')); 339 sortrevind = document.getElementById( 'sorttable_sortrevind' ); 340 if ( sortrevind ) { 341 sortrevind.parentNode.removeChild( sortrevind ); 342 } 343 sortrevind = document.createElement( 'span' ); 344 sortrevind.id = "sorttable_sortrevind"; 345 sortrevind.innerHTML = stIsIE ? ' <font face="webdings">5</font>' : ' ▴'; 346 this.appendChild( sortrevind ); 347 return; 348 } 349 if ( this.className.search( /\bsorttable_sorted_reverse\b/ ) !== -1 ) { 350 if ( !ph2 ) { 351 sorttable.original_order( this.sorttable_tbody, this.sindex ); 352 var list = theadrow.childNodes; 353 for( var i = 0; i < list.length; i++ ) { 354 var cell = list[i]; 355 if ( cell.nodeType === 1 ) { // an element 356 cell.className = cell.className.replace( 'sorttable_sorted_reverse', '' ); 357 cell.className = cell.className.replace( 'sorttable_sorted', '' ); 358 } 359 } 360 sortfwdind = document.getElementById( 'sorttable_sortfwdind' ); 361 if ( sortfwdind ) { 362 sortfwdind.parentNode.removeChild( sortfwdind ); 363 } 364 sortrevind = document.getElementById( 'sorttable_sortrevind' ); 365 if ( sortrevind ) { 366 sortrevind.parentNode.removeChild( sortrevind ); 367 } 368 return; 369 } else { 370 // if we're already sorted by this column in reverse, just 371 // re-reverse the table, which is quicker 372 sorttable.reverse( this.sorttable_tbody, this.sindex ); 373 this.className = this.className.replace( 'sorttable_sorted_reverse', 374 'sorttable_sorted' ); 375 sortrevind = document.getElementById( 'sorttable_sortrevind' ); 376 if ( sortrevind ) { 377 sortrevind.parentNode.removeChild( sortrevind ); 378 } 379 // this.removeChild(document.getElementById('sorttable_sortrevind')); 380 sortfwdind = document.getElementById( 'sorttable_sortfwdind' ); 381 if ( sortfwdind ) { 382 sortfwdind.parentNode.removeChild( sortfwdind ); 383 } 384 sortfwdind = document.createElement( 'span' ); 385 sortfwdind.id = "sorttable_sortfwdind"; 386 sortfwdind.innerHTML = stIsIE ? ' <font face="webdings">6</font>' : ' ▾'; 387 this.appendChild( sortfwdind ); 388 return; 389 } 390 } 391 392 // remove sorttable_sorted classes 393// theadrow = this.parentNode; 394 var list = theadrow.childNodes; 395 for( var i = 0; i < list.length; i++ ) { 396 var cell = list[i]; 397 if ( cell.nodeType === 1 ) { // an element 398 cell.className = cell.className.replace( 'sorttable_sorted_reverse', '' ); 399 cell.className = cell.className.replace( 'sorttable_sorted', '' ); 400 } 401 } 402 sortfwdind = document.getElementById( 'sorttable_sortfwdind' ); 403 if ( sortfwdind ) { 404 sortfwdind.parentNode.removeChild( sortfwdind ); 405 } 406 sortrevind = document.getElementById( 'sorttable_sortrevind' ); 407 if ( sortrevind ) { 408 sortrevind.parentNode.removeChild( sortrevind ); 409 } 410 411 this.className += ' sorttable_sorted'; 412 sortfwdind = document.createElement( 'span' ); 413 sortfwdind.id = "sorttable_sortfwdind"; 414 sortfwdind.innerHTML = stIsIE ? ' <font face="webdings">6</font>' : ' ▾'; 415 this.appendChild( sortfwdind ); 416 417 // build an array to sort. This is a Schwartzian transform thing, 418 // i.e., we "decorate" each row with the actual sort key, 419 // sort based on the sort keys, and then put the rows back in order 420 // which is a lot faster because you only do getInnerText once per row 421 var row_array = []; 422 var col = this.sorttable_columnindex; 423 var rows = this.sorttable_tbody.rows; 424 sindex = this.sindex; 425 for( var j = sindex; j < rows.length; j++ ) { 426 row_array[row_array.length] = [sorttable.getInnerText( rows[j].cells[col] ), rows[j]]; 427 } 428 /* If you want a stable sort, uncomment the following line */ 429 //sorttable.shaker_sort(row_array, this.sorttable_sortfunction); 430 /* and comment out this one */ 431 row_array.sort( this.sorttable_sortfunction ); 432 433 var tb = this.sorttable_tbody; 434 for( var j3 = 0; j3 < row_array.length; j3++ ) { 435 tb.appendChild( row_array[j3][1] ); 436 } 437 438 //delete row_array; 439 } ); 440 } 441 } 442 }, 443 guessType: function ( table, column ) { 444 // guess the type of a column based on its first non-blank row 445 var textCnt = 0; 446 var numCnt = 0; 447 var ddmmCnt = 0; 448 var mmddCnt = 0; 449 var ipCnt = 0; 450 451 for( var i = 0; i < table.tBodies[0].rows.length; i++ ) { 452 var text = sorttable.getInnerText( table.tBodies[0].rows[i].cells[column] ); 453 if ( text !== "" ) { 454 if ( text.match( /^([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])$/ ) ) { // now for ip-addresses 455 ipCnt++; 456 } else if ( text.match( /^[\-\+]?[£$¤]?[\d,.]+[%€]?$/ ) ) { 457 numCnt++; 458 } else { 459 // check for a date: dd/mm/yyyy or dd/mm/yy 460 // can have / or . or - as separator 461 // can be mm/dd as well 462 var possdate = text.match( sorttable.DATE_RE ); 463 if ( possdate ) { 464 // looks like a date 465 var first = parseInt( possdate[1] ); 466 var second = parseInt( possdate[2] ); 467 if ( first > 12 ) { 468 // definitely dd/mm 469 ddmmCnt++; 470 } else if ( second > 12 ) { 471 mmddCnt++; 472 } else { 473 // looks like a date, but we can't tell which, so assume 474 // that it's dd/mm (English imperialism!) and keep looking 475 ddmmCnt++; 476 } 477 } else { // not a date (nor IP nor number) 478 textCnt++; 479 } 480 } 481 } 482 } 483 if ( textCnt > numCnt && textCnt > ipCnt && textCnt > ddmmCnt && textCnt > mmddCnt ) 484 return sorttable.sort_alpha; 485 if ( numCnt > ipCnt && numCnt > ddmmCnt && numCnt > mmddCnt ) 486 return sorttable.sort_numeric; 487 if ( ipCnt > ddmmCnt && ipCnt > mmddCnt ) 488 return sorttable.sort_ipaddr; 489 return ( ddmmCnt > mmddCnt ) ? sorttable.sort_ddmm : sorttable.sort_mmdd; 490 }, 491 getInnerText: function ( node ) { 492 // gets the text we want to use for sorting for a cell. 493 // strips leading and trailing whitespace. 494 // this is *not* a generic getInnerText function; it's special to sorttable. 495 // for example, you can override the cell text with a customkey attribute. 496 // it also gets .value for <input> fields. 497 if ( !node ) { 498 return ''; 499 } 500 var hasInputs = ( typeof node.getElementsByTagName === "function" ) && 501 node.getElementsByTagName( "input" ).length; 502 if ( node.getAttribute( "sorttable_customkey" ) !== null ) { 503 return node.getAttribute( "sorttable_customkey" ); 504 } else if ( typeof node.textContent !== "undefined" && !hasInputs ) { 505 return node.textContent.replace( /^\s+|\s+$/g, '' ); 506 } else if ( typeof node.innerText !== "undefined" && !hasInputs ) { 507 return node.innerText.replace( /^\s+|\s+$/g, '' ); 508 } else if ( typeof node.text !== "undefined" && !hasInputs ) { 509 return node.text.replace( /^\s+|\s+$/g, '' ); 510 } else { 511 switch ( node.nodeType ) { 512 case 3: 513 return ( node.nodeName.toLowerCase() === "input" ) ? node.value.replace( /^\s+|\s+$/g, '' ) : ''; 514 case 4: 515 return node.nodeValue.replace( /^\s+|\s+$/g, '' ); 516 case 1: 517 case 11: 518 var innerText = ''; 519 for( var i = 0; i < node.childNodes.length; i++ ) { 520 innerText += sorttable.getInnerText( node.childNodes[i] ); 521 } 522 return innerText.replace( /^\s+|\s+$/g, '' ); 523 default: 524 return ''; 525 } 526 } 527 }, 528 reverse: function ( tbody, sindex ) { 529 // reverse the rows in a tbody 530 var newrows = []; 531 for( var i = sindex; i < tbody.rows.length; i++ ) { 532 newrows[newrows.length] = tbody.rows[i]; 533 } 534 for( var i = newrows.length - 1; i >= 0; i-- ) { 535 tbody.appendChild( newrows[i] ); 536 } 537 //delete newrows; 538 }, 539 original_order: function ( tbody, isindex ) { 540 // build an array to sort. This is a Schwartzian transform thing, 541 // i.e., we "decorate" each row with the actual sort key, 542 // sort based on the sort keys, and then put the rows back in order 543 // which is a lot faster because you only do getInnerText once per row 544 var row_array = []; 545 var rows = tbody.rows; 546 var sindex = isindex; 547 for( var j = sindex; j < rows.length; j++ ) { 548 row_array[row_array.length] = [rows[j].className, rows[j]]; 549 } 550 /* If you want a stable sort, uncomment the following line */ 551 //sorttable.shaker_sort(row_array, this.sorttable_sortfunction); 552 /* and comment out this one */ 553 row_array.sort( sorttable.sort_alpha ); 554 555 var tb = tbody; 556 for( var j3 = 0; j3 < row_array.length; j3++ ) { 557 tb.appendChild( row_array[j3][1] ); 558 } 559 560 //delete row_array; 561 }, 562 /* sort functions 563 each sort function takes two parameters, a and b 564 you are comparing a[0] and b[0] */ 565 sort_ipaddr: function ( a, b ) { 566 var aa = a[0].split( ".", 4 ); 567 var bb = b[0].split( ".", 4 ); 568 var resulta = aa[0] * 0x1000000 + aa[1] * 0x10000 + aa[2] * 0x100 + aa[3] * 1; 569 var resultb = bb[0] * 0x1000000 + bb[1] * 0x10000 + bb[2] * 0x100 + bb[3] * 1; 570 return resulta - resultb; 571 }, 572 sort_numeric: function ( a, b ) { 573 if ( a[0] === "" ) { 574 return -1; 575 } 576 if ( b[0] === "" ) { 577 return 1; 578 } 579 var aa = parseFloat( a[0].replace( /[^0-9.\-]/g, '' ) ); 580 if ( isNaN( aa ) ) { 581 aa = Number.NEGATIVE_INFINITY; 582 } 583 var bb = parseFloat( b[0].replace( /[^0-9.\-]/g, '' ) ); 584 if ( isNaN( bb ) ) { 585 bb = Number.NEGATIVE_INFINITY; 586 } 587 return aa - bb; 588 }, 589 sort_alpha: function ( a, b ) { 590 return a[0].localeCompare( b[0] ); 591 }, 592 sort_ddmm: function ( a, b ) { 593 var mtch = a[0].match( sorttable.DATE_RE ); 594 var y = mtch[3]; 595 var m = mtch[2]; 596 var d = mtch[1]; 597 var t = mtch[5] + ''; 598 if ( t.length < 1 ) { 599 t = ''; 600 } 601 if ( m.length === 1 ) { 602 m = '0' + m; 603 } 604 if ( d.length === 1 ) { 605 d = '0' + d; 606 } 607 var dt1 = y + m + d + t; 608 mtch = b[0].match( sorttable.DATE_RE ); 609 y = mtch[3]; 610 m = mtch[2]; 611 d = mtch[1]; 612 t = mtch[5] + ''; 613 if ( t.length < 1 ) { 614 t = ''; 615 } 616 if ( m.length === 1 ) { 617 m = '0' + m; 618 } 619 if ( d.length === 1 ) { 620 d = '0' + d; 621 } 622 var dt2 = y + m + d + t; 623 if ( dt1 === dt2 ) { 624 return 0; 625 } 626 if ( dt1 < dt2 ) { 627 return -1; 628 } 629 return 1; 630 }, 631 sort_mmdd: function ( a, b ) { 632 var mtch = a[0].match( sorttable.DATE_RE ); 633 var y = mtch[3]; 634 var d = mtch[2]; 635 var m = mtch[1]; 636 var t = mtch[5] + ''; 637 if ( m.length === 1 ) { 638 m = '0' + m; 639 } 640 if ( d.length === 1 ) { 641 d = '0' + d; 642 } 643 var dt1 = y + m + d + t; 644 mtch = b[0].match( sorttable.DATE_RE ); 645 y = mtch[3]; 646 d = mtch[2]; 647 m = mtch[1]; 648 t = mtch[5] + ''; 649 if ( t.length < 1 ) { 650 t = ''; 651 } 652 if ( m.length === 1 ) { 653 m = '0' + m; 654 } 655 if ( d.length === 1 ) { 656 d = '0' + d; 657 } 658 var dt2 = y + m + d + t; 659 if ( dt1 === dt2 ) { 660 return 0; 661 } 662 if ( dt1 < dt2 ) { 663 return -1; 664 } 665 return 1; 666 }, 667 shaker_sort: function ( list, comp_func ) { 668 // A stable sort function to allow multi-level sorting of data 669 // see: http://en.wikipedia.org/wiki/Cocktail_sort 670 // thanks to Joseph Nahmias 671 var b = 0; 672 var t = list.length - 1; 673 var swap = true; 674 var q; 675 676 while( swap ) { 677 swap = false; 678 for( var i = b; i < t; ++i ) { 679 if ( comp_func( list[i], list[i + 1] ) > 0 ) { 680 q = list[i]; 681 list[i] = list[i + 1]; 682 list[i + 1] = q; 683 swap = true; 684 } 685 } // for 686 t--; 687 688 if ( !swap ) { 689 break; 690 } 691 692 for( var i = t; i > b; --i ) { 693 if ( comp_func( list[i], list[i - 1] ) < 0 ) { 694 q = list[i]; 695 list[i] = list[i - 1]; 696 list[i - 1] = q; 697 swap = true; 698 } 699 } // for 700 b++; 701 702 } // while(swap) 703 } 704 705 706}; 707 708if ( typeof ( window.addEvent ) !== "undefined" ) { 709 window.addEvent( window, "load", sorttable.init ); 710} else { 711 jQuery( function () { 712 sorttable.init(); 713 } ); 714} 715