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