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