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 sortfn = sorttable.sort_alpha; 448 for (var i=0; i<table.tBodies[0].rows.length; i++) { 449 text = sorttable.getInnerText(table.tBodies[0].rows[i].cells[column]); 450 set=0; 451 if (text !== '') { 452 if (text.match(/^-?[£$¤]?[\d,.]+[%€]?$/)) { 453 set=1; 454 NUM=1; 455 } 456 // check for a date: dd/mm/yyyy or dd/mm/yy 457 // can have / or . or - as separator 458 // can be mm/dd as well 459 possdate = text.match(sorttable.DATE_RE); 460 if (possdate) { 461 // looks like a date 462 first = parseInt(possdate[1]); 463 second = parseInt(possdate[2]); 464 if (first > 12) { 465 // definitely dd/mm 466// return sorttable.sort_ddmm; 467 set=1; 468 DDMM=1; 469 } else if (second > 12) { 470 set=1; 471 MMDD=1; 472// return sorttable.sort_mmdd; 473 } else { 474 // looks like a date, but we can't tell which, so assume 475 // that it's dd/mm (English imperialism!) and keep looking 476 set=1; 477 DDMM=1; 478// sortfn = sorttable.sort_ddmm; 479 } 480 } 481 // if nothing known then assume text 482 if (set==0) { 483 TEXT=1; 484 } 485 set=0; 486 487 } 488 } 489 if (TEXT>0 || NUM+DDMM+MMDD>1) return sorttable.sort_alpha; 490 if (NUM>0) return sorttable.sort_numeric; 491 if (DDMM>0) return sorttable.sort_ddmm; 492 if (MMDD>0) return sorttable.sort_mmdd; 493 }, 494 495 getInnerText: function(node) { 496 // gets the text we want to use for sorting for a cell. 497 // strips leading and trailing whitespace. 498 // this is *not* a generic getInnerText function; it's special to sorttable. 499 // for example, you can override the cell text with a customkey attribute. 500 // it also gets .value for <input> fields. 501 502 hasInputs = (typeof node.getElementsByTagName == 'function') && 503 node.getElementsByTagName('input').length; 504 505 if (node.getAttribute("sorttable_customkey") !== null) { 506 return node.getAttribute("sorttable_customkey"); 507 } 508 else if (typeof node.textContent != 'undefined' && !hasInputs) { 509 return node.textContent.replace(/^\s+|\s+$/g, ''); 510 } 511 else if (typeof node.innerText != 'undefined' && !hasInputs) { 512 return node.innerText.replace(/^\s+|\s+$/g, ''); 513 } 514 else if (typeof node.text != 'undefined' && !hasInputs) { 515 return node.text.replace(/^\s+|\s+$/g, ''); 516 } 517 else { 518 switch (node.nodeType) { 519 case 3: 520 if (node.nodeName.toLowerCase() == 'input') { 521 return node.value.replace(/^\s+|\s+$/g, ''); 522 } 523 case 4: 524 return node.nodeValue.replace(/^\s+|\s+$/g, ''); 525 break; 526 case 1: 527 case 11: 528 var innerText = ''; 529 for (var i = 0; i < node.childNodes.length; i++) { 530 innerText += sorttable.getInnerText(node.childNodes[i]); 531 } 532 return innerText.replace(/^\s+|\s+$/g, ''); 533 break; 534 default: 535 return ''; 536 } 537 } 538 }, 539 540 reverse: function(tbody,sindex) { 541 // reverse the rows in a tbody 542 newrows = []; 543 for (var i=sindex; i<tbody.rows.length; i++) { 544 newrows[newrows.length] = tbody.rows[i]; 545 } 546 for (var i=newrows.length-1; i>=0; i--) { 547 tbody.appendChild(newrows[i]); 548 } 549 delete newrows; 550 }, 551 original_order: function(tbody,isindex) { 552 // build an array to sort. This is a Schwartzian transform thing, 553 // i.e., we "decorate" each row with the actual sort key, 554 // sort based on the sort keys, and then put the rows back in order 555 // which is a lot faster because you only do getInnerText once per row 556 row_array = []; 557 rows = tbody.rows; 558 sindex = isindex; 559 for (var j=sindex; j<rows.length; j++) { 560 row_array[row_array.length] = [rows[j].className, rows[j]]; 561 } 562 /* If you want a stable sort, uncomment the following line */ 563 //sorttable.shaker_sort(row_array, this.sorttable_sortfunction); 564 /* and comment out this one */ 565 row_array.sort(sorttable.sort_alpha); 566 567 tb = tbody; 568 for (var j3=0; j3<row_array.length; j3++) { 569 tb.appendChild(row_array[j3][1]); 570 } 571 572 delete row_array; 573 }, 574 575 /* sort functions 576 each sort function takes two parameters, a and b 577 you are comparing a[0] and b[0] */ 578 sort_numeric: function(a,b) { 579 aa = parseFloat(a[0].replace(/[^0-9.\-]/g,'')); 580 if (isNaN(aa)) {aa = 0;} 581 bb = parseFloat(b[0].replace(/[^0-9.\-]/g,'')); 582 if (isNaN(bb)) {bb = 0;} 583 return aa-bb; 584 }, 585 sort_alpha: function(a,b) { 586 if (a[0]==b[0]) {return 0;} 587 if (a[0]<b[0]) {return -1;} 588 return 1; 589 }, 590 sort_ddmm: function(a,b) { 591 mtch = a[0].match(sorttable.DATE_RE); 592 y = mtch[3]; m = mtch[2]; d = mtch[1]; 593 t = mtch[5]+''; 594 if (t.length < 1 ) {t = '';} 595 if (m.length == 1) {m = '0'+m;} 596 if (d.length == 1) {d = '0'+d;} 597 dt1 = y+m+d+t; 598 mtch = b[0].match(sorttable.DATE_RE); 599 y = mtch[3]; m = mtch[2]; d = mtch[1]; 600 t = mtch[5]+''; 601 if (t.length < 1 ) {t = '';} 602 if (m.length == 1) {m = '0'+m;} 603 if (d.length == 1) {d = '0'+d;} 604 dt2 = y+m+d+t; 605 if (dt1==dt2) {return 0;} 606 if (dt1<dt2) {return -1;} 607 return 1; 608 }, 609 sort_mmdd: function(a,b) { 610 mtch = a[0].match(sorttable.DATE_RE); 611 y = mtch[3]; d = mtch[2]; m = mtch[1]; 612 t = mtch[5]+''; 613 if (m.length == 1) {m = '0'+m;} 614 if (d.length == 1) {d = '0'+d;} 615 dt1 = y+m+d+t; 616 mtch = b[0].match(sorttable.DATE_RE); 617 y = mtch[3]; d = mtch[2]; m = mtch[1]; 618 t = mtch[5]+''; 619 if (t.length < 1 ) {t = '';} 620 if (m.length == 1) {m = '0'+m;} 621 if (d.length == 1) {d = '0'+d;} 622 dt2 = y+m+d+t; 623 if (dt1==dt2) {return 0;} 624 if (dt1<dt2) {return -1;} 625 return 1; 626 }, 627 628 shaker_sort: function(list, comp_func) { 629 // A stable sort function to allow multi-level sorting of data 630 // see: http://en.wikipedia.org/wiki/Cocktail_sort 631 // thanks to Joseph Nahmias 632 var b = 0; 633 var t = list.length - 1; 634 var swap = true; 635 636 while(swap) { 637 swap = false; 638 for(var i = b; i < t; ++i) { 639 if ( comp_func(list[i], list[i+1]) > 0 ) { 640 var q = list[i]; list[i] = list[i+1]; list[i+1] = q; 641 swap = true; 642 } 643 } // for 644 t--; 645 646 if (!swap) {break;} 647 648 for(var i = t; i > b; --i) { 649 if ( comp_func(list[i], list[i-1]) < 0 ) { 650 var q = list[i]; list[i] = list[i-1]; list[i-1] = q; 651 swap = true; 652 } 653 } // for 654 b++; 655 656 } // while(swap) 657 } 658 659 660}; 661/* ****************************************************************** 662 Supporting functions: bundled here to avoid depending on a library 663 ****************************************************************** */ 664 665 666 667// Dean Edwards/Matthias Miller/John Resig 668 669 670// Dean's forEach: http://dean.edwards.name/base/forEach.js 671/* 672 forEach, version 1.0 673 Copyright 2006, Dean Edwards 674 License: http://www.opensource.org/licenses/mit-license.php 675*/ 676 677// array-like enumeration 678if (!Array.forEach) { // mozilla already supports this 679 Array.forEach = function(array, block, context) { 680 for (var i = 0; i < array.length; i++) { 681 block.call(context, array[i], i, array); 682 } 683 }; 684} 685 686// generic enumeration 687Function.prototype.forEach = function(object, block, context) { 688 for (var key in object) { 689 if (typeof this.prototype[key] == "undefined") { 690 block.call(context, object[key], key, object); 691 } 692 } 693}; 694 695// character enumeration 696String.forEach = function(string, block, context) { 697 Array.forEach(string.split(""), function(chr, index) { 698 block.call(context, chr, index, string); 699 }); 700}; 701 702// globally resolve forEach enumeration 703var forEach = function(object, block, context) { 704 if (object) { 705 var resolve = Object; // default 706 if (object instanceof Function) { 707 // functions have a "length" property 708 resolve = Function; 709 } else if (object.forEach instanceof Function) { 710 // the object implements a custom forEach method so use that 711 object.forEach(block, context); 712 return; 713 } else if (typeof object == "string") { 714 // the object is a string 715 resolve = String; 716 } else if (typeof object.length == "number") { 717 // the object is array-like 718 resolve = Array; 719 } 720 resolve.forEach(object, block, context); 721 } 722}; 723 724 725if ('undefined' != typeof(window.addEvent)) { 726 window.addEvent(window, 'load', sorttable.init); 727} else { 728 jQuery(function() { 729 sorttable.init(); 730 }); 731} 732 733//sorttable.init; 734 735function reinitsort() { 736 sorttable.reinit(); 737} 738