xref: /plugin/sortablejs/script.js (revision 271b055c4c28ea702d9b85c80cd5f8aca1b9c7ee)
1/*
2 SortTable
3
4 Instructions:
5 Used from dokuwiki
6 Click on the headers to sort
7
8 Thanks to many, many people for contributions and suggestions.
9 Currently licensed as X11:
10 http://www.kryogenix.org/code/browser/licence.html
11
12 v2.1 (7th April 2007)
13 * originally by Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/
14
15 v2.1b (19 Feb 2008)
16 * first Otto Vainio (otto@valjakko.net) revision
17 * Fixed some jslint errors to support DokuWiki (http://www.splitbrain.org) js compression
18 * function reinitsort()
19 * sorttable.reinit
20
21 v2.2 (27.11.2008)
22 * Changed line 77 document.getElementsByTagName('table') to div.getElementsByTagName('table')
23 to allow multiple sortable tables in same page (Thanks to Hans Sampiemon)
24
25 v2.3 (14.1.2009)
26 * Added option for default sorting.
27 * Use dokuwiki event registration.
28
29 v2.4 (27.1.2009)
30 * Cleaned some jlint errors to make this workable, when css+js compress is set in dokuwiki
31
32 v2.5 (10.5.2011)
33 * Fixed problems with secionediting, footnotes and edittable
34
35 v2.6 (18.7.2013)
36 * Added support for jQuery and dokuwiki Weatherwax ->
37
38 v2.7 (28.5.2014)
39 * Fixed problem with first row not getting sorted
40
41 v2.8 (30.5.2014)
42 * Fixed problem with first row not getting sorted in default sort. Added option "sumrow" to prevent sum line sort.
43
44 v2.9 (13.8.2014)
45 * Fixed problem with header row being sorted in earlier versions of dokuwiki. Added option for sorting back to default
46
47 v2.11 (6.7.2015)
48 * Added ip address sort. (Thanks Chefkeks)
49
50 v2.12 (14.12.2015)
51 * PHP 7 compatibility and issue #8. Default sort for columns > 9
52
53 v2.13
54 * revision by Vaxquis; fixes some (most) of the current issues
55 */
56
57//
58
59var stIsIE = /*@cc_on!@*/false;
60//var tableid = 0;
61
62var sorttable = {
63    reinit: function () {
64        arguments.callee.done = true;
65        // kill the timer
66        //if (_timer) {clearInterval(_timer);}
67
68        if ( !document.createElement || !document.getElementsByTagName ) {
69            return;
70        }
71
72        var elems = document.getElementsByTagName( "table" );
73        var elem;
74        for( var i = 0; i < elems.length; i++ ) {
75            elem = elems[i];
76            if ( elem.className.search( /\bsortable\b/ ) !== -1 ) {
77                sorttable.makeSortable( elem );
78            }
79        }
80        elems = document.getElementsByTagName( "div" );
81        for( var i = 0; i < elems.length; i++ ) {
82            elem = elems[i];
83            if ( elem.className.search( /\bsortable\b/ ) !== -1 ) {
84                sorttable.makeSortableDiv( elem );
85            }
86        }
87    },
88    init: function () {
89        if ( arguments.callee.done ) {
90            return;
91        }
92        sorttable.reinit();
93    },
94    makeSortableDiv: function ( div ) {
95        var childTables = div.getElementsByTagName( "table" );
96        var elem;
97        for( var i = 0; i < childTables.length; i++ ) {
98            elem = childTables[i];
99            var colid = div.className;
100            var patt1 = /\bcol_\d_[a-z]+/gi;
101            var overs = [];
102            if ( colid.search( patt1 ) !== -1 ) {
103                var overrides = colid.match( patt1 );
104                for( var i = 0; i < overrides.length; i++ ) {
105                    var entry = overrides[i];
106                    if ( entry !== "" ) {
107                        try {
108                            var tmp = entry.split( "_" );
109                            var ind = tmp[1];
110                            var val = tmp[2];
111                            overs[ind] = val;
112                        } catch( e ) {
113                        }
114                    }
115                }
116                colid = colid.replace( patt1, '' );
117            }
118            var patt2 = /\bsortbottom_?\d?/gi;
119            var bottoms = 0;
120            if ( colid.search( patt2 ) !== -1 ) {
121                var bs = colid.match( patt2 );
122                try {
123                    var tmp = bs[0].split( "_" );
124                    //var ind = tmp[1];
125                    var val = 1;
126                    if ( tmp.length > 1 ) {
127                        val = tmp[1];
128                    }
129                    bottoms = val;
130                } catch( e ) {
131                }
132            }
133            var patt2ph = /\bthreephase/gi;
134            var ph2 = true;
135            if ( colid.search( patt2ph ) !== -1 ) {
136                ph2 = false;
137            }
138
139            sorttable.makeSortable( elem, overs, bottoms, ph2 );
140            var pattdefault = /\bsortr?\d\d?/gi;
141            if ( colid.search( pattdefault ) !== -1 ) {
142                var mi = colid.match( pattdefault );
143                colid = mi[0].replace( 'sort', '' );
144                if ( colid !== '' ) {
145                    colid = colid.trim();
146                }
147                var revs = false;
148                if ( colid.search( /\br/ ) !== -1 ) {
149                    revs = true;
150                    colid = colid.replace( 'r', '' );
151                }
152                sorttable.defaultSort( elem, colid, revs );
153            }
154        }
155    },
156    defaultSort: function ( table, colid, revs ) {
157//    theadrow = table.tHead.rows[0].cells;
158        var havetHead = table.tHead;
159        var sindex = 1;
160        if ( havetHead ) {
161            sindex = 0;
162        }
163        var theadrow = table.rows[0].cells;
164        colid--;
165        var colname = "col" + colid;
166        // remove sorttable_sorted classes
167        var thiscell = false;
168        for( var i = 0; i < theadrow.length; i++ ) {
169            var cell = theadrow[i];
170            var colclass = cell.className;
171            var classname = colclass.split( " " );
172//       if (cell.className==colname)
173            if ( classname[0] === colname ) {
174                thiscell = cell;
175            }
176//       if (cell.nodeType == 1) { // an element
177//         cell.className = cell.className.replace('sorttable_sorted_reverse','');
178//         cell.className = cell.className.replace('sorttable_sorted','');
179//       }
180        }
181        if ( thiscell === false ) {
182            return;
183        }
184        var sortfwdind = document.getElementById( 'sorttable_sortfwdind' );
185        if ( sortfwdind ) {
186            sortfwdind.parentNode.removeChild( sortfwdind );
187        }
188        var sortrevind = document.getElementById( 'sorttable_sortrevind' );
189        if ( sortrevind ) {
190            sortrevind.parentNode.removeChild( sortrevind );
191        }
192
193        thiscell.className += ' sorttable_sorted';
194        sortfwdind = document.createElement( 'span' );
195        sortfwdind.id = "sorttable_sortfwdind";
196        sortfwdind.innerHTML = stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25BE;';
197        thiscell.appendChild( sortfwdind );
198
199        // build an array to sort. This is a Schwartzian transform thing,
200        // i.e., we "decorate" each row with the actual sort key,
201        // sort based on the sort keys, and then put the rows back in order
202        // which is a lot faster because you only do getInnerText once per row
203        var row_array = [];
204        var col = thiscell.sorttable_columnindex;
205        var rows = thiscell.sorttable_tbody.rows;
206        for( var j = sindex; j < rows.length; j++ ) {
207            row_array[row_array.length] = [sorttable.getInnerText( rows[j].cells[col] ), rows[j]];
208        }
209        /* If you want a stable sort, uncomment the following line */
210        //sorttable.shaker_sort(row_array, this.sorttable_sortfunction);
211        /* and comment out this one */
212        row_array.sort( thiscell.sorttable_sortfunction );
213
214        var tb = thiscell.sorttable_tbody;
215        for( var jj = 0; jj < row_array.length; jj++ ) {
216            tb.appendChild( row_array[jj][1] );
217        }
218
219        //delete row_array;
220        // If reverse sort wanted, then doit
221        if ( revs ) {
222            // reverse the table, which is quicker
223            sorttable.reverse( thiscell.sorttable_tbody, sindex );
224            thiscell.className = thiscell.className.replace( 'sorttable_sorted',
225                    'sorttable_sorted_reverse' );
226            thiscell.removeChild( document.getElementById( 'sorttable_sortfwdind' ) );
227            sortrevind = document.createElement( 'span' );
228            sortrevind.id = "sorttable_sortrevind";
229            sortrevind.innerHTML = stIsIE ? '&nbsp<font face="webdings">5</font>' : '&nbsp;&#x25B4;';
230            thiscell.appendChild( sortrevind );
231        }
232    },
233    makeSortable: function ( table, overrides, bottoms, ph2 ) {
234//    tableid++;
235        /*
236         if (table.getElementsByTagName('thead').length === 0) {
237         // table doesn't have a tHead. Since it should have, create one and
238         // put the first table row in it.
239         the = document.createElement('thead');
240         the.appendChild(table.rows[0]);
241         table.insertBefore(the,table.firstChild);
242         }
243         */
244        // Safari doesn't support table.tHead, sigh
245        /*
246         if (table.tHead === null) {table.tHead = table.getElementsByTagName('thead')[0];}
247
248         if (table.tHead.rows.length != 1) {return;} // can't cope with two header rows
249         */
250//    table.tHead.className += ' tableid'+tableid;
251
252        // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as
253        // "total" rows, for example). This is B&R, since what you're supposed
254        // to do is put them in a tfoot. So, if there are sortbottom rows,
255        // for backwards compatibility, move them to tfoot (creating it if needed).
256
257        var sortbottomrows = [];
258        if ( bottoms > 0 ) {
259            var frombottom = table.rows.length - bottoms;
260            for( var i = table.rows.length - 1; i >= frombottom; i-- ) {
261//      if (bottoms<frombottom) {
262                sortbottomrows[sortbottomrows.length] = table.rows[i];
263//      }
264//      frombottom++;
265            }
266            if ( sortbottomrows ) {
267                var tfo;
268                if ( table.tFoot === null ) {
269                    // table doesn't have a tfoot. Create one.
270                    tfo = document.createElement( 'tfoot' );
271                    table.appendChild( tfo );
272                }
273                for( var ii = sortbottomrows.length - 1; ii >= 0; ii-- ) {
274                    tfo.appendChild( sortbottomrows[ii] );
275                }
276                //delete sortbottomrows;
277            }
278        }
279        // work through each column and calculate its type
280        var havetHead = table.tHead;
281        var sindex = 1;
282        if ( havetHead ) {
283            sindex = 0;
284        }
285        var headrow = table.rows[0].cells;
286//    for (var i=0; i<headrow.length; i++) {
287        for( var i = 0; i < headrow.length; i++ ) {
288            // manually override the type with a sorttable_type attribute
289            var colOptions = "";
290            if ( overrides[i + 1] )
291            {
292                colOptions = overrides[i + 1];
293            }
294            if ( !colOptions.match( /\bnosort\b/ ) ) { // skip this col
295                var mtch = colOptions.match( /\b[a-z0-9]+\b/ );
296                var override;
297                if ( mtch ) {
298                    override = mtch[0];
299                }
300                if ( mtch && typeof sorttable["sort_" + override] === 'function' ) {
301                    headrow[i].sorttable_sortfunction = sorttable["sort_" + override];
302                } else {
303                    headrow[i].sorttable_sortfunction = sorttable.guessType( table, i );
304                }
305                /*
306                 if (!headrow[i].className.match(/\bsorttable_nosort\b/)) { // skip this col
307                 mtch = headrow[i].className.match(/\bsorttable_([a-z0-9]+)\b/);
308                 if (mtch) { override = mtch[1]; }
309                 if (mtch && typeof sorttable["sort_"+override] == 'function') {
310                 headrow[i].sorttable_sortfunction = sorttable["sort_"+override];
311                 } else {
312                 headrow[i].sorttable_sortfunction = sorttable.guessType(table,i);
313                 }
314                 */
315                // make it clickable to sort
316                headrow[i].sorttable_columnindex = i;
317                headrow[i].sorttable_tbody = table.tBodies[0];
318                headrow[i].sindex = sindex;
319//        dean_addEvent(headrow[i],"click", function(e) {
320//        addEvent(headrow[i],"click", function(e) {
321                jQuery( headrow[i] ).click( function () {
322
323                    var theadrow = this.parentNode;
324                    var sortrevind, sortfwdind;
325                    if ( this.className.search( /\bsorttable_sorted\b/ ) !== -1 ) {
326                        // if we're already sorted by this column, just
327                        // reverse the table, which is quicker
328                        sorttable.reverse( this.sorttable_tbody, this.sindex );
329                        this.className = this.className.replace( 'sorttable_sorted',
330                                'sorttable_sorted_reverse' );
331                        sortfwdind = document.getElementById( 'sorttable_sortfwdind' );
332                        if ( sortfwdind ) {
333                            sortfwdind.parentNode.removeChild( sortfwdind );
334                        }
335//            this.removeChild(document.getElementById('sorttable_sortfwdind'));
336                        sortrevind = document.getElementById( 'sorttable_sortrevind' );
337                        if ( sortrevind ) {
338                            sortrevind.parentNode.removeChild( sortrevind );
339                        }
340                        sortrevind = document.createElement( 'span' );
341                        sortrevind.id = "sorttable_sortrevind";
342                        sortrevind.innerHTML = stIsIE ? '&nbsp<font face="webdings">5</font>' : '&nbsp;&#x25B4;';
343                        this.appendChild( sortrevind );
344                        return;
345                    }
346                    if ( this.className.search( /\bsorttable_sorted_reverse\b/ ) !== -1 ) {
347                        if ( !ph2 ) {
348                            sorttable.original_order( this.sorttable_tbody, this.sindex );
349                            var list = theadrow.childNodes;
350                            for( var i = 0; i < list.length; i++ ) {
351                                var cell = list[i];
352                                if ( cell.nodeType === 1 ) { // an element
353                                    cell.className = cell.className.replace( 'sorttable_sorted_reverse', '' );
354                                    cell.className = cell.className.replace( 'sorttable_sorted', '' );
355                                }
356                            }
357                            sortfwdind = document.getElementById( 'sorttable_sortfwdind' );
358                            if ( sortfwdind ) {
359                                sortfwdind.parentNode.removeChild( sortfwdind );
360                            }
361                            sortrevind = document.getElementById( 'sorttable_sortrevind' );
362                            if ( sortrevind ) {
363                                sortrevind.parentNode.removeChild( sortrevind );
364                            }
365                            return;
366                        } else {
367                            // if we're already sorted by this column in reverse, just
368                            // re-reverse the table, which is quicker
369                            sorttable.reverse( this.sorttable_tbody, this.sindex );
370                            this.className = this.className.replace( 'sorttable_sorted_reverse',
371                                    'sorttable_sorted' );
372                            sortrevind = document.getElementById( 'sorttable_sortrevind' );
373                            if ( sortrevind ) {
374                                sortrevind.parentNode.removeChild( sortrevind );
375                            }
376                            //            this.removeChild(document.getElementById('sorttable_sortrevind'));
377                            sortfwdind = document.getElementById( 'sorttable_sortfwdind' );
378                            if ( sortfwdind ) {
379                                sortfwdind.parentNode.removeChild( sortfwdind );
380                            }
381                            sortfwdind = document.createElement( 'span' );
382                            sortfwdind.id = "sorttable_sortfwdind";
383                            sortfwdind.innerHTML = stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25BE;';
384                            this.appendChild( sortfwdind );
385                            return;
386                        }
387                    }
388
389                    // remove sorttable_sorted classes
390//          theadrow = this.parentNode;
391                    var list = theadrow.childNodes;
392                    for( var i = 0; i < list.length; i++ ) {
393                        var cell = list[i];
394                        if ( cell.nodeType === 1 ) { // an element
395                            cell.className = cell.className.replace( 'sorttable_sorted_reverse', '' );
396                            cell.className = cell.className.replace( 'sorttable_sorted', '' );
397                        }
398                    }
399                    sortfwdind = document.getElementById( 'sorttable_sortfwdind' );
400                    if ( sortfwdind ) {
401                        sortfwdind.parentNode.removeChild( sortfwdind );
402                    }
403                    sortrevind = document.getElementById( 'sorttable_sortrevind' );
404                    if ( sortrevind ) {
405                        sortrevind.parentNode.removeChild( sortrevind );
406                    }
407
408                    this.className += ' sorttable_sorted';
409                    sortfwdind = document.createElement( 'span' );
410                    sortfwdind.id = "sorttable_sortfwdind";
411                    sortfwdind.innerHTML = stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25BE;';
412                    this.appendChild( sortfwdind );
413
414                    // build an array to sort. This is a Schwartzian transform thing,
415                    // i.e., we "decorate" each row with the actual sort key,
416                    // sort based on the sort keys, and then put the rows back in order
417                    // which is a lot faster because you only do getInnerText once per row
418                    var row_array = [];
419                    var col = this.sorttable_columnindex;
420                    var rows = this.sorttable_tbody.rows;
421                    sindex = this.sindex;
422                    for( var j = sindex; j < rows.length; j++ ) {
423                        row_array[row_array.length] = [sorttable.getInnerText( rows[j].cells[col] ), rows[j]];
424                    }
425                    /* If you want a stable sort, uncomment the following line */
426                    //sorttable.shaker_sort(row_array, this.sorttable_sortfunction);
427                    /* and comment out this one */
428                    row_array.sort( this.sorttable_sortfunction );
429
430                    var tb = this.sorttable_tbody;
431                    for( var j3 = 0; j3 < row_array.length; j3++ ) {
432                        tb.appendChild( row_array[j3][1] );
433                    }
434
435                    //delete row_array;
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 textCnt = 0;
443        var numCnt = 0;
444        var dateCnt = 0;
445        var ipCnt = 0;
446
447        for( var i = 0; i < table.tBodies[0].rows.length; i++ ) {
448            var text = sorttable.getInnerText( table.tBodies[0].rows[i].cells[column] );
449            if ( text !== "" ) {
450                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])$/ ) ) {
451                    ipCnt++;
452                } else if ( text.match( /^[\-\+]?.?\d*[\d,.]?\d+.?$/ ) ) {
453                    numCnt++;
454                } else if ( !isNaN( new Date( text ).getTime() ) ) {
455                    dateCnt++;
456                } else { // not a date (nor IP nor number)
457                    textCnt++;
458                }
459            }
460        }
461        if ( textCnt > numCnt && textCnt > ipCnt && textCnt > dateCnt )
462            return sorttable.sort_alpha;
463        if ( numCnt > ipCnt && numCnt > dateCnt )
464            return sorttable.sort_numeric;
465        if ( ipCnt > dateCnt )
466            return sorttable.sort_ipaddr;
467        return sorttable.sort_date;
468    },
469    getInnerText: function ( node ) {
470        // gets the text we want to use for sorting for a cell.
471        // strips leading and trailing whitespace.
472        // this is *not* a generic getInnerText function; it's special to sorttable.
473        // for example, you can override the cell text with a customkey attribute.
474        // it also gets .value for <input> fields.
475        if ( !node ) {
476            return '';
477        }
478        var hasInputs = ( typeof node.getElementsByTagName === "function" ) &&
479                node.getElementsByTagName( "input" ).length;
480        if ( node.getAttribute( "sorttable_customkey" ) !== null ) {
481            return node.getAttribute( "sorttable_customkey" );
482        } else if ( typeof node.textContent !== "undefined" && !hasInputs ) {
483            return node.textContent.replace( /^\s+|\s+$/g, '' );
484        } else if ( typeof node.innerText !== "undefined" && !hasInputs ) {
485            return node.innerText.replace( /^\s+|\s+$/g, '' );
486        } else if ( typeof node.text !== "undefined" && !hasInputs ) {
487            return node.text.replace( /^\s+|\s+$/g, '' );
488        } else {
489            switch ( node.nodeType ) {
490                case 3:
491                    return ( node.nodeName.toLowerCase() === "input" ) ? node.value.replace( /^\s+|\s+$/g, '' ) : '';
492                case 4:
493                    return node.nodeValue.replace( /^\s+|\s+$/g, '' );
494                case 1:
495                case 11:
496                    var innerText = '';
497                    for( var i = 0; i < node.childNodes.length; i++ ) {
498                        innerText += sorttable.getInnerText( node.childNodes[i] );
499                    }
500                    return innerText.replace( /^\s+|\s+$/g, '' );
501                default:
502                    return '';
503            }
504        }
505    },
506    reverse: function ( tbody, sindex ) {
507        // reverse the rows in a tbody
508        var newrows = [];
509        for( var i = sindex; i < tbody.rows.length; i++ ) {
510            newrows[newrows.length] = tbody.rows[i];
511        }
512        for( var i = newrows.length - 1; i >= 0; i-- ) {
513            tbody.appendChild( newrows[i] );
514        }
515        //delete newrows;
516    },
517    original_order: function ( tbody, isindex ) {
518        // build an array to sort. This is a Schwartzian transform thing,
519        // i.e., we "decorate" each row with the actual sort key,
520        // sort based on the sort keys, and then put the rows back in order
521        // which is a lot faster because you only do getInnerText once per row
522        var row_array = [];
523        var rows = tbody.rows;
524        var sindex = isindex;
525        for( var j = sindex; j < rows.length; j++ ) {
526            row_array[row_array.length] = [rows[j].className, rows[j]];
527        }
528        /* If you want a stable sort, uncomment the following line */
529        //sorttable.shaker_sort(row_array, this.sorttable_sortfunction);
530        /* and comment out this one */
531        row_array.sort( sorttable.sort_alpha );
532
533        var tb = tbody;
534        for( var j3 = 0; j3 < row_array.length; j3++ ) {
535            tb.appendChild( row_array[j3][1] );
536        }
537
538        //delete row_array;
539    },
540    /* sort functions
541     each sort function takes two parameters, a and b
542     you are comparing a[0] and b[0] */
543    sort_ipaddr: function ( a, b ) {
544        var aa = a[0].split( ".", 4 );
545        var bb = b[0].split( ".", 4 );
546        var resulta = aa[0] * 0x1000000 + aa[1] * 0x10000 + aa[2] * 0x100 + aa[3] * 1;
547        var resultb = bb[0] * 0x1000000 + bb[1] * 0x10000 + bb[2] * 0x100 + bb[3] * 1;
548        return resulta - resultb;
549    },
550    sort_numeric: function ( a, b ) {
551        if ( a[0] === "" ) {
552            return -1;
553        }
554        if ( b[0] === "" ) {
555            return 1;
556        }
557        var aa = parseFloat( a[0].replace( ",", "." ).replace( /[^0-9.\-]/g, "" ) );
558        if ( isNaN( aa ) ) {
559            aa = Number.NEGATIVE_INFINITY;
560        }
561        var bb = parseFloat( b[0].replace( ",", "." ).replace( /[^0-9.\-]/g, "" ) );
562        if ( isNaN( bb ) ) {
563            bb = Number.NEGATIVE_INFINITY;
564        }
565        return aa - bb;
566    },
567    sort_alpha: function ( a, b ) {
568        return a[0].localeCompare( b[0] );
569    },
570    sort_date: function ( a, b ) {
571        var aa = new Date( a[0] ), bb = new Date( b[0] );
572        return ( aa > bb ) - ( aa < bb );
573    },
574    shaker_sort: function ( list, comp_func ) {
575        // A stable sort function to allow multi-level sorting of data
576        // see: http://en.wikipedia.org/wiki/Cocktail_sort
577        // thanks to Joseph Nahmias
578        var b = 0;
579        var t = list.length - 1;
580        var swap = true;
581        var q;
582
583        while( swap ) {
584            swap = false;
585            for( var i = b; i < t; ++i ) {
586                if ( comp_func( list[i], list[i + 1] ) > 0 ) {
587                    q = list[i];
588                    list[i] = list[i + 1];
589                    list[i + 1] = q;
590                    swap = true;
591                }
592            } // for
593            t--;
594
595            if ( !swap ) {
596                break;
597            }
598
599            for( var i = t; i > b; --i ) {
600                if ( comp_func( list[i], list[i - 1] ) < 0 ) {
601                    q = list[i];
602                    list[i] = list[i - 1];
603                    list[i - 1] = q;
604                    swap = true;
605                }
606            } // for
607            b++;
608
609        } // while(swap)
610    }
611
612};
613
614if ( typeof ( window.addEvent ) !== "undefined" ) {
615    window.addEvent( window, "load", sorttable.init );
616} else {
617    jQuery( function () {
618        sorttable.init();
619    } );
620}
621