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