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