dos2unix
[plewww.git] / plekit / tablesort / tablesort.js
index 27e8c3c..9b55e59 100644 (file)
-/*\r
-        TableSort revisited v5.0 by frequency-decoder.com\r
-\r
-        Released under a creative commons Attribution-ShareAlike 2.5 license (http://creativecommons.org/licenses/by-sa/2.5/)\r
-\r
-        Please credit frequency decoder in any derivative work - thanks\r
-\r
-        You are free:\r
-\r
-        * to copy, distribute, display, and perform the work\r
-        * to make derivative works\r
-        * to make commercial use of the work\r
-\r
-        Under the following conditions:\r
-\r
-                by Attribution.\r
-                --------------\r
-                You must attribute the work in the manner specified by the author or licensor.\r
-\r
-                sa\r
-                --\r
-                Share Alike. If you alter, transform, or build upon this work, you may distribute the resulting work only under a license identical to this one.\r
-\r
-        * For any reuse or distribution, you must make clear to others the license terms of this work.\r
-        * Any of these conditions can be waived if you get permission from the copyright holder.\r
-*/\r
-\r
-(function() {\r
-fdTableSort = {\r
-        regExp_Currency:        /^[£$€¥¤]/,\r
-        regExp_Number:          /^(\-)?[0-9]+(\.[0-9]*)?$/,\r
-        pos:                    -1,\r
-        uniqueHash:             1,\r
-        thNode:                 null,\r
-        tableId:                null,\r
-        tableCache:             {},\r
-        tmpCache:               {},\r
-        sortActiveClass:        "sort-active",\r
-        /*@cc_on\r
-        /*@if (@_win32)\r
-        colspan:                "colSpan",\r
-        rowspan:                "rowSpan",\r
-        @else @*/\r
-        colspan:                "colspan",\r
-        rowspan:                "rowspan",\r
-        /*@end\r
-        @*/\r
-        \r
-        addEvent: function(obj, type, fn, tmp) {\r
-                tmp || (tmp = true);\r
-                if( obj.attachEvent ) {\r
-                        obj["e"+type+fn] = fn;\r
-                        obj[type+fn] = function(){obj["e"+type+fn]( window.event );};\r
-                        obj.attachEvent( "on"+type, obj[type+fn] );\r
-                } else {\r
-                        obj.addEventListener( type, fn, true );\r
-                };\r
-        },\r
-        removeEvent: function(obj, type, fn, tmp) {\r
-                tmp || (tmp = true);\r
-                try {\r
-                        if( obj.detachEvent ) {\r
-                                obj.detachEvent( "on"+type, obj[type+fn] );\r
-                                obj[type+fn] = null;\r
-                        } else {\r
-                                obj.removeEventListener( type, fn, true );\r
-                        };\r
-                } catch(err) {};\r
-        },\r
-        stopEvent: function(e) {\r
-                e = e || window.event;\r
-\r
-                if(e.stopPropagation) {\r
-                        e.stopPropagation();\r
-                        e.preventDefault();\r
-                };\r
-                \r
-                /*@cc_on@*/\r
-                /*@if(@_win32)\r
-                e.cancelBubble = true;\r
-                e.returnValue  = false;\r
-                /*@end@*/\r
-                return false;\r
-        },\r
-        parseClassName: function(head, tbl) {\r
-                var colMatch = tbl.className.match(new RegExp(head + "((-[\\d]+([r]){0,1})+)"));\r
-                return colMatch && colMatch.length ? colMatch[0].replace(head, "").split("-") : [];\r
-        },\r
-        disableSelection: function(element) {\r
-                element.onselectstart = function() {\r
-                        return false;\r
-                };\r
-                element.unselectable = "on";\r
-                element.style.MozUserSelect = "none";\r
-        },\r
-        removeTableCache: function(tableId) {\r
-                if(!(tableId in fdTableSort.tableCache)) return;\r
-\r
-                fdTableSort.tableCache[tableId] = null;\r
-                delete fdTableSort.tableCache[tableId];\r
-\r
-                var tbl = document.getElementById(tableId);\r
-                if(!tbl) return;\r
-                var ths = tbl.getElementsByTagName("th");\r
-                var a;\r
-                for(var i = 0, th; th = ths[i]; i++) {\r
-                        a = th.getElementsByTagName("a");\r
-                        if(a.length) a[0].onkeydown = a[0].onclick = null;\r
-                        th.onclick = th.onselectstart = th = a = null;\r
-                };\r
-        },\r
-        removeTmpCache: function(tableId) {\r
-                if(!(tableId in fdTableSort.tmpCache)) return;\r
-                var headers = fdTableSort.tmpCache[tableId].headers;\r
-                var a;\r
-                for(var i = 0, row; row = headers[i]; i++) {\r
-                        for(var j = 0, th; th = row[j]; j++) {\r
-                                a = th.getElementsByTagName("a");\r
-                                if(a.length) a[0].onkeydown = a[0].onclick = null;\r
-                                th.onclick = th.onselectstart = th = a = null;\r
-                        };\r
-                };\r
-                fdTableSort.tmpCache[tableId] = null;\r
-                delete fdTableSort.tmpCache[tableId];\r
-        },\r
-        initEvt: function(e) {\r
-                fdTableSort.init(false);\r
-        },\r
-        init: function(tableId) {\r
-                if (!document.getElementsByTagName || !document.createElement || !document.getElementById) return;\r
-\r
-                var tables = tableId && document.getElementById(tableId) ? [document.getElementById(tableId)] : document.getElementsByTagName("table");\r
-                var c, ii, len, colMatch, showOnly, match, showArrow, columnNumSortObj, obj, workArr, headers, thtext, aclone, multi, colCnt, cel, allRowArr, rowArr, sortableTable, celCount, colspan, rowspan, rowLength;\r
-\r
-                var a          = document.createElement("a");\r
-                a.href         = "#";\r
-                a.className    = "fdTableSortTrigger";\r
-\r
-                var span       = document.createElement("span");\r
-\r
-                for(var k = 0, tbl; tbl = tables[k]; k++) {\r
-\r
-                        if(tbl.id) {\r
-                                fdTableSort.removeTableCache(tbl.id);\r
-                                fdTableSort.removeTmpCache(tbl.id);\r
-                        };\r
-\r
-                        allRowArr     = tbl.getElementsByTagName('thead').length ? tbl.getElementsByTagName('thead')[0].getElementsByTagName('tr') : tbl.getElementsByTagName('tr');\r
-                        rowArr        = [];\r
-                        sortableTable = false;\r
-\r
-                        for(var i = 0, tr; tr = allRowArr[i]; i++) {\r
-                                if(tr.getElementsByTagName('td').length || !tr.getElementsByTagName('th').length) { continue; };\r
-                                rowArr[rowArr.length] = tr.getElementsByTagName('th');\r
-                                for(var j = 0, th; th = rowArr[rowArr.length - 1][j]; j++) {\r
-                                        if(th.className.search(/sortable/) != -1) { sortableTable = true; };\r
-                                };\r
-                        };\r
-\r
-                        if(!sortableTable) continue;\r
-\r
-                        if(!tbl.id) { tbl.id = "fd-table-" + fdTableSort.uniqueHash++; };\r
-\r
-                        showArrow   = tbl.className.search("no-arrow") == -1;\r
-                        showOnly    = tbl.className.search("sortable-onload-show") != -1;\r
-\r
-                        columnNumSortObj = {};\r
-                        colMatch         = fdTableSort.parseClassName(showOnly ? "sortable-onload-show" : "sortable-onload", tbl);\r
-                        for(match = 1; match < colMatch.length; match++) {\r
-                                columnNumSortObj[parseInt(colMatch[match], 10)] = { "reverse":colMatch[match].search("r") != -1 };\r
-                        };\r
-\r
-                        rowLength = rowArr[0].length;\r
-\r
-                        for(c = 0;c < rowArr[0].length;c++){\r
-                                if(rowArr[0][c].getAttribute(fdTableSort.colspan) && rowArr[0][c].getAttribute(fdTableSort.colspan) > 1){\r
-                                        rowLength = rowLength + (rowArr[0][c].getAttribute(fdTableSort.colspan) - 1);\r
-                                };\r
-                        };\r
-\r
-                        workArr = new Array(rowArr.length);\r
-                        for(c = rowArr.length;c--;){ workArr[c]= new Array(rowLength); };\r
-\r
-                        for(c = 0;c < workArr.length;c++){\r
-                                celCount = 0;\r
-                                for(i = 0;i < rowLength;i++){\r
-                                        if(!workArr[c][i]){\r
-                                                cel = rowArr[c][celCount];\r
-                                                colspan = (cel.getAttribute(fdTableSort.colspan) > 1) ? cel.getAttribute(fdTableSort.colspan):1;\r
-                                                rowspan = (cel.getAttribute(fdTableSort.rowspan) > 1) ? cel.getAttribute(fdTableSort.rowspan):1;\r
-                                                for(var t = 0;((t < colspan)&&((i+t) < rowLength));t++){\r
-                                                        for(var n = 0;((n < rowspan)&&((c+n) < workArr.length));n++) {\r
-                                                                workArr[(c+n)][(i+t)] = cel;\r
-                                                        };\r
-                                                };\r
-                                                if(++celCount == rowArr[c].length) break;\r
-                                        };\r
-                                };\r
-                        };\r
-\r
-                        for(c = 0;c < workArr.length;c++) {\r
-                                for(i = 0;i < workArr[c].length;i++){\r
-\r
-                                        if(workArr[c][i].className.search("fd-column-") == -1 && workArr[c][i].className.search("sortable") != -1) workArr[c][i].className = workArr[c][i].className + " fd-column-" + i;\r
-\r
-                                        if(workArr[c][i].className.match('sortable')) {\r
-                                                workArr[c][i].className = workArr[c][i].className.replace(/forwardSort|reverseSort/, "");\r
-\r
-                                                if(i in columnNumSortObj) {\r
-                                                        columnNumSortObj[i]["thNode"] = workArr[c][i];\r
-                                                        columnNumSortObj["active"] = true;\r
-                                                };\r
-\r
-                                                thtext = fdTableSort.getInnerText(workArr[c][i], true);\r
-                                                \r
-                                                for(var cn = workArr[c][i].childNodes.length; cn--;) {\r
-                                                        // Skip image nodes and links created by the filter script.\r
-                                                        if(workArr[c][i].childNodes[cn].nodeType == 1 && (workArr[c][i].childNodes[cn].className == "fdFilterTrigger" || /img/i.test(workArr[c][i].childNodes[cn].nodeName))) {\r
-                                                                continue;\r
-                                                        };\r
-                                                        if(workArr[c][i].childNodes[cn].nodeType == 1 && /^a$/i.test(workArr[c][i].childNodes[cn].nodeName)) {\r
-                                                                workArr[c][i].childNodes[cn].onclick = workArr[c][i].childNodes[cn].onkeydown = null;\r
-                                                        };\r
-                                                        workArr[c][i].removeChild(workArr[c][i].childNodes[cn]);\r
-                                                };\r
-\r
-                                                aclone = a.cloneNode(true);\r
-                                                //aclone.appendChild(document.createTextNode(thtext));\r
-                                                aclone.innerHTML = thtext;\r
-                                                aclone.title = "Sort on \u201c" + thtext.replace('<br />', '') + "\u201d";\r
-                                                aclone.onclick = aclone.onkeydown = workArr[c][i].onclick = fdTableSort.initWrapper;\r
-                                                workArr[c][i].appendChild(aclone);\r
-                                                if(showArrow) workArr[c][i].appendChild(span.cloneNode(false));\r
-                                                workArr[c][i].className = workArr[c][i].className.replace(/fd-identical|fd-not-identical/, "");\r
-                                                fdTableSort.disableSelection(workArr[c][i]);\r
-                                                aclone = null;\r
-                                        };\r
-                                };\r
-                        };\r
-\r
-                        fdTableSort.tmpCache[tbl.id] = {cols:rowLength, headers:workArr};\r
-\r
-                        workArr = null;\r
-                        multi   = 0;\r
-\r
-                        if("active" in columnNumSortObj) {\r
-                                fdTableSort.tableId = tbl.id;\r
-                                fdTableSort.prepareTableData(document.getElementById(fdTableSort.tableId));\r
-\r
-                                delete columnNumSortObj["active"];\r
-\r
-                                for(col in columnNumSortObj) {\r
-                                        obj = columnNumSortObj[col];\r
-                                        if(!("thNode" in obj)) { continue; };\r
-                                        fdTableSort.multi = true;\r
-\r
-                                        len = obj.reverse ? 2 : 1;\r
-\r
-                                        for(ii = 0; ii < len; ii++) {\r
-                                                fdTableSort.thNode = obj.thNode;\r
-                                                if(!showOnly) {\r
-                                                        fdTableSort.initSort(false, true);\r
-                                                } else {\r
-                                                        fdTableSort.addThNode();\r
-                                                };\r
-                                        };\r
-\r
-                                        if(showOnly) {\r
-                                                fdTableSort.removeClass(obj.thNode, "(forwardSort|reverseSort)");\r
-                                                fdTableSort.addClass(obj.thNode, obj.reverse ? "reverseSort" : "forwardSort");\r
-                                                if(showArrow) {\r
-                                                        span = fdTableSort.thNode.getElementsByTagName('span')[0];\r
-                                                        if(span.firstChild) { span.removeChild(span.firstChild); };\r
-                                                        span.appendChild(document.createTextNode(len == 1 ? " \u2193" : " \u2191"));\r
-                                                };\r
-                                        };\r
-                                };\r
-                                if(showOnly && (fdTableSort.tableCache[tbl.id].colStyle || fdTableSort.tableCache[tbl.id].rowStyle)) {\r
-                                        fdTableSort.redraw(tbl.id, false);\r
-                                };\r
-                        } else if(tbl.className.search(/onload-zebra/) != -1) {\r
-                                fdTableSort.tableId = tbl.id;\r
-                                fdTableSort.prepareTableData(tbl);\r
-                                if(fdTableSort.tableCache[tbl.id].rowStyle) { fdTableSort.redraw(tbl.id, false); };\r
-                        };\r
-                };\r
-\r
-                fdTableSort.thNode = aclone = a = span = columnNumSortObj = thNode = tbl = allRowArr = rowArr = null;\r
-        },\r
-        initWrapper: function(e) {\r
-                e = e || window.event;\r
-                var kc = e.type == "keydown" ? e.keyCode != null ? e.keyCode : e.charCode : -1;\r
-                if(fdTableSort.thNode == null && (e.type == "click" || kc == 13)) {\r
-                        var targ = this;\r
-                        while(targ.tagName.toLowerCase() != "th") { targ = targ.parentNode; };\r
-                        fdTableSort.thNode = targ;\r
-                        while(targ.tagName.toLowerCase() != "table") { targ = targ.parentNode; };\r
-                        fdTableSort.tableId = targ.id;\r
-                        fdTableSort.multi = e.shiftKey;\r
-                        fdTableSort.addSortActiveClass();\r
-                        setTimeout(fdTableSort.initSort,5,false);\r
-                        return fdTableSort.stopEvent(e);\r
-                };\r
-                return kc != -1 ? true : fdTableSort.stopEvent(e);\r
-        },\r
-        jsWrapper: function(tableid, colNums) {\r
-                if(!(tableid in fdTableSort.tmpCache)) { return false; };\r
-                if(!(tableid in fdTableSort.tableCache)) { fdTableSort.prepareTableData(document.getElementById(tableid)); };\r
-                if(!(colNums instanceof Array)) { colNums = [colNums]; };\r
-\r
-                fdTableSort.tableId = tableid;\r
-                var len = colNums.length, colNum;\r
-\r
-                if(fdTableSort.tableCache[tableid].thList.length == colNums.length) {\r
-                        var identical = true;\r
-                        var th;\r
-                        for(var i = 0; i < len; i++) {\r
-                                colNum = colNums[i];\r
-                                th = fdTableSort.tmpCache[tableid].headers[0][colNum];\r
-                                if(th != fdTableSort.tableCache[tableid].thList[i]) {\r
-                                        identical = false;\r
-                                        break;\r
-                                };\r
-                        };\r
-                        if(identical) {\r
-                                fdTableSort.thNode = th;\r
-                                fdTableSort.initSort(true);\r
-                                return;\r
-                        };\r
-                };\r
-\r
-                fdTableSort.addSortActiveClass();\r
-\r
-                for(var i = 0; i < len; i++) {\r
-                        fdTableSort.multi = i;\r
-                        colNum = colNums[i];\r
-                        fdTableSort.thNode = fdTableSort.tmpCache[tableid].headers[0][colNum];\r
-                        fdTableSort.initSort(true);\r
-                };\r
-        },\r
-        addSortActiveClass: function() {\r
-                if(fdTableSort.thNode == null) { return; };\r
-                fdTableSort.addClass(fdTableSort.thNode, fdTableSort.sortActiveClass);\r
-                fdTableSort.addClass(document.getElementsByTagName('body')[0], fdTableSort.sortActiveClass);\r
-        },\r
-        removeSortActiveClass: function() {\r
-                if(fdTableSort.thNode == null) return;\r
-                fdTableSort.removeClass(fdTableSort.thNode, fdTableSort.sortActiveClass);\r
-                fdTableSort.removeClass(document.getElementsByTagName('body')[0], fdTableSort.sortActiveClass);\r
-        },\r
-        doCallback: function(init) {\r
-                if(!fdTableSort.tableId || !(fdTableSort.tableId in fdTableSort.tableCache)) { return; };\r
-                fdTableSort.callback(fdTableSort.tableId, init ? fdTableSort.tableCache[fdTableSort.tableId].initiatedCallback : fdTableSort.tableCache[fdTableSort.tableId].completeCallback);\r
-        },\r
-        addClass: function(e,c) {\r
-                if(new RegExp("(^|\\s)" + c + "(\\s|$)").test(e.className)) { return; };\r
-                e.className += ( e.className ? " " : "" ) + c;\r
-        },\r
-        /*@cc_on\r
-        /*@if (@_win32)\r
-        removeClass: function(e,c) {\r
-                e.className = !c ? "" : e.className.replace(new RegExp("(^|\\s)" + c + "(\\s|$)"), " ").replace(/^\s*((?:[\S\s]*\S)?)\s*$/, '$1');\r
-        },\r
-        @else @*/\r
-        removeClass: function(e,c) {\r
-                e.className = !c ? "" : e.className.replace(new RegExp("(^|\\s)" + c + "(\\s|$)"), " ").replace(/^\s\s*/, '').replace(/\s\s*$/, '');\r
-        },\r
-        /*@end\r
-        @*/\r
-        callback: function(tblId, cb) {\r
-                var func, parts;\r
-                try {\r
-                        if(cb.indexOf(".") != -1) {                              \r
-                                parts = cb.split('.');\r
-                                obj   = window;\r
-                                for (var x = 0, part; part = obj[parts[x]]; x++) {\r
-                                        if(part instanceof Function) {\r
-                                                (function() {\r
-                                                        var method = part;\r
-                                                        func = function (data) { method.apply(obj, [data]) };\r
-                                                })();\r
-                                        } else {\r
-                                                obj = part;\r
-                                        };\r
-                                };\r
-                        } else if(cb + tblId in window) {\r
-                                func = window[cb + tblId];\r
-                        } else if(cb in window) {\r
-                                func = window[cb];\r
-                        } else {\r
-                                func = null;\r
-                        };\r
-                 } catch(err) {};\r
-                           \r
-                if(!(func instanceof Function)) return;\r
-                func(tblId, fdTableSort.tableCache[tblId].thList);                               \r
-        },\r
-        prepareTableData: function(table) {\r
-                var data = [];\r
-\r
-                var start = table.getElementsByTagName('tbody');\r
-                start = start.length ? start[0] : table;\r
-\r
-                var trs = start.rows;\r
-                var ths = table.getElementsByTagName('th');\r
-\r
-                var numberOfRows = trs.length;\r
-                var numberOfCols = fdTableSort.tmpCache[table.id].cols;\r
-\r
-                var data = [];\r
-                var identical = new Array(numberOfCols);\r
-                var identVal  = new Array(numberOfCols);\r
-\r
-                for(var tmp = 0; tmp < numberOfCols; tmp++) identical[tmp] = true;\r
-\r
-                var tr, td, th, txt, tds, col, row;\r
-\r
-                var re = new RegExp(/fd-column-([0-9]+)/);\r
-                var rowCnt = 0;\r
-\r
-                var sortableColumnNumbers = [];\r
-\r
-                for(var tmp = 0, th; th = ths[tmp]; tmp++) {\r
-                        if(th.className.search(re) == -1) continue;\r
-                        sortableColumnNumbers[sortableColumnNumbers.length] = th;\r
-                };\r
-\r
-                for(row = 0; row < numberOfRows; row++) {\r
-\r
-                        tr              = trs[row];\r
-                        if(tr.parentNode != start || tr.getElementsByTagName("th").length || (tr.parentNode && tr.parentNode.tagName.toLowerCase().search(/thead|tfoot/) != -1)) continue;\r
-                        data[rowCnt]    = [];\r
-                        tds             = tr.cells;\r
-\r
-                        for(var tmp = 0, th; th = sortableColumnNumbers[tmp]; tmp++) {\r
-                                col = th.className.match(re)[1];\r
-\r
-                                td  = tds[col];\r
-                                txt = fdTableSort.getInnerText(td) + " ";\r
-                                txt = txt.replace(/^\s+/,'').replace(/\s+$/,'');\r
-\r
-                                if(th.className.search(/sortable-date/) != -1) {\r
-                                        txt = fdTableSort.dateFormat(txt, th.className.search(/sortable-date-dmy/) != -1);\r
-                                } else if(th.className.search(/sortable-numeric|sortable-currency/) != -1) {\r
-                                        txt = parseFloat(txt.replace(/[^0-9\.\-]/g,''));\r
-                                        if(isNaN(txt)) txt = "";\r
-                                } else if(th.className.search(/sortable-text/) != -1) {\r
-                                        txt = txt.toLowerCase();\r
-                                } else if (th.className.search(/sortable-keep/) != -1) {\r
-                                        txt = rowCnt;\r
-                                } else if(th.className.search(/sortable-([a-zA-Z\_]+)/) != -1) {\r
-                                        if((th.className.match(/sortable-([a-zA-Z\_]+)/)[1] + "PrepareData") in window) {\r
-                                                txt = window[th.className.match(/sortable-([a-zA-Z\_]+)/)[1] + "PrepareData"](td, txt);\r
-                                        };\r
-                                } else if(txt != "") {\r
-                                        fdTableSort.removeClass(th, "sortable");\r
-                                        if(fdTableSort.dateFormat(txt) != 0) {\r
-                                                fdTableSort.addClass(th, "sortable-date");\r
-                                                txt = fdTableSort.dateFormat(txt);\r
-                                        } else if(txt.search(fdTableSort.regExp_Number) != -1 || txt.search(fdTableSort.regExp_Currency) != -1) {\r
-                                                fdTableSort.addClass(th, "sortable-numeric");\r
-                                                txt = parseFloat(txt.replace(/[^0-9\.\-]/g,''));\r
-                                                if(isNaN(txt)) txt = "";\r
-                                        } else {\r
-                                                fdTableSort.addClass(th, "sortable-text");\r
-                                                txt = txt.toLowerCase();\r
-                                        };\r
-                                };\r
-\r
-                                if(rowCnt > 0 && identical[col] && identVal[col] != txt) { identical[col] = false; };\r
-\r
-                                identVal[col]     = txt;\r
-                                data[rowCnt][col] = txt;\r
-                        };\r
-                        data[rowCnt][numberOfCols] = tr;\r
-                        rowCnt++;\r
-                };\r
-\r
-                var colStyle = table.className.search(/colstyle-([\S]+)/) != -1 ? table.className.match(/colstyle-([\S]+)/)[1] : false;\r
-                var rowStyle = table.className.search(/rowstyle-([\S]+)/) != -1 ? table.className.match(/rowstyle-([\S]+)/)[1] : false;\r
-                var iCBack   = table.className.search(/sortinitiatedcallback-([\S-]+)/) == -1 ? "sortInitiatedCallback" : table.className.match(/sortinitiatedcallback-([\S]+)/)[1];\r
-                var cCBack   = table.className.search(/sortcompletecallback-([\S-]+)/) == -1 ? "sortCompleteCallback" : table.className.match(/sortcompletecallback-([\S]+)/)[1];\r
-                iCBack = iCBack.replace("-", ".");\r
-                cCBack = cCBack.replace("-", ".");\r
-                fdTableSort.tableCache[table.id] = { hook:start, initiatedCallback:iCBack, completeCallback:cCBack, thList:[], colOrder:{}, data:data, identical:identical, colStyle:colStyle, rowStyle:rowStyle, noArrow:table.className.search(/no-arrow/) != -1 };\r
-                sortableColumnNumbers = data = tr = td = th = trs = identical = identVal = null;\r
-        },\r
-        onUnload: function() {\r
-                for(tbl in fdTableSort.tableCache) { fdTableSort.removeTableCache(tbl); };\r
-                for(tbl in fdTableSort.tmpCache) { fdTableSort.removeTmpCache(tbl); };\r
-                fdTableSort.removeEvent(window, "load", fdTableSort.initEvt);\r
-                fdTableSort.removeEvent(window, "unload", fdTableSort.onUnload);\r
-                fdTableSort.tmpCache = fdTableSort.tableCache = null;\r
-        },\r
-        addThNode: function() {\r
-                var dataObj = fdTableSort.tableCache[fdTableSort.tableId];\r
-                var pos     = fdTableSort.thNode.className.match(/fd-column-([0-9]+)/)[1];\r
-                var alt     = false;\r
-\r
-                if(!fdTableSort.multi) {\r
-                        if(dataObj.colStyle) {\r
-                                var len = dataObj.thList.length;\r
-                                for(var i = 0; i < len; i++) {\r
-                                        dataObj.colOrder[dataObj.thList[i].className.match(/fd-column-([0-9]+)/)[1]] = false;\r
-                                };\r
-                        };\r
-                        if(dataObj.thList.length && dataObj.thList[0] == fdTableSort.thNode) alt = true;\r
-                        dataObj.thList = [];\r
-                };\r
-\r
-                var found = false;\r
-                var l = dataObj.thList.length;\r
-\r
-                for(var i = 0, n; n = dataObj.thList[i]; i++) {\r
-                        if(n == fdTableSort.thNode) {\r
-                                found = true;\r
-                                break;\r
-                        };\r
-                };\r
-\r
-                if(!found) {\r
-                        dataObj.thList.push(fdTableSort.thNode);\r
-                        if(dataObj.colStyle) { dataObj.colOrder[pos] = true; };\r
-                };\r
-\r
-                var ths = document.getElementById(fdTableSort.tableId).getElementsByTagName("th");\r
-                for(var i = 0, th; th = ths[i]; i++) {\r
-                        found = false;\r
-                        for(var z = 0, n; n = dataObj.thList[z]; z++) {\r
-                                if(n == th) {\r
-                                        found = true;\r
-                                        break;\r
-                                };\r
-                        };\r
-                        if(!found) {\r
-                                fdTableSort.removeClass(th, "(forwardSort|reverseSort)");\r
-                                if(!dataObj.noArrow) {\r
-                                        span = th.getElementsByTagName('span');\r
-                                        if(span.length) {\r
-                                                span = span[0];\r
-                                                while(span.firstChild) span.removeChild(span.firstChild);\r
-                                        };\r
-                                };\r
-                        };\r
-                };\r
-\r
-                if(dataObj.thList.length > 1) {\r
-                        classToAdd = fdTableSort.thNode.className.search(/forwardSort/) != -1 ? "reverseSort" : "forwardSort";\r
-                        fdTableSort.removeClass(fdTableSort.thNode, "(forwardSort|reverseSort)");\r
-                        fdTableSort.addClass(fdTableSort.thNode, classToAdd);\r
-                        dataObj.pos = -1\r
-                } else if(alt) { dataObj.pos = fdTableSort.thNode };\r
-        },\r
-        initSort: function(noCallback, ident) {\r
-                var thNode      = fdTableSort.thNode;\r
-                var tableElem   = document.getElementById(fdTableSort.tableId);\r
-\r
-                if(!(fdTableSort.tableId in fdTableSort.tableCache)) { fdTableSort.prepareTableData(document.getElementById(fdTableSort.tableId)); };\r
-\r
-                fdTableSort.addThNode();\r
-\r
-                if(!noCallback) { fdTableSort.doCallback(true); };\r
-\r
-                fdTableSort.pos = thNode.className.match(/fd-column-([0-9]+)/)[1];\r
-                var dataObj     = fdTableSort.tableCache[tableElem.id];\r
-                var lastPos     = dataObj.pos && dataObj.pos.className ? dataObj.pos.className.match(/fd-column-([0-9]+)/)[1] : -1;\r
-                var len1        = dataObj.data.length;\r
-                var len2        = dataObj.data.length > 0 ? dataObj.data[0].length - 1 : 0;\r
-                var identical   = dataObj.identical[fdTableSort.pos];\r
-                var classToAdd  = "forwardSort";\r
-\r
-                if(dataObj.thList.length > 1) {\r
-                        var js  = "var sortWrapper = function(a,b) {\n";\r
-                        var l   = dataObj.thList.length;\r
-                        var cnt = 0;\r
-                        var e,d,th,p,f;\r
-\r
-                        for(var i=0; i < l; i++) {\r
-                                th = dataObj.thList[i];\r
-                                p  = th.className.match(/fd-column-([0-9]+)/)[1];\r
-                                if(dataObj.identical[p]) { continue; };\r
-                                cnt++;\r
-\r
-                                if(th.className.match(/sortable-(numeric|currency|date|keep)/)) {\r
-                                        f = "fdTableSort.sortNumeric";\r
-                                } else if(th.className.match('sortable-text')) {\r
-                                        f = "fdTableSort.sortText";\r
-                                } else if(th.className.search(/sortable-([a-zA-Z\_]+)/) != -1 && th.className.match(/sortable-([a-zA-Z\_]+)/)[1] in window) {\r
-                                        f = "window['" + th.className.match(/sortable-([a-zA-Z\_]+)/)[1] + "']";\r
-                                } else  f = "fdTableSort.sortText";\r
-\r
-                                e = "e" + i;\r
-                                d = th.className.search('forwardSort') != -1 ? "a,b" : "b,a";\r
-                                js += "fdTableSort.pos   = " + p + ";\n";\r
-                                js += "var " + e + " = "+f+"(" + d +");\n";\r
-                                js += "if(" + e + ") return " + e + ";\n";\r
-                                js += "else { \n";\r
-                        };\r
-\r
-                        js += "return 0;\n";\r
-\r
-                        for(var i=0; i < cnt; i++) {\r
-                                js += "};\n";\r
-                        };\r
-\r
-                        if(cnt) js += "return 0;\n";\r
-                        js += "};\n";\r
-\r
-                        eval(js);\r
-                        dataObj.data.sort(sortWrapper);\r
-                        identical = false;\r
-                } else if((lastPos == fdTableSort.pos && !identical) || (thNode.className.search(/sortable-keep/) != -1 && lastPos == -1)) {\r
-                        dataObj.data.reverse();\r
-                        classToAdd = thNode.className.search(/reverseSort/) != -1 ? "forwardSort" : "reverseSort";\r
-                        if(thNode.className.search(/sortable-keep/) != -1 && lastPos == -1) fdTableSort.tableCache[tableElem.id].pos = thNode;\r
-                } else {\r
-                        fdTableSort.tableCache[tableElem.id].pos = thNode;\r
-                        classToAdd = thNode.className.search(/forwardSort/) != -1 ? "reverseSort" : "forwardSort";\r
-                        if(!identical) {\r
-                                if(thNode.className.match(/sortable-(numeric|currency|date|keep)/)) {\r
-                                        dataObj.data.sort(fdTableSort.sortNumeric);\r
-                                } else if(thNode.className.match('sortable-text')) {\r
-                                        dataObj.data.sort(fdTableSort.sortText);\r
-                                } else if(thNode.className.search(/sortable-([a-zA-Z\_]+)/) != -1 && thNode.className.match(/sortable-([a-zA-Z\_]+)/)[1] in window) {\r
-                                        dataObj.data.sort(window[thNode.className.match(/sortable-([a-zA-Z\_]+)/)[1]]);\r
-                                };\r
-\r
-                                if(thNode.className.search(/(^|\s)favour-reverse($|\s)/) != -1) {\r
-                                        classToAdd = classToAdd == "forwardSort" ? "reverseSort" : "forwardSort";\r
-                                        dataObj.data.reverse();\r
-                                };\r
-                        };\r
-                };\r
-                if(ident) { identical = false; };\r
-                if(dataObj.thList.length == 1) {\r
-                        fdTableSort.removeClass(thNode, "(forwardSort|reverseSort)");\r
-                        fdTableSort.addClass(thNode, classToAdd);\r
-                };\r
-                if(!dataObj.noArrow) {\r
-                        var span = fdTableSort.thNode.getElementsByTagName('span')[0];\r
-                        if(span.firstChild) span.removeChild(span.firstChild);\r
-                        span.appendChild(document.createTextNode(fdTableSort.thNode.className.search(/forwardSort/) != -1 ? " \u2193" : " \u2191"));\r
-                };\r
-                if(!dataObj.rowStyle && !dataObj.colStyle && identical) {\r
-                        fdTableSort.removeSortActiveClass();\r
-                        if(!noCallback) { fdTableSort.doCallback(false); };\r
-                        fdTableSort.thNode = null;\r
-                        return;\r
-                };\r
-                if("tablePaginater" in window && tablePaginater.tableIsPaginated(fdTableSort.tableId)) {\r
-                        tablePaginater.redraw(fdTableSort.tableId, identical);\r
-                } else {\r
-                        fdTableSort.redraw(fdTableSort.tableId, identical);\r
-                };\r
-                fdTableSort.removeSortActiveClass();\r
-                if(!noCallback) { fdTableSort.doCallback(false); };\r
-                fdTableSort.thNode = null;\r
-        },\r
-        redraw: function(tableid, identical) {\r
-                if(!tableid || !(tableid in fdTableSort.tableCache)) { return; };\r
-                var dataObj     = fdTableSort.tableCache[tableid];\r
-                var data        = dataObj.data;\r
-                var len1        = data.length;\r
-                var len2        = len1 ? data[0].length - 1 : 0;\r
-                var hook        = dataObj.hook;\r
-                var colStyle    = dataObj.colStyle;\r
-                var rowStyle    = dataObj.rowStyle;\r
-                var colOrder    = dataObj.colOrder;\r
-                var highLight   = 0;\r
-                var reg         = /(^|\s)invisibleRow(\s|$)/;\r
-                var tr, tds;\r
-\r
-                for(var i = 0; i < len1; i++) {\r
-                        tr = data[i][len2];\r
-                        if(colStyle) {\r
-                                tds = tr.cells;\r
-                                for(thPos in colOrder) {\r
-                                        if(!colOrder[thPos]) fdTableSort.removeClass(tds[thPos], colStyle);\r
-                                        else fdTableSort.addClass(tds[thPos], colStyle);\r
-                                };\r
-                        };\r
-                        if(!identical) {\r
-                                if(rowStyle && tr.className.search(reg) == -1) {\r
-                                        if(highLight++ & 1) fdTableSort.addClass(tr, rowStyle);\r
-                                        else fdTableSort.removeClass(tr, rowStyle);\r
-                                };\r
-\r
-                                // Netscape 8.1.2 requires the removeChild call or it freaks out, so add the line if you want to support this browser\r
-                                // hook.removeChild(tr);\r
-                                hook.appendChild(tr);\r
-                        };\r
-                };\r
-                tr = tds = hook = null;\r
-        },\r
-        getInnerText: function(el, allowBrTags) {\r
-                if (typeof el == "string" || typeof el == "undefined") return el;\r
-                if(el.innerText) return el.innerText;\r
-                var txt = '', i;\r
-                for(i = el.firstChild; i; i = i.nextSibling) {\r
-                        if(allowBrTags && i.nodeName && i.nodeName == "BR") txt += "<br />";\r
-                        else if(i.nodeType == 3)       txt += i.nodeValue;\r
-                        else if(i.nodeType == 1)       txt += fdTableSort.getInnerText(i);\r
-                };\r
-                return txt;\r
-        },\r
-        dateFormat: function(dateIn, favourDMY) {\r
-                var dateTest = [\r
-                        { regExp:/^(0?[1-9]|1[012])([- \/.])(0?[1-9]|[12][0-9]|3[01])([- \/.])((\d\d)?\d\d)$/, d:3, m:1, y:5 },  // mdy\r
-                        { regExp:/^(0?[1-9]|[12][0-9]|3[01])([- \/.])(0?[1-9]|1[012])([- \/.])((\d\d)?\d\d)$/, d:1, m:3, y:5 },  // dmy\r
-                        { regExp:/^(\d\d\d\d)([- \/.])(0?[1-9]|1[012])([- \/.])(0?[1-9]|[12][0-9]|3[01])$/, d:5, m:3, y:1 }      // ymd\r
-                        ];\r
-                var start, cnt = 0, numFormats = dateTest.length;\r
-                while(cnt < numFormats) {\r
-                        start = (cnt + (favourDMY ? numFormats + 1 : numFormats)) % numFormats;\r
-                        if(dateIn.match(dateTest[start].regExp)) {\r
-                                res = dateIn.match(dateTest[start].regExp);\r
-                                y = res[dateTest[start].y];\r
-                                m = res[dateTest[start].m];\r
-                                d = res[dateTest[start].d];\r
-                                if(m.length == 1) m = "0" + String(m);\r
-                                if(d.length == 1) d = "0" + String(d);\r
-                                if(y.length != 4) y = (parseInt(y) < 50) ? "20" + String(y) : "19" + String(y);\r
-\r
-                                return y+String(m)+d;\r
-                        };\r
-                        cnt++;\r
-                };\r
-                return 0;\r
-        },\r
-        sortNumeric:function(a,b) {\r
-                var aa = a[fdTableSort.pos];\r
-                var bb = b[fdTableSort.pos];\r
-                if(aa == bb) return 0;\r
-                if(aa === "" && !isNaN(bb)) return -1;\r
-                if(bb === "" && !isNaN(aa)) return 1;\r
-                return aa - bb;\r
-        },\r
-        sortText:function(a,b) {\r
-                var aa = a[fdTableSort.pos];\r
-                var bb = b[fdTableSort.pos];\r
-                if(aa == bb) return 0;\r
-                if(aa < bb)  return -1;\r
-                return 1;\r
-        }\r
-};\r
-})();\r
-fdTableSort.addEvent(window, "load",   fdTableSort.initEvt);\r
-fdTableSort.addEvent(window, "unload", fdTableSort.onUnload);\r
+/*
+        TableSort revisited v5.0 by frequency-decoder.com
+
+        Released under a creative commons Attribution-ShareAlike 2.5 license (http://creativecommons.org/licenses/by-sa/2.5/)
+
+        Please credit frequency decoder in any derivative work - thanks
+
+        You are free:
+
+        * to copy, distribute, display, and perform the work
+        * to make derivative works
+        * to make commercial use of the work
+
+        Under the following conditions:
+
+                by Attribution.
+                --------------
+                You must attribute the work in the manner specified by the author or licensor.
+
+                sa
+                --
+                Share Alike. If you alter, transform, or build upon this work, you may distribute the resulting work only under a license identical to this one.
+
+        * For any reuse or distribution, you must make clear to others the license terms of this work.
+        * Any of these conditions can be waived if you get permission from the copyright holder.
+*/
+
+(function() {
+fdTableSort = {
+        regExp_Currency:        /^[£$€¥¤]/,
+        regExp_Number:          /^(\-)?[0-9]+(\.[0-9]*)?$/,
+        pos:                    -1,
+        uniqueHash:             1,
+        thNode:                 null,
+        tableId:                null,
+        tableCache:             {},
+        tmpCache:               {},
+        sortActiveClass:        "sort-active",
+        /*@cc_on
+        /*@if (@_win32)
+        colspan:                "colSpan",
+        rowspan:                "rowSpan",
+        @else @*/
+        colspan:                "colspan",
+        rowspan:                "rowspan",
+        /*@end
+        @*/
+        
+        addEvent: function(obj, type, fn, tmp) {
+                tmp || (tmp = true);
+                if( obj.attachEvent ) {
+                        obj["e"+type+fn] = fn;
+                        obj[type+fn] = function(){obj["e"+type+fn]( window.event );};
+                        obj.attachEvent( "on"+type, obj[type+fn] );
+                } else {
+                        obj.addEventListener( type, fn, true );
+                };
+        },
+        removeEvent: function(obj, type, fn, tmp) {
+                tmp || (tmp = true);
+                try {
+                        if( obj.detachEvent ) {
+                                obj.detachEvent( "on"+type, obj[type+fn] );
+                                obj[type+fn] = null;
+                        } else {
+                                obj.removeEventListener( type, fn, true );
+                        };
+                } catch(err) {};
+        },
+        stopEvent: function(e) {
+                e = e || window.event;
+
+                if(e.stopPropagation) {
+                        e.stopPropagation();
+                        e.preventDefault();
+                };
+                
+                /*@cc_on@*/
+                /*@if(@_win32)
+                e.cancelBubble = true;
+                e.returnValue  = false;
+                /*@end@*/
+                return false;
+        },
+        parseClassName: function(head, tbl) {
+                var colMatch = tbl.className.match(new RegExp(head + "((-[\\d]+([r]){0,1})+)"));
+                return colMatch && colMatch.length ? colMatch[0].replace(head, "").split("-") : [];
+        },
+        disableSelection: function(element) {
+                element.onselectstart = function() {
+                        return false;
+                };
+                element.unselectable = "on";
+                element.style.MozUserSelect = "none";
+        },
+        removeTableCache: function(tableId) {
+                if(!(tableId in fdTableSort.tableCache)) return;
+
+                fdTableSort.tableCache[tableId] = null;
+                delete fdTableSort.tableCache[tableId];
+
+                var tbl = document.getElementById(tableId);
+                if(!tbl) return;
+                var ths = tbl.getElementsByTagName("th");
+                var a;
+                for(var i = 0, th; th = ths[i]; i++) {
+                        a = th.getElementsByTagName("a");
+                        if(a.length) a[0].onkeydown = a[0].onclick = null;
+                        th.onclick = th.onselectstart = th = a = null;
+                };
+        },
+        removeTmpCache: function(tableId) {
+                if(!(tableId in fdTableSort.tmpCache)) return;
+                var headers = fdTableSort.tmpCache[tableId].headers;
+                var a;
+                for(var i = 0, row; row = headers[i]; i++) {
+                        for(var j = 0, th; th = row[j]; j++) {
+                                a = th.getElementsByTagName("a");
+                                if(a.length) a[0].onkeydown = a[0].onclick = null;
+                                th.onclick = th.onselectstart = th = a = null;
+                        };
+                };
+                fdTableSort.tmpCache[tableId] = null;
+                delete fdTableSort.tmpCache[tableId];
+        },
+        initEvt: function(e) {
+                fdTableSort.init(false);
+        },
+        init: function(tableId) {
+                if (!document.getElementsByTagName || !document.createElement || !document.getElementById) return;
+
+                var tables = tableId && document.getElementById(tableId) ? [document.getElementById(tableId)] : document.getElementsByTagName("table");
+                var c, ii, len, colMatch, showOnly, match, showArrow, columnNumSortObj, obj, workArr, headers, thtext, aclone, multi, colCnt, cel, allRowArr, rowArr, sortableTable, celCount, colspan, rowspan, rowLength;
+
+                var a          = document.createElement("a");
+                a.href         = "#";
+                a.className    = "fdTableSortTrigger";
+
+                var span       = document.createElement("span");
+
+                for(var k = 0, tbl; tbl = tables[k]; k++) {
+
+                        if(tbl.id) {
+                                fdTableSort.removeTableCache(tbl.id);
+                                fdTableSort.removeTmpCache(tbl.id);
+                        };
+
+                        allRowArr     = tbl.getElementsByTagName('thead').length ? tbl.getElementsByTagName('thead')[0].getElementsByTagName('tr') : tbl.getElementsByTagName('tr');
+                        rowArr        = [];
+                        sortableTable = false;
+
+                        for(var i = 0, tr; tr = allRowArr[i]; i++) {
+                                if(tr.getElementsByTagName('td').length || !tr.getElementsByTagName('th').length) { continue; };
+                                rowArr[rowArr.length] = tr.getElementsByTagName('th');
+                                for(var j = 0, th; th = rowArr[rowArr.length - 1][j]; j++) {
+                                        if(th.className.search(/sortable/) != -1) { sortableTable = true; };
+                                };
+                        };
+
+                        if(!sortableTable) continue;
+
+                        if(!tbl.id) { tbl.id = "fd-table-" + fdTableSort.uniqueHash++; };
+
+                        showArrow   = tbl.className.search("no-arrow") == -1;
+                        showOnly    = tbl.className.search("sortable-onload-show") != -1;
+
+                        columnNumSortObj = {};
+                        colMatch         = fdTableSort.parseClassName(showOnly ? "sortable-onload-show" : "sortable-onload", tbl);
+                        for(match = 1; match < colMatch.length; match++) {
+                                columnNumSortObj[parseInt(colMatch[match], 10)] = { "reverse":colMatch[match].search("r") != -1 };
+                        };
+
+                        rowLength = rowArr[0].length;
+
+                        for(c = 0;c < rowArr[0].length;c++){
+                                if(rowArr[0][c].getAttribute(fdTableSort.colspan) && rowArr[0][c].getAttribute(fdTableSort.colspan) > 1){
+                                        rowLength = rowLength + (rowArr[0][c].getAttribute(fdTableSort.colspan) - 1);
+                                };
+                        };
+
+                        workArr = new Array(rowArr.length);
+                        for(c = rowArr.length;c--;){ workArr[c]= new Array(rowLength); };
+
+                        for(c = 0;c < workArr.length;c++){
+                                celCount = 0;
+                                for(i = 0;i < rowLength;i++){
+                                        if(!workArr[c][i]){
+                                                cel = rowArr[c][celCount];
+                                                colspan = (cel.getAttribute(fdTableSort.colspan) > 1) ? cel.getAttribute(fdTableSort.colspan):1;
+                                                rowspan = (cel.getAttribute(fdTableSort.rowspan) > 1) ? cel.getAttribute(fdTableSort.rowspan):1;
+                                                for(var t = 0;((t < colspan)&&((i+t) < rowLength));t++){
+                                                        for(var n = 0;((n < rowspan)&&((c+n) < workArr.length));n++) {
+                                                                workArr[(c+n)][(i+t)] = cel;
+                                                        };
+                                                };
+                                                if(++celCount == rowArr[c].length) break;
+                                        };
+                                };
+                        };
+
+                        for(c = 0;c < workArr.length;c++) {
+                                for(i = 0;i < workArr[c].length;i++){
+
+                                        if(workArr[c][i].className.search("fd-column-") == -1 && workArr[c][i].className.search("sortable") != -1) workArr[c][i].className = workArr[c][i].className + " fd-column-" + i;
+
+                                        if(workArr[c][i].className.match('sortable')) {
+                                                workArr[c][i].className = workArr[c][i].className.replace(/forwardSort|reverseSort/, "");
+
+                                                if(i in columnNumSortObj) {
+                                                        columnNumSortObj[i]["thNode"] = workArr[c][i];
+                                                        columnNumSortObj["active"] = true;
+                                                };
+
+                                                thtext = fdTableSort.getInnerText(workArr[c][i], true);
+                                                
+                                                for(var cn = workArr[c][i].childNodes.length; cn--;) {
+                                                        // Skip image nodes and links created by the filter script.
+                                                        if(workArr[c][i].childNodes[cn].nodeType == 1 && (workArr[c][i].childNodes[cn].className == "fdFilterTrigger" || /img/i.test(workArr[c][i].childNodes[cn].nodeName))) {
+                                                                continue;
+                                                        };
+                                                        if(workArr[c][i].childNodes[cn].nodeType == 1 && /^a$/i.test(workArr[c][i].childNodes[cn].nodeName)) {
+                                                                workArr[c][i].childNodes[cn].onclick = workArr[c][i].childNodes[cn].onkeydown = null;
+                                                        };
+                                                        workArr[c][i].removeChild(workArr[c][i].childNodes[cn]);
+                                                };
+
+                                                aclone = a.cloneNode(true);
+                                                //aclone.appendChild(document.createTextNode(thtext));
+                                                aclone.innerHTML = thtext;
+                                                aclone.title = "Sort on \u201c" + thtext.replace('<br />', '') + "\u201d";
+                                                aclone.onclick = aclone.onkeydown = workArr[c][i].onclick = fdTableSort.initWrapper;
+                                                workArr[c][i].appendChild(aclone);
+                                                if(showArrow) workArr[c][i].appendChild(span.cloneNode(false));
+                                                workArr[c][i].className = workArr[c][i].className.replace(/fd-identical|fd-not-identical/, "");
+                                                fdTableSort.disableSelection(workArr[c][i]);
+                                                aclone = null;
+                                        };
+                                };
+                        };
+
+                        fdTableSort.tmpCache[tbl.id] = {cols:rowLength, headers:workArr};
+
+                        workArr = null;
+                        multi   = 0;
+
+                        if("active" in columnNumSortObj) {
+                                fdTableSort.tableId = tbl.id;
+                                fdTableSort.prepareTableData(document.getElementById(fdTableSort.tableId));
+
+                                delete columnNumSortObj["active"];
+
+                                for(col in columnNumSortObj) {
+                                        obj = columnNumSortObj[col];
+                                        if(!("thNode" in obj)) { continue; };
+                                        fdTableSort.multi = true;
+
+                                        len = obj.reverse ? 2 : 1;
+
+                                        for(ii = 0; ii < len; ii++) {
+                                                fdTableSort.thNode = obj.thNode;
+                                                if(!showOnly) {
+                                                        fdTableSort.initSort(false, true);
+                                                } else {
+                                                        fdTableSort.addThNode();
+                                                };
+                                        };
+
+                                        if(showOnly) {
+                                                fdTableSort.removeClass(obj.thNode, "(forwardSort|reverseSort)");
+                                                fdTableSort.addClass(obj.thNode, obj.reverse ? "reverseSort" : "forwardSort");
+                                                if(showArrow) {
+                                                        span = fdTableSort.thNode.getElementsByTagName('span')[0];
+                                                        if(span.firstChild) { span.removeChild(span.firstChild); };
+                                                        span.appendChild(document.createTextNode(len == 1 ? " \u2193" : " \u2191"));
+                                                };
+                                        };
+                                };
+                                if(showOnly && (fdTableSort.tableCache[tbl.id].colStyle || fdTableSort.tableCache[tbl.id].rowStyle)) {
+                                        fdTableSort.redraw(tbl.id, false);
+                                };
+                        } else if(tbl.className.search(/onload-zebra/) != -1) {
+                                fdTableSort.tableId = tbl.id;
+                                fdTableSort.prepareTableData(tbl);
+                                if(fdTableSort.tableCache[tbl.id].rowStyle) { fdTableSort.redraw(tbl.id, false); };
+                        };
+                };
+
+                fdTableSort.thNode = aclone = a = span = columnNumSortObj = thNode = tbl = allRowArr = rowArr = null;
+        },
+        initWrapper: function(e) {
+                e = e || window.event;
+                var kc = e.type == "keydown" ? e.keyCode != null ? e.keyCode : e.charCode : -1;
+                if(fdTableSort.thNode == null && (e.type == "click" || kc == 13)) {
+                        var targ = this;
+                        while(targ.tagName.toLowerCase() != "th") { targ = targ.parentNode; };
+                        fdTableSort.thNode = targ;
+                        while(targ.tagName.toLowerCase() != "table") { targ = targ.parentNode; };
+                        fdTableSort.tableId = targ.id;
+                        fdTableSort.multi = e.shiftKey;
+                        fdTableSort.addSortActiveClass();
+                        setTimeout(fdTableSort.initSort,5,false);
+                        return fdTableSort.stopEvent(e);
+                };
+                return kc != -1 ? true : fdTableSort.stopEvent(e);
+        },
+        jsWrapper: function(tableid, colNums) {
+                if(!(tableid in fdTableSort.tmpCache)) { return false; };
+                if(!(tableid in fdTableSort.tableCache)) { fdTableSort.prepareTableData(document.getElementById(tableid)); };
+                if(!(colNums instanceof Array)) { colNums = [colNums]; };
+
+                fdTableSort.tableId = tableid;
+                var len = colNums.length, colNum;
+
+                if(fdTableSort.tableCache[tableid].thList.length == colNums.length) {
+                        var identical = true;
+                        var th;
+                        for(var i = 0; i < len; i++) {
+                                colNum = colNums[i];
+                                th = fdTableSort.tmpCache[tableid].headers[0][colNum];
+                                if(th != fdTableSort.tableCache[tableid].thList[i]) {
+                                        identical = false;
+                                        break;
+                                };
+                        };
+                        if(identical) {
+                                fdTableSort.thNode = th;
+                                fdTableSort.initSort(true);
+                                return;
+                        };
+                };
+
+                fdTableSort.addSortActiveClass();
+
+                for(var i = 0; i < len; i++) {
+                        fdTableSort.multi = i;
+                        colNum = colNums[i];
+                        fdTableSort.thNode = fdTableSort.tmpCache[tableid].headers[0][colNum];
+                        fdTableSort.initSort(true);
+                };
+        },
+        addSortActiveClass: function() {
+                if(fdTableSort.thNode == null) { return; };
+                fdTableSort.addClass(fdTableSort.thNode, fdTableSort.sortActiveClass);
+                fdTableSort.addClass(document.getElementsByTagName('body')[0], fdTableSort.sortActiveClass);
+        },
+        removeSortActiveClass: function() {
+                if(fdTableSort.thNode == null) return;
+                fdTableSort.removeClass(fdTableSort.thNode, fdTableSort.sortActiveClass);
+                fdTableSort.removeClass(document.getElementsByTagName('body')[0], fdTableSort.sortActiveClass);
+        },
+        doCallback: function(init) {
+                if(!fdTableSort.tableId || !(fdTableSort.tableId in fdTableSort.tableCache)) { return; };
+                fdTableSort.callback(fdTableSort.tableId, init ? fdTableSort.tableCache[fdTableSort.tableId].initiatedCallback : fdTableSort.tableCache[fdTableSort.tableId].completeCallback);
+        },
+        addClass: function(e,c) {
+                if(new RegExp("(^|\\s)" + c + "(\\s|$)").test(e.className)) { return; };
+                e.className += ( e.className ? " " : "" ) + c;
+        },
+        /*@cc_on
+        /*@if (@_win32)
+        removeClass: function(e,c) {
+                e.className = !c ? "" : e.className.replace(new RegExp("(^|\\s)" + c + "(\\s|$)"), " ").replace(/^\s*((?:[\S\s]*\S)?)\s*$/, '$1');
+        },
+        @else @*/
+        removeClass: function(e,c) {
+                e.className = !c ? "" : e.className.replace(new RegExp("(^|\\s)" + c + "(\\s|$)"), " ").replace(/^\s\s*/, '').replace(/\s\s*$/, '');
+        },
+        /*@end
+        @*/
+        callback: function(tblId, cb) {
+                var func, parts;
+                try {
+                        if(cb.indexOf(".") != -1) {                              
+                                parts = cb.split('.');
+                                obj   = window;
+                                for (var x = 0, part; part = obj[parts[x]]; x++) {
+                                        if(part instanceof Function) {
+                                                (function() {
+                                                        var method = part;
+                                                        func = function (data) { method.apply(obj, [data]) };
+                                                })();
+                                        } else {
+                                                obj = part;
+                                        };
+                                };
+                        } else if(cb + tblId in window) {
+                                func = window[cb + tblId];
+                        } else if(cb in window) {
+                                func = window[cb];
+                        } else {
+                                func = null;
+                        };
+                 } catch(err) {};
+                           
+                if(!(func instanceof Function)) return;
+                func(tblId, fdTableSort.tableCache[tblId].thList);                               
+        },
+        prepareTableData: function(table) {
+                var data = [];
+
+                var start = table.getElementsByTagName('tbody');
+                start = start.length ? start[0] : table;
+
+                var trs = start.rows;
+                var ths = table.getElementsByTagName('th');
+
+                var numberOfRows = trs.length;
+                var numberOfCols = fdTableSort.tmpCache[table.id].cols;
+
+                var data = [];
+                var identical = new Array(numberOfCols);
+                var identVal  = new Array(numberOfCols);
+
+                for(var tmp = 0; tmp < numberOfCols; tmp++) identical[tmp] = true;
+
+                var tr, td, th, txt, tds, col, row;
+
+                var re = new RegExp(/fd-column-([0-9]+)/);
+                var rowCnt = 0;
+
+                var sortableColumnNumbers = [];
+
+                for(var tmp = 0, th; th = ths[tmp]; tmp++) {
+                        if(th.className.search(re) == -1) continue;
+                        sortableColumnNumbers[sortableColumnNumbers.length] = th;
+                };
+
+                for(row = 0; row < numberOfRows; row++) {
+
+                        tr              = trs[row];
+                        if(tr.parentNode != start || tr.getElementsByTagName("th").length || (tr.parentNode && tr.parentNode.tagName.toLowerCase().search(/thead|tfoot/) != -1)) continue;
+                        data[rowCnt]    = [];
+                        tds             = tr.cells;
+
+                        for(var tmp = 0, th; th = sortableColumnNumbers[tmp]; tmp++) {
+                                col = th.className.match(re)[1];
+
+                                td  = tds[col];
+                                txt = fdTableSort.getInnerText(td) + " ";
+                                txt = txt.replace(/^\s+/,'').replace(/\s+$/,'');
+
+                                if(th.className.search(/sortable-date/) != -1) {
+                                        txt = fdTableSort.dateFormat(txt, th.className.search(/sortable-date-dmy/) != -1);
+                                } else if(th.className.search(/sortable-numeric|sortable-currency/) != -1) {
+                                        txt = parseFloat(txt.replace(/[^0-9\.\-]/g,''));
+                                        if(isNaN(txt)) txt = "";
+                                } else if(th.className.search(/sortable-text/) != -1) {
+                                        txt = txt.toLowerCase();
+                                } else if (th.className.search(/sortable-keep/) != -1) {
+                                        txt = rowCnt;
+                                } else if(th.className.search(/sortable-([a-zA-Z\_]+)/) != -1) {
+                                        if((th.className.match(/sortable-([a-zA-Z\_]+)/)[1] + "PrepareData") in window) {
+                                                txt = window[th.className.match(/sortable-([a-zA-Z\_]+)/)[1] + "PrepareData"](td, txt);
+                                        };
+                                } else if(txt != "") {
+                                        fdTableSort.removeClass(th, "sortable");
+                                        if(fdTableSort.dateFormat(txt) != 0) {
+                                                fdTableSort.addClass(th, "sortable-date");
+                                                txt = fdTableSort.dateFormat(txt);
+                                        } else if(txt.search(fdTableSort.regExp_Number) != -1 || txt.search(fdTableSort.regExp_Currency) != -1) {
+                                                fdTableSort.addClass(th, "sortable-numeric");
+                                                txt = parseFloat(txt.replace(/[^0-9\.\-]/g,''));
+                                                if(isNaN(txt)) txt = "";
+                                        } else {
+                                                fdTableSort.addClass(th, "sortable-text");
+                                                txt = txt.toLowerCase();
+                                        };
+                                };
+
+                                if(rowCnt > 0 && identical[col] && identVal[col] != txt) { identical[col] = false; };
+
+                                identVal[col]     = txt;
+                                data[rowCnt][col] = txt;
+                        };
+                        data[rowCnt][numberOfCols] = tr;
+                        rowCnt++;
+                };
+
+                var colStyle = table.className.search(/colstyle-([\S]+)/) != -1 ? table.className.match(/colstyle-([\S]+)/)[1] : false;
+                var rowStyle = table.className.search(/rowstyle-([\S]+)/) != -1 ? table.className.match(/rowstyle-([\S]+)/)[1] : false;
+                var iCBack   = table.className.search(/sortinitiatedcallback-([\S-]+)/) == -1 ? "sortInitiatedCallback" : table.className.match(/sortinitiatedcallback-([\S]+)/)[1];
+                var cCBack   = table.className.search(/sortcompletecallback-([\S-]+)/) == -1 ? "sortCompleteCallback" : table.className.match(/sortcompletecallback-([\S]+)/)[1];
+                iCBack = iCBack.replace("-", ".");
+                cCBack = cCBack.replace("-", ".");
+                fdTableSort.tableCache[table.id] = { hook:start, initiatedCallback:iCBack, completeCallback:cCBack, thList:[], colOrder:{}, data:data, identical:identical, colStyle:colStyle, rowStyle:rowStyle, noArrow:table.className.search(/no-arrow/) != -1 };
+                sortableColumnNumbers = data = tr = td = th = trs = identical = identVal = null;
+        },
+        onUnload: function() {
+                for(tbl in fdTableSort.tableCache) { fdTableSort.removeTableCache(tbl); };
+                for(tbl in fdTableSort.tmpCache) { fdTableSort.removeTmpCache(tbl); };
+                fdTableSort.removeEvent(window, "load", fdTableSort.initEvt);
+                fdTableSort.removeEvent(window, "unload", fdTableSort.onUnload);
+                fdTableSort.tmpCache = fdTableSort.tableCache = null;
+        },
+        addThNode: function() {
+                var dataObj = fdTableSort.tableCache[fdTableSort.tableId];
+                var pos     = fdTableSort.thNode.className.match(/fd-column-([0-9]+)/)[1];
+                var alt     = false;
+
+                if(!fdTableSort.multi) {
+                        if(dataObj.colStyle) {
+                                var len = dataObj.thList.length;
+                                for(var i = 0; i < len; i++) {
+                                        dataObj.colOrder[dataObj.thList[i].className.match(/fd-column-([0-9]+)/)[1]] = false;
+                                };
+                        };
+                        if(dataObj.thList.length && dataObj.thList[0] == fdTableSort.thNode) alt = true;
+                        dataObj.thList = [];
+                };
+
+                var found = false;
+                var l = dataObj.thList.length;
+
+                for(var i = 0, n; n = dataObj.thList[i]; i++) {
+                        if(n == fdTableSort.thNode) {
+                                found = true;
+                                break;
+                        };
+                };
+
+                if(!found) {
+                        dataObj.thList.push(fdTableSort.thNode);
+                        if(dataObj.colStyle) { dataObj.colOrder[pos] = true; };
+                };
+
+                var ths = document.getElementById(fdTableSort.tableId).getElementsByTagName("th");
+                for(var i = 0, th; th = ths[i]; i++) {
+                        found = false;
+                        for(var z = 0, n; n = dataObj.thList[z]; z++) {
+                                if(n == th) {
+                                        found = true;
+                                        break;
+                                };
+                        };
+                        if(!found) {
+                                fdTableSort.removeClass(th, "(forwardSort|reverseSort)");
+                                if(!dataObj.noArrow) {
+                                        span = th.getElementsByTagName('span');
+                                        if(span.length) {
+                                                span = span[0];
+                                                while(span.firstChild) span.removeChild(span.firstChild);
+                                        };
+                                };
+                        };
+                };
+
+                if(dataObj.thList.length > 1) {
+                        classToAdd = fdTableSort.thNode.className.search(/forwardSort/) != -1 ? "reverseSort" : "forwardSort";
+                        fdTableSort.removeClass(fdTableSort.thNode, "(forwardSort|reverseSort)");
+                        fdTableSort.addClass(fdTableSort.thNode, classToAdd);
+                        dataObj.pos = -1
+                } else if(alt) { dataObj.pos = fdTableSort.thNode };
+        },
+        initSort: function(noCallback, ident) {
+                var thNode      = fdTableSort.thNode;
+                var tableElem   = document.getElementById(fdTableSort.tableId);
+
+                if(!(fdTableSort.tableId in fdTableSort.tableCache)) { fdTableSort.prepareTableData(document.getElementById(fdTableSort.tableId)); };
+
+                fdTableSort.addThNode();
+
+                if(!noCallback) { fdTableSort.doCallback(true); };
+
+                fdTableSort.pos = thNode.className.match(/fd-column-([0-9]+)/)[1];
+                var dataObj     = fdTableSort.tableCache[tableElem.id];
+                var lastPos     = dataObj.pos && dataObj.pos.className ? dataObj.pos.className.match(/fd-column-([0-9]+)/)[1] : -1;
+                var len1        = dataObj.data.length;
+                var len2        = dataObj.data.length > 0 ? dataObj.data[0].length - 1 : 0;
+                var identical   = dataObj.identical[fdTableSort.pos];
+                var classToAdd  = "forwardSort";
+
+                if(dataObj.thList.length > 1) {
+                        var js  = "var sortWrapper = function(a,b) {\n";
+                        var l   = dataObj.thList.length;
+                        var cnt = 0;
+                        var e,d,th,p,f;
+
+                        for(var i=0; i < l; i++) {
+                                th = dataObj.thList[i];
+                                p  = th.className.match(/fd-column-([0-9]+)/)[1];
+                                if(dataObj.identical[p]) { continue; };
+                                cnt++;
+
+                                if(th.className.match(/sortable-(numeric|currency|date|keep)/)) {
+                                        f = "fdTableSort.sortNumeric";
+                                } else if(th.className.match('sortable-text')) {
+                                        f = "fdTableSort.sortText";
+                                } else if(th.className.search(/sortable-([a-zA-Z\_]+)/) != -1 && th.className.match(/sortable-([a-zA-Z\_]+)/)[1] in window) {
+                                        f = "window['" + th.className.match(/sortable-([a-zA-Z\_]+)/)[1] + "']";
+                                } else  f = "fdTableSort.sortText";
+
+                                e = "e" + i;
+                                d = th.className.search('forwardSort') != -1 ? "a,b" : "b,a";
+                                js += "fdTableSort.pos   = " + p + ";\n";
+                                js += "var " + e + " = "+f+"(" + d +");\n";
+                                js += "if(" + e + ") return " + e + ";\n";
+                                js += "else { \n";
+                        };
+
+                        js += "return 0;\n";
+
+                        for(var i=0; i < cnt; i++) {
+                                js += "};\n";
+                        };
+
+                        if(cnt) js += "return 0;\n";
+                        js += "};\n";
+
+                        eval(js);
+                        dataObj.data.sort(sortWrapper);
+                        identical = false;
+                } else if((lastPos == fdTableSort.pos && !identical) || (thNode.className.search(/sortable-keep/) != -1 && lastPos == -1)) {
+                        dataObj.data.reverse();
+                        classToAdd = thNode.className.search(/reverseSort/) != -1 ? "forwardSort" : "reverseSort";
+                        if(thNode.className.search(/sortable-keep/) != -1 && lastPos == -1) fdTableSort.tableCache[tableElem.id].pos = thNode;
+                } else {
+                        fdTableSort.tableCache[tableElem.id].pos = thNode;
+                        classToAdd = thNode.className.search(/forwardSort/) != -1 ? "reverseSort" : "forwardSort";
+                        if(!identical) {
+                                if(thNode.className.match(/sortable-(numeric|currency|date|keep)/)) {
+                                        dataObj.data.sort(fdTableSort.sortNumeric);
+                                } else if(thNode.className.match('sortable-text')) {
+                                        dataObj.data.sort(fdTableSort.sortText);
+                                } else if(thNode.className.search(/sortable-([a-zA-Z\_]+)/) != -1 && thNode.className.match(/sortable-([a-zA-Z\_]+)/)[1] in window) {
+                                        dataObj.data.sort(window[thNode.className.match(/sortable-([a-zA-Z\_]+)/)[1]]);
+                                };
+
+                                if(thNode.className.search(/(^|\s)favour-reverse($|\s)/) != -1) {
+                                        classToAdd = classToAdd == "forwardSort" ? "reverseSort" : "forwardSort";
+                                        dataObj.data.reverse();
+                                };
+                        };
+                };
+                if(ident) { identical = false; };
+                if(dataObj.thList.length == 1) {
+                        fdTableSort.removeClass(thNode, "(forwardSort|reverseSort)");
+                        fdTableSort.addClass(thNode, classToAdd);
+                };
+                if(!dataObj.noArrow) {
+                        var span = fdTableSort.thNode.getElementsByTagName('span')[0];
+                        if(span.firstChild) span.removeChild(span.firstChild);
+                        span.appendChild(document.createTextNode(fdTableSort.thNode.className.search(/forwardSort/) != -1 ? " \u2193" : " \u2191"));
+                };
+                if(!dataObj.rowStyle && !dataObj.colStyle && identical) {
+                        fdTableSort.removeSortActiveClass();
+                        if(!noCallback) { fdTableSort.doCallback(false); };
+                        fdTableSort.thNode = null;
+                        return;
+                };
+                if("tablePaginater" in window && tablePaginater.tableIsPaginated(fdTableSort.tableId)) {
+                        tablePaginater.redraw(fdTableSort.tableId, identical);
+                } else {
+                        fdTableSort.redraw(fdTableSort.tableId, identical);
+                };
+                fdTableSort.removeSortActiveClass();
+                if(!noCallback) { fdTableSort.doCallback(false); };
+                fdTableSort.thNode = null;
+        },
+        redraw: function(tableid, identical) {
+                if(!tableid || !(tableid in fdTableSort.tableCache)) { return; };
+                var dataObj     = fdTableSort.tableCache[tableid];
+                var data        = dataObj.data;
+                var len1        = data.length;
+                var len2        = len1 ? data[0].length - 1 : 0;
+                var hook        = dataObj.hook;
+                var colStyle    = dataObj.colStyle;
+                var rowStyle    = dataObj.rowStyle;
+                var colOrder    = dataObj.colOrder;
+                var highLight   = 0;
+                var reg         = /(^|\s)invisibleRow(\s|$)/;
+                var tr, tds;
+
+                for(var i = 0; i < len1; i++) {
+                        tr = data[i][len2];
+                        if(colStyle) {
+                                tds = tr.cells;
+                                for(thPos in colOrder) {
+                                        if(!colOrder[thPos]) fdTableSort.removeClass(tds[thPos], colStyle);
+                                        else fdTableSort.addClass(tds[thPos], colStyle);
+                                };
+                        };
+                        if(!identical) {
+                                if(rowStyle && tr.className.search(reg) == -1) {
+                                        if(highLight++ & 1) fdTableSort.addClass(tr, rowStyle);
+                                        else fdTableSort.removeClass(tr, rowStyle);
+                                };
+
+                                // Netscape 8.1.2 requires the removeChild call or it freaks out, so add the line if you want to support this browser
+                                // hook.removeChild(tr);
+                                hook.appendChild(tr);
+                        };
+                };
+                tr = tds = hook = null;
+        },
+        getInnerText: function(el, allowBrTags) {
+                if (typeof el == "string" || typeof el == "undefined") return el;
+                if(el.innerText) return el.innerText;
+                var txt = '', i;
+                for(i = el.firstChild; i; i = i.nextSibling) {
+                        if(allowBrTags && i.nodeName && i.nodeName == "BR") txt += "<br />";
+                        else if(i.nodeType == 3)       txt += i.nodeValue;
+                        else if(i.nodeType == 1)       txt += fdTableSort.getInnerText(i);
+                };
+                return txt;
+        },
+        dateFormat: function(dateIn, favourDMY) {
+                var dateTest = [
+                        { regExp:/^(0?[1-9]|1[012])([- \/.])(0?[1-9]|[12][0-9]|3[01])([- \/.])((\d\d)?\d\d)$/, d:3, m:1, y:5 },  // mdy
+                        { regExp:/^(0?[1-9]|[12][0-9]|3[01])([- \/.])(0?[1-9]|1[012])([- \/.])((\d\d)?\d\d)$/, d:1, m:3, y:5 },  // dmy
+                        { regExp:/^(\d\d\d\d)([- \/.])(0?[1-9]|1[012])([- \/.])(0?[1-9]|[12][0-9]|3[01])$/, d:5, m:3, y:1 }      // ymd
+                        ];
+                var start, cnt = 0, numFormats = dateTest.length;
+                while(cnt < numFormats) {
+                        start = (cnt + (favourDMY ? numFormats + 1 : numFormats)) % numFormats;
+                        if(dateIn.match(dateTest[start].regExp)) {
+                                res = dateIn.match(dateTest[start].regExp);
+                                y = res[dateTest[start].y];
+                                m = res[dateTest[start].m];
+                                d = res[dateTest[start].d];
+                                if(m.length == 1) m = "0" + String(m);
+                                if(d.length == 1) d = "0" + String(d);
+                                if(y.length != 4) y = (parseInt(y) < 50) ? "20" + String(y) : "19" + String(y);
+
+                                return y+String(m)+d;
+                        };
+                        cnt++;
+                };
+                return 0;
+        },
+        sortNumeric:function(a,b) {
+                var aa = a[fdTableSort.pos];
+                var bb = b[fdTableSort.pos];
+                if(aa == bb) return 0;
+                if(aa === "" && !isNaN(bb)) return -1;
+                if(bb === "" && !isNaN(aa)) return 1;
+                return aa - bb;
+        },
+        sortText:function(a,b) {
+                var aa = a[fdTableSort.pos];
+                var bb = b[fdTableSort.pos];
+                if(aa == bb) return 0;
+                if(aa < bb)  return -1;
+                return 1;
+        }
+};
+})();
+fdTableSort.addEvent(window, "load",   fdTableSort.initEvt);
+fdTableSort.addEvent(window, "unload", fdTableSort.onUnload);