1/** 2 Based on code from http://www.kryogenix.org/code/browser/sorttable/ by Stuart Langridge 3 (distributed under the conditions of MIT licence from http://www.kryogenix.org/code/browser/licence.html). 4 Includes open-source contributions from other people 5 (see https://github.com/FyiurAmron/sortablejs/graphs/contributors for more details). 6 Maintainers: 7 2007-2016 oiv (Otto Vainio at otto@valjakko.net) 8 2016-? vaxquis AKA FyiurAmron (spamove@gmail.com) 9 */ 10 11var stIsIE = /*@cc_on!@*/false; 12//var tableid = 0; 13 14var sorttable = { 15 reinit: function () { 16 arguments.callee.done = true; 17 18 if ( !document.createElement || !document.getElementsByTagName ) { 19 return; 20 } 21 22 var elems = document.getElementsByTagName( "table" ); 23 var elem; 24 for( var i = 0; i < elems.length; i++ ) { 25 elem = elems[i]; 26 if ( jQuery(elem).hasClass("sortable") ) { 27 sorttable.makeSortable( elem ); 28 } 29 } 30 elems = document.getElementsByTagName( "div" ); 31 for( var i = 0; i < elems.length; i++ ) { 32 elem = elems[i]; 33 if ( jQuery(elem).hasClass("sortable") ) { 34 sorttable.makeSortableDiv( elem ); 35 } 36 } 37 }, 38 init: function () { 39 if ( arguments.callee.done ) { 40 return; 41 } 42 sorttable.reinit(); 43 }, 44 makeSortableDiv: function ( div ) { 45 var childTables = div.getElementsByTagName( "table" ); 46 var elem; 47 for( var i = 0; i < childTables.length; i++ ) { 48 elem = childTables[i]; 49 var colid = div.className; 50 var patt1 = /\bcol_\d+_[a-z]+/gi; 51 var overs = []; 52 if ( colid.search( patt1 ) !== -1 ) { 53 var overrides = colid.match( patt1 ); 54 for( var i = 0; i < overrides.length; i++ ) { 55 var entry = overrides[i]; 56 if ( entry !== "" ) { 57 try { 58 var tmp = entry.split( "_" ); 59 var ind = tmp[1]; 60 var val = tmp[2]; 61 overs[ind] = val; 62 } catch( e ) { 63 } 64 } 65 } 66 colid = colid.replace( patt1, '' ); 67 } 68 var patt2 = /\bsortbottom_?\d?/gi; 69 var bottoms = 0; 70 if ( colid.search( patt2 ) !== -1 ) { 71 var bs = colid.match( patt2 ); 72 try { 73 var tmp = bs[0].split( "_" ); 74 //var ind = tmp[1]; 75 var val = 1; 76 if ( tmp.length > 1 ) { 77 val = tmp[1]; 78 } 79 bottoms = val; 80 } catch( e ) { 81 } 82 } 83 var patt2ph = /\bthreephase/gi; 84 var ph2 = true; 85 if ( colid.search( patt2ph ) !== -1 ) { 86 ph2 = false; 87 } 88 89 sorttable.makeSortable( elem, overs, bottoms, ph2 ); 90 var pattdefault = /\bsortr?\d\d?/gi; 91 if ( colid.search( pattdefault ) !== -1 ) { 92 var mi = colid.match( pattdefault ); 93 colid = mi[0].replace( 'sort', '' ); 94 if ( colid !== '' ) { 95 colid = colid.trim(); 96 } 97 var revs = false; 98 if ( colid.search( /\br/ ) !== -1 ) { 99 revs = true; 100 colid = colid.replace( 'r', '' ); 101 } 102 sorttable.defaultSort( elem, colid, revs ); 103 } 104 } 105 }, 106 defaultSort: function ( table, colid, revs ) { 107 var havetHead = table.tHead; 108 var sindex = 1; 109 if ( havetHead ) { 110 sindex = 0; 111 } 112 var theadrow = table.rows[0].cells; 113 colid--; 114 var colname = "col" + colid; 115 // remove sorttable_sorted classes 116 var thiscell = false; 117 for( var i = 0; i < theadrow.length; i++ ) { 118 var cell = theadrow[i]; 119 var colclass = cell.className; 120 var classname = colclass.split( " " ); 121 if ( classname[0] === colname ) { 122 thiscell = cell; 123 } 124 } 125 if ( thiscell === false ) { 126 return; 127 } 128 // build an array to sort. This is a Schwartzian transform thing, 129 // i.e., we "decorate" each row with the actual sort key, 130 // sort based on the sort keys, and then put the rows back in order 131 // which is a lot faster because you only do getInnerText once per row 132 var row_array = []; 133 var col = thiscell.sorttable_columnindex; 134 var rows = thiscell.sorttable_tbody.rows; 135 for( var j = sindex; j < rows.length; j++ ) { 136 row_array[row_array.length] = [sorttable.getInnerText( rows[j].cells[col] ), rows[j]]; 137 } 138 /* If you want a stable sort, uncomment the following line */ 139 //sorttable.shaker_sort(row_array, this.sorttable_sortfunction); 140 /* and comment out this one */ 141 row_array.sort( thiscell.sorttable_sortfunction ); 142 143 var tb = thiscell.sorttable_tbody; 144 for( var jj = 0; jj < row_array.length; jj++ ) { 145 tb.appendChild( row_array[jj][1] ); 146 } 147 148 if ( revs ) { 149 sorttable.reverse( thiscell.sorttable_tbody, sindex ); 150 jQuery(thiscell).addClass( "sorttable_sorted_reverse" ); 151 } else { 152 jQuery(thiscell).addClass( "sorttable_sorted" ); 153 } 154 }, 155 makeSortable: function ( table, overrides, bottoms, ph2 ) { 156 // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as 157 // "total" rows, for example). This is B&R, since what you're supposed 158 // to do is put them in a tfoot. So, if there are sortbottom rows, 159 // for backwards compatibility, move them to tfoot (creating it if needed). 160 161 var sortbottomrows = []; 162 if ( bottoms > 0 ) { 163 var frombottom = table.rows.length - bottoms; 164 for( var i = table.rows.length - 1; i >= frombottom; i-- ) { 165 sortbottomrows[sortbottomrows.length] = table.rows[i]; 166 } 167 if ( sortbottomrows ) { 168 var tfo; 169 if ( table.tFoot === null ) { 170 // table doesn't have a tfoot. Create one. 171 tfo = document.createElement( 'tfoot' ); 172 table.appendChild( tfo ); 173 } 174 for( var ii = sortbottomrows.length - 1; ii >= 0; ii-- ) { 175 tfo.appendChild( sortbottomrows[ii] ); 176 } 177 //delete sortbottomrows; 178 } 179 } 180 // work through each column and calculate its type 181 var havetHead = table.tHead; 182 var sindex = 1; 183 if ( havetHead ) { 184 sindex = 0; 185 } 186 var headrow = table.rows[0].cells; 187 188 for( var i = 0; i < headrow.length; i++ ) { 189 // manually override the type with a sorttable_type attribute 190 var colOptions = ""; 191 if ( overrides[i + 1] ) 192 { 193 colOptions = overrides[i + 1]; 194 } 195 if ( colOptions.match( /\bnosort\b/ ) ) { 196 jQuery(headrow[i]).addClass("sorttable_nosort"); 197 } else { // skip this col 198 var mtch = colOptions.match( /\b[a-z0-9]+\b/ ); 199 var override; 200 if ( mtch ) { 201 override = mtch[0]; 202 } 203 if ( mtch && typeof sorttable["sort_" + override] === 'function' ) { 204 headrow[i].sorttable_sortfunction = sorttable["sort_" + override]; 205 } else { 206 headrow[i].sorttable_sortfunction = sorttable.guessType( table, i ); 207 } 208 209 // make it clickable to sort 210 headrow[i].sorttable_columnindex = i; 211 headrow[i].sorttable_tbody = table.tBodies[0]; 212 headrow[i].sindex = sindex; 213 214 jQuery( headrow[i] ).click( function () { 215 var theadrow = this.parentNode; 216 var jqt = jQuery( this ); 217 if ( jqt.hasClass( "sorttable_sorted" ) ) { 218 // if we're already sorted by this column, just reverse the table 219 sorttable.reverse( this.sorttable_tbody, this.sindex ); 220 jqt.removeClass( "sorttable_sorted" ); 221 jqt.addClass( "sorttable_sorted_reverse" ); 222 return; 223 } 224 if ( jqt.hasClass( "sorttable_sorted_reverse" ) ) { 225 if ( !ph2 ) { 226 sorttable.original_order( this.sorttable_tbody, this.sindex ); 227 var list = theadrow.childNodes; 228 for( var i = 0; i < list.length; i++ ) { 229 var cell = list[i]; 230 if ( cell.nodeType === 1 ) { // an element 231 var cc = jQuery( cell ); 232 cc.removeClass( "sorttable_sorted" ); 233 cc.removeClass( "sorttable_sorted_reverse" ); 234 } 235 } 236 return; 237 } else { 238 // if we're already sorted by this column in reverse, just re-reverse the table 239 sorttable.reverse( this.sorttable_tbody, this.sindex ); 240 jqt.removeClass( "sorttable_sorted_reverse" ); 241 jqt.addClass( "sorttable_sorted" ); 242 return; 243 } 244 } 245 246 // remove sorttable_sorted classes 247 var list = theadrow.childNodes; 248 for( var i = 0; i < list.length; i++ ) { 249 var cell = list[i]; 250 if ( cell.nodeType === 1 ) { // an element 251 var cc = jQuery( cell ); 252 cc.removeClass( "sorttable_sorted" ); 253 cc.removeClass( "sorttable_sorted_reverse" ); 254 } 255 } 256 jqt.addClass( "sorttable_sorted" ); 257 258 // build an array to sort. This is a Schwartzian transform thing, 259 // i.e., we "decorate" each row with the actual sort key, 260 // sort based on the sort keys, and then put the rows back in order 261 // which is a lot faster because you only do getInnerText once per row 262 var row_array = []; 263 var col = this.sorttable_columnindex; 264 var rows = this.sorttable_tbody.rows; 265 sindex = this.sindex; 266 for( var j = sindex; j < rows.length; j++ ) { 267 row_array[row_array.length] = [sorttable.getInnerText( rows[j].cells[col] ), rows[j]]; 268 } 269 /* If you want a stable sort, uncomment the following line */ 270 //sorttable.shaker_sort(row_array, this.sorttable_sortfunction); 271 /* and comment out this one */ 272 row_array.sort( this.sorttable_sortfunction ); 273 274 var tb = this.sorttable_tbody; 275 for( var j3 = 0; j3 < row_array.length; j3++ ) { 276 tb.appendChild( row_array[j3][1] ); 277 } 278 279 //delete row_array; 280 } ); 281 } 282 } 283 }, 284 guessType: function ( table, column ) { 285 // guess the type of a column based on its first non-blank row 286 var textCnt = 0; 287 var numCnt = 0; 288 var dateCnt = 0; 289 var ipCnt = 0; 290 291 for( var i = 0; i < table.tBodies[0].rows.length; i++ ) { 292 var text = sorttable.getInnerText( table.tBodies[0].rows[i].cells[column] ); 293 if ( text !== "" ) { 294 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])$/ ) ) { 295 ipCnt++; 296 } else if ( text.match( /^[\-\+]?.?\d*[\d,.]?\d+.?$/ ) ) { 297 numCnt++; 298 } else if ( !isNaN( new Date( text ).getTime() ) ) { 299 dateCnt++; 300 } else { // not a date (nor IP nor number) 301 textCnt++; 302 } 303 } 304 } 305 if ( textCnt > numCnt && textCnt > ipCnt && textCnt > dateCnt ) 306 return sorttable.sort_alpha; 307 if ( numCnt > ipCnt && numCnt > dateCnt ) 308 return sorttable.sort_numeric; 309 if ( ipCnt > dateCnt ) 310 return sorttable.sort_ipaddr; 311 return sorttable.sort_date; 312 }, 313 getInnerText: function ( node ) { 314 // gets the text we want to use for sorting for a cell. 315 // strips leading and trailing whitespace. 316 // this is *not* a generic getInnerText function; it's special to sorttable. 317 // for example, you can override the cell text with a customkey attribute. 318 // it also gets .value for <input> fields. 319 if ( !node ) { 320 return ''; 321 } 322 var hasInputs = ( typeof node.getElementsByTagName === "function" ) && 323 node.getElementsByTagName( "input" ).length; 324 if ( node.getAttribute( "sorttable_customkey" ) !== null ) { 325 return node.getAttribute( "sorttable_customkey" ); 326 } else if ( typeof node.textContent !== "undefined" && !hasInputs ) { 327 return node.textContent.replace( /^\s+|\s+$/g, '' ); 328 } else if ( typeof node.innerText !== "undefined" && !hasInputs ) { 329 return node.innerText.replace( /^\s+|\s+$/g, '' ); 330 } else if ( typeof node.text !== "undefined" && !hasInputs ) { 331 return node.text.replace( /^\s+|\s+$/g, '' ); 332 } else { 333 switch ( node.nodeType ) { 334 case 3: 335 return ( node.nodeName.toLowerCase() === "input" ) ? node.value.replace( /^\s+|\s+$/g, '' ) : ''; 336 case 4: 337 return node.nodeValue.replace( /^\s+|\s+$/g, '' ); 338 case 1: 339 case 11: 340 var innerText = ''; 341 for( var i = 0; i < node.childNodes.length; i++ ) { 342 innerText += sorttable.getInnerText( node.childNodes[i] ); 343 } 344 return innerText.replace( /^\s+|\s+$/g, '' ); 345 default: 346 return ''; 347 } 348 } 349 }, 350 reverse: function ( tbody, sindex ) { 351 // reverse the rows in a tbody 352 var newrows = []; 353 for( var i = sindex; i < tbody.rows.length; i++ ) { 354 newrows[newrows.length] = tbody.rows[i]; 355 } 356 for( var i = newrows.length - 1; i >= 0; i-- ) { 357 tbody.appendChild( newrows[i] ); 358 } 359 //delete newrows; 360 }, 361 original_order: function ( tbody, isindex ) { 362 // build an array to sort. This is a Schwartzian transform thing, 363 // i.e., we "decorate" each row with the actual sort key, 364 // sort based on the sort keys, and then put the rows back in order 365 // which is a lot faster because you only do getInnerText once per row 366 var row_array = []; 367 var rows = tbody.rows; 368 var sindex = isindex; 369 for( var j = sindex; j < rows.length; j++ ) { 370 row_array[row_array.length] = [rows[j].className, rows[j]]; 371 } 372 /* If you want a stable sort, uncomment the following line */ 373 //sorttable.shaker_sort(row_array, this.sorttable_sortfunction); 374 /* and comment out this one */ 375 row_array.sort( sorttable.sort_alpha ); 376 377 var tb = tbody; 378 for( var j3 = 0; j3 < row_array.length; j3++ ) { 379 tb.appendChild( row_array[j3][1] ); 380 } 381 382 //delete row_array; 383 }, 384 /* sort functions 385 each sort function takes two parameters, a and b 386 you are comparing a[0] and b[0] */ 387 sort_ipaddr: function ( a, b ) { 388 var aa = a[0].split( ".", 4 ); 389 var bb = b[0].split( ".", 4 ); 390 var resulta = aa[0] * 0x1000000 + aa[1] * 0x10000 + aa[2] * 0x100 + aa[3] * 1; 391 var resultb = bb[0] * 0x1000000 + bb[1] * 0x10000 + bb[2] * 0x100 + bb[3] * 1; 392 return resulta - resultb; 393 }, 394 sort_numeric: function ( a, b ) { 395 if ( a[0] === "" ) { 396 return -1; 397 } 398 if ( b[0] === "" ) { 399 return 1; 400 } 401 var aa = parseFloat( a[0].replace( ",", "." ).replace( /[^0-9.\-]/g, "" ) ); 402 if ( isNaN( aa ) ) { 403 aa = Number.NEGATIVE_INFINITY; 404 } 405 var bb = parseFloat( b[0].replace( ",", "." ).replace( /[^0-9.\-]/g, "" ) ); 406 if ( isNaN( bb ) ) { 407 bb = Number.NEGATIVE_INFINITY; 408 } 409 return aa - bb; 410 }, 411 sort_alpha: function ( a, b ) { 412 return a[0].localeCompare( b[0] ); 413 }, 414 sort_date: function ( a, b ) { 415 var aa = new Date( a[0] ), bb = new Date( b[0] ); 416 return ( aa > bb ) - ( aa < bb ); 417 }, 418 shaker_sort: function ( list, comp_func ) { 419 // A stable sort function to allow multi-level sorting of data 420 // see: http://en.wikipedia.org/wiki/Cocktail_sort 421 // thanks to Joseph Nahmias 422 var b = 0; 423 var t = list.length - 1; 424 var swap = true; 425 var q; 426 427 while( swap ) { 428 swap = false; 429 for( var i = b; i < t; ++i ) { 430 if ( comp_func( list[i], list[i + 1] ) > 0 ) { 431 q = list[i]; 432 list[i] = list[i + 1]; 433 list[i + 1] = q; 434 swap = true; 435 } 436 } // for 437 t--; 438 439 if ( !swap ) { 440 break; 441 } 442 443 for( var i = t; i > b; --i ) { 444 if ( comp_func( list[i], list[i - 1] ) < 0 ) { 445 q = list[i]; 446 list[i] = list[i - 1]; 447 list[i - 1] = q; 448 swap = true; 449 } 450 } // for 451 b++; 452 453 } // while(swap) 454 } 455 456}; 457 458if ( typeof ( window.addEvent ) !== "undefined" ) { 459 window.addEvent( window, "load", sorttable.init ); 460} else { 461 jQuery( function () { 462 sorttable.init(); 463 } ); 464} 465