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