Quelltext der Datei: http://www.michaelster.ch/jsTestFolder/css/tablesort.js

Dateigrösse: 41.02 kb

[Anzeige ohne Zeilennummern]


  1 /*
  2         TableSort revisited v4.9 by frequency-decoder.com
  3 
  4         Released under a creative commons Attribution-ShareAlike 2.5 license (http://creativecommons.org/licenses/by-sa/2.5/)
  5 
  6         Please credit frequency decoder in any derivative work - thanks
  7 
  8         You are free:
  9 
 10         * to copy, distribute, display, and perform the work
 11         * to make derivative works
 12         * to make commercial use of the work
 13 
 14         Under the following conditions:
 15 
 16                 by Attribution.
 17                 --------------
 18                 You must attribute the work in the manner specified by the author or licensor.
 19 
 20                 sa
 21                 --
 22                 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.
 23 
 24         * For any reuse or distribution, you must make clear to others the license terms of this work.
 25         * Any of these conditions can be waived if you get permission from the copyright holder.
 26 */
 27 
 28 (function() {
 29 fdTableSort = {
 30         regExp_Currency:        /^[£$€¥¤]/,
 31         regExp_Number:          /^(\-)?[0-9]+(\.[0-9]*)?$/,
 32         pos:                    -1,
 33         uniqueHash:             1,
 34         thNode:                 null,
 35         tableId:                null,
 36         tableCache:             {},
 37         tmpCache:               {},
 38         sortActiveClass:        "sort-active",
 39         /*@cc_on
 40         /*@if (@_win32)
 41         colspan:                "colSpan",
 42         rowspan:                "rowSpan",
 43         @else @*/
 44         colspan:                "colspan",
 45         rowspan:                "rowspan",
 46         /*@end
 47         @*/
 48         addEvent: function(obj, type, fn, tmp) {
 49                 tmp || (tmp = true);
 50                 if( obj.attachEvent ) {
 51                         obj["e"+type+fn] = fn;
 52                         obj[type+fn] = function(){obj["e"+type+fn]( window.event );};
 53                         obj.attachEvent( "on"+type, obj[type+fn] );
 54                 } else {
 55                         obj.addEventListener( type, fn, true );
 56                 };
 57         },
 58         removeEvent: function(obj, type, fn, tmp) {
 59                 tmp || (tmp = true);
 60                 try {
 61                         if( obj.detachEvent ) {
 62                                 obj.detachEvent( "on"+type, obj[type+fn] );
 63                                 obj[type+fn] = null;
 64                         } else {
 65                                 obj.removeEventListener( type, fn, true );
 66                         };
 67                 } catch(err) {};
 68         },
 69         stopEvent: function(e) {
 70                 e = e || window.event;
 71 
 72                 if(e.stopPropagation) {
 73                         e.stopPropagation();
 74                         e.preventDefault();
 75                 };
 76                 /*@cc_on@*/
 77                 /*@if(@_win32)
 78                 e.cancelBubble = true;
 79                 e.returnValue  = false;
 80                 /*@end@*/
 81                 return false;
 82         },
 83         parseClassName: function(head, tbl) {
 84                 var colMatch = tbl.className.match(new RegExp(head + "((-[\\d]+([r]){0,1})+)"));
 85                 return colMatch && colMatch.length ? colMatch[0].replace(head, "").split("-") : [];
 86         },
 87         disableSelection: function(element) {
 88                 element.onselectstart = function() {
 89                         return false;
 90                 };
 91                 element.unselectable = "on";
 92                 element.style.MozUserSelect = "none";
 93         },
 94         removeTableCache: function(tableId) {
 95                 if(!(tableId in fdTableSort.tableCache)) return;
 96 
 97                 fdTableSort.tableCache[tableId] = null;
 98                 delete fdTableSort.tableCache[tableId];
 99 
100                 var tbl = document.getElementById(tableId);
101                 if(!tbl) return;
102                 var ths = tbl.getElementsByTagName("th");
103                 var a;
104                 for(var i = 0, th; th = ths[i]; i++) {
105                         a = th.getElementsByTagName("a");
106                         if(a.length) a[0].onkeydown = a[0].onclick = null;
107                         th.onclick = th.onselectstart = th = a = null;
108                 };
109         },
110         removeTmpCache: function(tableId) {
111                 if(!(tableId in fdTableSort.tmpCache)) return;
112                 var headers = fdTableSort.tmpCache[tableId].headers;
113                 var a;
114                 for(var i = 0, row; row = headers[i]; i++) {
115                         for(var j = 0, th; th = row[j]; j++) {
116                                 a = th.getElementsByTagName("a");
117                                 if(a.length) a[0].onkeydown = a[0].onclick = null;
118                                 th.onclick = th.onselectstart = th = a = null;
119                         };
120                 };
121                 fdTableSort.tmpCache[tableId] = null;
122                 delete fdTableSort.tmpCache[tableId];
123         },
124         initEvt: function(e) {
125                 fdTableSort.init(false);
126         },
127         init: function(tableId) {
128                 if (!document.getElementsByTagName || !document.createElement || !document.getElementById) return;
129 
130                 var tables = tableId && document.getElementById(tableId) ? [document.getElementById(tableId)] : document.getElementsByTagName("table");
131                 var c, ii, len, colMatch, showOnly, match, showArrow, columnNumSortObj, obj, workArr, headers, thtext, aclone, multi, colCnt, cel, allRowArr, rowArr, sortableTable, celCount, colspan, rowspan, rowLength;
132 
133                 var a          = document.createElement("a");
134                 a.href         = "#";
135                 a.className    = "fdTableSortTrigger";
136 
137                 var span       = document.createElement("span");
138 
139                 for(var k = 0, tbl; tbl = tables[k]; k++) {
140 
141                         if(tbl.id) {
142                                 fdTableSort.removeTableCache(tbl.id);
143                                 fdTableSort.removeTmpCache(tbl.id);
144                         };
145 
146                         allRowArr     = tbl.getElementsByTagName('thead').length ? tbl.getElementsByTagName('thead')[0].getElementsByTagName('tr') : tbl.getElementsByTagName('tr');
147                         rowArr        = [];
148                         sortableTable = false;
149 
150                         for(var i = 0, tr; tr = allRowArr[i]; i++) {
151                                 if(tr.getElementsByTagName('td').length || !tr.getElementsByTagName('th').length) { continue; };
152                                 rowArr[rowArr.length] = tr.getElementsByTagName('th');
153                                 for(var j = 0, th; th = rowArr[rowArr.length - 1][j]; j++) {
154                                         if(th.className.search(/sortable/) != -1) { sortableTable = true; };
155                                 };
156                         };
157 
158                         if(!sortableTable) continue;
159 
160                         if(!tbl.id) { tbl.id = "fd-table-" + fdTableSort.uniqueHash++; };
161 
162                         showArrow   = tbl.className.search("no-arrow") == -1;
163                         showOnly    = tbl.className.search("sortable-onload-show") != -1;
164 
165                         columnNumSortObj = {};
166                         colMatch         = fdTableSort.parseClassName(showOnly ? "sortable-onload-show" : "sortable-onload", tbl);
167                         for(match = 1; match < colMatch.length; match++) {
168                                 columnNumSortObj[parseInt(colMatch[match], 10)] = { "reverse":colMatch[match].search("r") != -1 };
169                         };
170 
171                         rowLength = rowArr[0].length;
172 
173                         for(c = 0;c < rowArr[0].length;c++){
174                                 if(rowArr[0][c].getAttribute(fdTableSort.colspan) && rowArr[0][c].getAttribute(fdTableSort.colspan) > 1){
175                                         rowLength = rowLength + (rowArr[0][c].getAttribute(fdTableSort.colspan) - 1);
176                                 };
177                         };
178 
179                         workArr = new Array(rowArr.length);
180                         for(c = rowArr.length;c--;){ workArr[c]= new Array(rowLength); };
181 
182                         for(c = 0;c < workArr.length;c++){
183                                 celCount = 0;
184                                 for(i = 0;i < rowLength;i++){
185                                         if(!workArr[c][i]){
186                                                 cel = rowArr[c][celCount];
187                                                 colspan = (cel.getAttribute(fdTableSort.colspan) > 1) ? cel.getAttribute(fdTableSort.colspan):1;
188                                                 rowspan = (cel.getAttribute(fdTableSort.rowspan) > 1) ? cel.getAttribute(fdTableSort.rowspan):1;
189                                                 for(var t = 0;((t < colspan)&&((i+t) < rowLength));t++){
190                                                         for(var n = 0;((n < rowspan)&&((c+n) < workArr.length));n++) {
191                                                                 workArr[(c+n)][(i+t)] = cel;
192                                                         };
193                                                 };
194                                                 if(++celCount == rowArr[c].length) break;
195                                         };
196                                 };
197                         };
198 
199                         for(c = 0;c < workArr.length;c++) {
200                                 for(i = 0;i < workArr[c].length;i++){
201 
202                                         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;
203 
204                                         if(workArr[c][i].className.match('sortable')) {
205                                                 workArr[c][i].className = workArr[c][i].className.replace(/forwardSort|reverseSort/, "");
206 
207                                                 if(i in columnNumSortObj) {
208                                                         columnNumSortObj[i]["thNode"] = workArr[c][i];
209                                                         columnNumSortObj["active"] = true;
210                                                 };
211 
212                                                 thtext = fdTableSort.getInnerText(workArr[c][i]);
213 
214                                                 for(var cn = workArr[c][i].childNodes.length; cn--;) {
215                                                         // Skip image nodes and links created by the filter script.
216                                                         if(workArr[c][i].childNodes[cn].nodeType == 1 && (workArr[c][i].childNodes[cn].className == "fdFilterTrigger" || /img/i.test(workArr[c][i].childNodes[cn].nodeName))) {
217                                                                 continue;
218                                                         };
219                                                         if(workArr[c][i].childNodes[cn].nodeType == 1 && /^a$/i.test(workArr[c][i].childNodes[cn].nodeName)) {
220                                                                 workArr[c][i].childNodes[cn].onclick = workArr[c][i].childNodes[cn].onkeydown = null;
221                                                         };
222                                                         workArr[c][i].removeChild(workArr[c][i].childNodes[cn]);
223                                                 };
224 
225                                                 aclone = a.cloneNode(true);
226                                                 aclone.appendChild(document.createTextNode(thtext));
227                                                 aclone.title = "Sort on \u201c" + thtext + "\u201d";
228                                                 aclone.onclick = aclone.onkeydown = workArr[c][i].onclick = fdTableSort.initWrapper;
229                                                 workArr[c][i].appendChild(aclone);
230                                                 if(showArrow) workArr[c][i].appendChild(span.cloneNode(false));
231                                                 workArr[c][i].className = workArr[c][i].className.replace(/fd-identical|fd-not-identical/, "");
232                                                 fdTableSort.disableSelection(workArr[c][i]);
233                                                 aclone = null;
234                                         };
235                                 };
236                         };
237 
238                         fdTableSort.tmpCache[tbl.id] = {cols:rowLength, headers:workArr};
239 
240                         workArr = null;
241                         multi   = 0;
242 
243                         if("active" in columnNumSortObj) {
244                                 fdTableSort.tableId = tbl.id;
245                                 fdTableSort.prepareTableData(document.getElementById(fdTableSort.tableId));
246 
247                                 delete columnNumSortObj["active"];
248 
249                                 for(col in columnNumSortObj) {
250                                         obj = columnNumSortObj[col];
251                                         if(!("thNode" in obj)) { continue; };
252                                         fdTableSort.multi = true;
253 
254                                         len = obj.reverse ? 2 : 1;
255 
256                                         for(ii = 0; ii < len; ii++) {
257                                                 fdTableSort.thNode = obj.thNode;
258                                                 if(!showOnly) {
259                                                         fdTableSort.initSort(false, true);
260                                                 } else {
261                                                         fdTableSort.addThNode();
262                                                 };
263                                         };
264 
265                                         if(showOnly) {
266                                                 fdTableSort.removeClass(obj.thNode, "(forwardSort|reverseSort)");
267                                                 fdTableSort.addClass(obj.thNode, obj.reverse ? "reverseSort" : "forwardSort");
268                                                 if(showArrow) {
269                                                         span = fdTableSort.thNode.getElementsByTagName('span')[0];
270                                                         if(span.firstChild) { span.removeChild(span.firstChild); };
271                                                         span.appendChild(document.createTextNode(len == 1 ? " \u2193" : " \u2191"));
272                                                 };
273                                         };
274                                 };
275                                 if(showOnly && (fdTableSort.tableCache[tbl.id].colStyle || fdTableSort.tableCache[tbl.id].rowStyle)) {
276                                         fdTableSort.redraw(tbl.id, false);
277                                 };
278                         } else if(tbl.className.search(/onload-zebra/) != -1) {
279                                 fdTableSort.tableId = tbl.id;
280                                 fdTableSort.prepareTableData(tbl);
281                                 if(fdTableSort.tableCache[tbl.id].rowStyle) { fdTableSort.redraw(tbl.id, false); };
282                         };
283                 };
284 
285                 fdTableSort.thNode = aclone = a = span = columnNumSortObj = thNode = tbl = allRowArr = rowArr = null;
286         },
287         initWrapper: function(e) {
288                 e = e || window.event;
289                 var kc = e.type == "keydown" ? e.keyCode != null ? e.keyCode : e.charCode : -1;
290                 if(fdTableSort.thNode == null && (e.type == "click" || kc == 13)) {
291                         var targ = this;
292                         while(targ.tagName.toLowerCase() != "th") { targ = targ.parentNode; };
293                         fdTableSort.thNode = targ;
294                         while(targ.tagName.toLowerCase() != "table") { targ = targ.parentNode; };
295                         fdTableSort.tableId = targ.id;
296                         fdTableSort.multi = e.shiftKey;
297                         fdTableSort.addSortActiveClass();
298                         setTimeout(fdTableSort.initSort,5,false);
299                         return fdTableSort.stopEvent(e);
300                 };
301                 return kc != -1 ? true : fdTableSort.stopEvent(e);
302         },
303         jsWrapper: function(tableid, colNums) {
304                 if(!(tableid in fdTableSort.tmpCache)) { return false; };
305                 if(!(tableid in fdTableSort.tableCache)) { fdTableSort.prepareTableData(document.getElementById(tableid)); };
306                 if(!(colNums instanceof Array)) { colNums = [colNums]; };
307 
308                 fdTableSort.tableId = tableid;
309                 var len = colNums.length, colNum;
310 
311                 if(fdTableSort.tableCache[tableid].thList.length == colNums.length) {
312                         var identical = true;
313                         var th;
314                         for(var i = 0; i < len; i++) {
315                                 colNum = colNums[i];
316                                 th = fdTableSort.tmpCache[tableid].headers[0][colNum];
317                                 if(th != fdTableSort.tableCache[tableid].thList[i]) {
318                                         identical = false;
319                                         break;
320                                 };
321                         };
322                         if(identical) {
323                                 fdTableSort.thNode = th;
324                                 fdTableSort.initSort(true);
325                                 return;
326                         };
327                 };
328 
329                 fdTableSort.addSortActiveClass();
330 
331                 for(var i = 0; i < len; i++) {
332                         fdTableSort.multi = i;
333                         colNum = colNums[i];
334                         fdTableSort.thNode = fdTableSort.tmpCache[tableid].headers[0][colNum];
335                         fdTableSort.initSort(true);
336                 };
337         },
338         addSortActiveClass: function() {
339                 if(fdTableSort.thNode == null) { return; };
340                 fdTableSort.addClass(fdTableSort.thNode, fdTableSort.sortActiveClass);
341                 fdTableSort.addClass(document.getElementsByTagName('body')[0], fdTableSort.sortActiveClass);
342         },
343         removeSortActiveClass: function() {
344                 if(fdTableSort.thNode == null) return;
345                 fdTableSort.removeClass(fdTableSort.thNode, fdTableSort.sortActiveClass);
346                 fdTableSort.removeClass(document.getElementsByTagName('body')[0], fdTableSort.sortActiveClass);
347         },
348         doCallback: function(init) {
349                 if(!fdTableSort.tableId || !(fdTableSort.tableId in fdTableSort.tableCache)) { return; };
350                 fdTableSort.callback(fdTableSort.tableId, init ? fdTableSort.tableCache[fdTableSort.tableId].initiatedCallback : fdTableSort.tableCache[fdTableSort.tableId].completeCallback);
351         },
352         addClass: function(e,c) {
353                 if(new RegExp("(^|\\s)" + c + "(\\s|$)").test(e.className)) { return; };
354                 e.className += ( e.className ? " " : "" ) + c;
355         },
356         /*@cc_on
357         /*@if (@_win32)
358         removeClass: function(e,c) {
359                 e.className = !c ? "" : e.className.replace(new RegExp("(^|\\s)" + c + "(\\s|$)"), " ").replace(/^\s*((?:[\S\s]*\S)?)\s*$/, '$1');
360         },
361         @else @*/
362         removeClass: function(e,c) {
363                 e.className = !c ? "" : e.className.replace(new RegExp("(^|\\s)" + c + "(\\s|$)"), " ").replace(/^\s\s*/, '').replace(/\s\s*$/, '');
364         },
365         /*@end
366         @*/
367         callback: function(tblId, cb) {
368                 var func;
369                 if(cb.indexOf(".") != -1) {
370                         var split = cb.split(".");
371                         func = window;
372                         for(var i = 0, f; f = split[i]; i++) {
373                                 if(f in func) {
374                                         func = func[f];
375                                 } else {
376                                         func = "";
377                                         break;
378                                 };
379                         };
380                 } else if(cb + tblId in window) {
381                         func = window[cb + tblId];
382                 } else if(cb in window) {
383                         func = window[cb];
384                 };
385                 if(typeof func == "function") { func(tblId, fdTableSort.tableCache[tblId].thList); };
386                 func = null;
387         },
388         prepareTableData: function(table) {
389                 var data = [];
390 
391                 var start = table.getElementsByTagName('tbody');
392                 start = start.length ? start[0] : table;
393 
394                 var trs = start.rows;
395                 var ths = table.getElementsByTagName('th');
396 
397                 var numberOfRows = trs.length;
398                 var numberOfCols = fdTableSort.tmpCache[table.id].cols;
399 
400                 var data = [];
401                 var identical = new Array(numberOfCols);
402                 var identVal  = new Array(numberOfCols);
403 
404                 for(var tmp = 0; tmp < numberOfCols; tmp++) identical[tmp] = true;
405 
406                 var tr, td, th, txt, tds, col, row;
407 
408                 var re = new RegExp(/fd-column-([0-9]+)/);
409                 var rowCnt = 0;
410 
411                 var sortableColumnNumbers = [];
412 
413                 for(var tmp = 0, th; th = ths[tmp]; tmp++) {
414                         if(th.className.search(re) == -1) continue;
415                         sortableColumnNumbers[sortableColumnNumbers.length] = th;
416                 };
417 
418                 for(row = 0; row < numberOfRows; row++) {
419 
420                         tr              = trs[row];
421                         if(tr.parentNode != start || tr.getElementsByTagName("th").length || (tr.parentNode && tr.parentNode.tagName.toLowerCase().search(/thead|tfoot/) != -1)) continue;
422                         data[rowCnt]    = [];
423                         tds             = tr.cells;
424 
425                         for(var tmp = 0, th; th = sortableColumnNumbers[tmp]; tmp++) {
426                                 col = th.className.match(re)[1];
427 
428                                 td  = tds[col];
429                                 txt = fdTableSort.getInnerText(td) + " ";
430                                 txt = txt.replace(/^\s+/,'').replace(/\s+$/,'');
431 
432                                 if(th.className.search(/sortable-date/) != -1) {
433                                         txt = fdTableSort.dateFormat(txt, th.className.search(/sortable-date-dmy/) != -1);
434                                 } else if(th.className.search(/sortable-numeric|sortable-currency/) != -1) {
435                                         txt = parseFloat(txt.replace(/[^0-9\.\-]/g,''));
436                                         if(isNaN(txt)) txt = "";
437                                 } else if(th.className.search(/sortable-text/) != -1) {
438                                         txt = txt.toLowerCase();
439                                 } else if (th.className.search(/sortable-keep/) != -1) {
440                                         txt = rowCnt;
441                                 } else if(th.className.search(/sortable-([a-zA-Z\_]+)/) != -1) {
442                                         if((th.className.match(/sortable-([a-zA-Z\_]+)/)[1] + "PrepareData") in window) {
443                                                 txt = window[th.className.match(/sortable-([a-zA-Z\_]+)/)[1] + "PrepareData"](td, txt);
444                                         };
445                                 } else if(txt != "") {
446                                         fdTableSort.removeClass(th, "sortable");
447                                         if(fdTableSort.dateFormat(txt) != 0) {
448                                                 fdTableSort.addClass(th, "sortable-date");
449                                                 txt = fdTableSort.dateFormat(txt);
450                                         } else if(txt.search(fdTableSort.regExp_Number) != -1 || txt.search(fdTableSort.regExp_Currency) != -1) {
451                                                 fdTableSort.addClass(th, "sortable-numeric");
452                                                 txt = parseFloat(txt.replace(/[^0-9\.\-]/g,''));
453                                                 if(isNaN(txt)) txt = "";
454                                         } else {
455                                                 fdTableSort.addClass(th, "sortable-text");
456                                                 txt = txt.toLowerCase();
457                                         };
458                                 };
459 
460                                 if(rowCnt > 0 && identical[col] && identVal[col] != txt) { identical[col] = false; };
461 
462                                 identVal[col]     = txt;
463                                 data[rowCnt][col] = txt;
464                         };
465                         data[rowCnt][numberOfCols] = tr;
466                         rowCnt++;
467                 };
468 
469                 var colStyle = table.className.search(/colstyle-([\S]+)/) != -1 ? table.className.match(/colstyle-([\S]+)/)[1] : false;
470                 var rowStyle = table.className.search(/rowstyle-([\S]+)/) != -1 ? table.className.match(/rowstyle-([\S]+)/)[1] : false;
471                 var iCBack   = table.className.search(/sortinitiatedcallback-([\S-]+)/) == -1 ? "sortInitiatedCallback" : table.className.match(/sortinitiatedcallback-([\S]+)/)[1];
472                 var cCBack   = table.className.search(/sortcompletecallback-([\S-]+)/) == -1 ? "sortCompleteCallback" : table.className.match(/sortcompletecallback-([\S]+)/)[1];
473                 iCBack = iCBack.replace("-", ".");
474                 cCBack = cCBack.replace("-", ".");
475                 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 };
476                 sortableColumnNumbers = data = tr = td = th = trs = identical = identVal = null;
477         },
478         onUnload: function() {
479                 for(tbl in fdTableSort.tableCache) { fdTableSort.removeTableCache(tbl); };
480                 for(tbl in fdTableSort.tmpCache) { fdTableSort.removeTmpCache(tbl); };
481                 fdTableSort.removeEvent(window, "load", fdTableSort.initEvt);
482                 fdTableSort.removeEvent(window, "unload", fdTableSort.onUnload);
483                 fdTableSort.tmpCache = fdTableSort.tableCache = null;
484         },
485         addThNode: function() {
486                 var dataObj = fdTableSort.tableCache[fdTableSort.tableId];
487                 var pos     = fdTableSort.thNode.className.match(/fd-column-([0-9]+)/)[1];
488                 var alt     = false;
489 
490                 if(!fdTableSort.multi) {
491                         if(dataObj.colStyle) {
492                                 var len = dataObj.thList.length;
493                                 for(var i = 0; i < len; i++) {
494                                   dataObj.colOrder[dataObj.thList[i].className.match(/fd-column-([0-9]+)/)[1]]=false;
495                                 };
496                         };
497                         if(dataObj.thList.length && dataObj.thList[0] == fdTableSort.thNode) alt = true;
498                         dataObj.thList = [];
499                 };
500 
501                 var found = false;
502                 var l = dataObj.thList.length;
503 
504                 for(var i = 0, n; n = dataObj.thList[i]; i++) {
505                         if(n == fdTableSort.thNode) {
506                                 found = true;
507                                 break;
508                         };
509                 };
510 
511                 if(!found) {
512                         dataObj.thList.push(fdTableSort.thNode);
513                         if(dataObj.colStyle) { dataObj.colOrder[pos] = true; };
514                 };
515 
516                 var ths = document.getElementById(fdTableSort.tableId).getElementsByTagName("th");
517                 for(var i = 0, th; th = ths[i]; i++) {
518                         found = false;
519                         for(var z = 0, n; n = dataObj.thList[z]; z++) {
520                                 if(n == th) {
521                                         found = true;
522                                         break;
523                                 };
524                         };
525                         if(!found) {
526                                 fdTableSort.removeClass(th, "(forwardSort|reverseSort)");
527                                 if(!dataObj.noArrow) {
528                                         span = th.getElementsByTagName('span');
529                                         if(span.length) {
530                                                 span = span[0];
531                                                 while(span.firstChild) span.removeChild(span.firstChild);
532                                         };
533                                 };
534                         };
535                 };
536 
537                 if(dataObj.thList.length > 1) {
538                         classToAdd = fdTableSort.thNode.className.search(/forwardSort/) != -1 ? "reverseSort" : "forwardSort";
539                         fdTableSort.removeClass(fdTableSort.thNode, "(forwardSort|reverseSort)");
540                         fdTableSort.addClass(fdTableSort.thNode, classToAdd);
541                         dataObj.pos = -1
542                 } else if(alt) { dataObj.pos = fdTableSort.thNode };
543         },
544         initSort: function(noCallback, ident) {
545                 var thNode      = fdTableSort.thNode;
546                 var tableElem   = document.getElementById(fdTableSort.tableId);
547 
548                 if(!(fdTableSort.tableId in fdTableSort.tableCache)) { fdTableSort.prepareTableData(document.getElementById(fdTableSort.tableId)); };
549 
550                 fdTableSort.addThNode();
551 
552                 if(!noCallback) { fdTableSort.doCallback(true); };
553 
554                 fdTableSort.pos = thNode.className.match(/fd-column-([0-9]+)/)[1];
555                 var dataObj     = fdTableSort.tableCache[tableElem.id];
556                 var lastPos     = dataObj.pos && dataObj.pos.className ? dataObj.pos.className.match(/fd-column-([0-9]+)/)[1] : -1;
557                 var len1        = dataObj.data.length;
558                 var len2        = dataObj.data.length > 0 ? dataObj.data[0].length - 1 : 0;
559                 var identical   = dataObj.identical[fdTableSort.pos];
560                 var classToAdd  = "forwardSort";
561 
562                 if(dataObj.thList.length > 1) {
563                         var js  = "var sortWrapper = function(a,b) {\n";
564                         var l   = dataObj.thList.length;
565                         var cnt = 0;
566                         var e,d,th,p,f;
567 
568                         for(var i=0; i < l; i++) {
569                                 th = dataObj.thList[i];
570                                 p  = th.className.match(/fd-column-([0-9]+)/)[1];
571                                 if(dataObj.identical[p]) { continue; };
572                                 cnt++;
573 
574                                 if(th.className.match(/sortable-(numeric|currency|date|keep)/)) {
575                                         f = "fdTableSort.sortNumeric";
576                                 } else if(th.className.match('sortable-text')) {
577                                         f = "fdTableSort.sortText";
578                                 } else if(th.className.search(/sortable-([a-zA-Z\_]+)/) != -1 && th.className.match(/sortable-([a-zA-Z\_]+)/)[1] in window) {
579                                         f = "window['" + th.className.match(/sortable-([a-zA-Z\_]+)/)[1] + "']";
580                                 } else  f = "fdTableSort.sortText";
581 
582                                 e = "e" + i;
583                                 d = th.className.search('forwardSort') != -1 ? "a,b" : "b,a";
584                                 js += "fdTableSort.pos   = " + p + ";\n";
585                                 js += "var " + e + " = "+f+"(" + d +");\n";
586                                 js += "if(" + e + ") return " + e + ";\n";
587                                 js += "else { \n";
588                         };
589 
590                         js += "return 0;\n";
591 
592                         for(var i=0; i < cnt; i++) {
593                                 js += "};\n";
594                         };
595 
596                         if(cnt) js += "return 0;\n";
597                         js += "};\n";
598 
599                         eval(js);
600                         dataObj.data.sort(sortWrapper);
601                         identical = false;
602                 } else if((lastPos == fdTableSort.pos && !identical) || (thNode.className.search(/sortable-keep/) != -1 && lastPos == -1)) {
603                         dataObj.data.reverse();
604                         classToAdd = thNode.className.search(/reverseSort/) != -1 ? "forwardSort" : "reverseSort";
605                         if(thNode.className.search(/sortable-keep/) != -1 && lastPos == -1) fdTableSort.tableCache[tableElem.id].pos = thNode;
606                 } else {
607                         fdTableSort.tableCache[tableElem.id].pos = thNode;
608                         classToAdd = thNode.className.search(/forwardSort/) != -1 ? "reverseSort" : "forwardSort";
609                         if(!identical) {
610                                 if(thNode.className.match(/sortable-(numeric|currency|date|keep)/)) {
611                                         dataObj.data.sort(fdTableSort.sortNumeric);
612                                 } else if(thNode.className.match('sortable-text')) {
613                                         dataObj.data.sort(fdTableSort.sortText);
614                                 } else if(thNode.className.search(/sortable-([a-zA-Z\_]+)/) != -1 && thNode.className.match(/sortable-([a-zA-Z\_]+)/)[1] in window) {
615                                         dataObj.data.sort(window[thNode.className.match(/sortable-([a-zA-Z\_]+)/)[1]]);
616                                 };
617 
618                                 if(thNode.className.search(/(^|\s)favour-reverse($|\s)/) != -1) {
619                                         classToAdd = classToAdd == "forwardSort" ? "reverseSort" : "forwardSort";
620                                         dataObj.data.reverse();
621                                 };
622                         };
623                 };
624                 if(ident) { identical = false; };
625                 if(dataObj.thList.length == 1) {
626                         fdTableSort.removeClass(thNode, "(forwardSort|reverseSort)");
627                         fdTableSort.addClass(thNode, classToAdd);
628                 };
629                 if(!dataObj.noArrow) {
630                         var span = fdTableSort.thNode.getElementsByTagName('span')[0];
631                         if(span.firstChild) span.removeChild(span.firstChild);
632                         span.appendChild(document.createTextNode(fdTableSort.thNode.className.search(/forwardSort/) != -1 ? " \u2193" : " \u2191"));
633                 };
634                 if(!dataObj.rowStyle && !dataObj.colStyle && identical) {
635                         fdTableSort.removeSortActiveClass();
636                         if(!noCallback) { fdTableSort.doCallback(false); };
637                         fdTableSort.thNode = null;
638                         return;
639                 };
640                 if("tablePaginater" in window && "tableInfo" in tablePaginater && fdTableSort.tableId in tablePaginater.tableInfo) {
641                         tablePaginater.redraw(fdTableSort.tableId, identical);
642                 } else {
643                         fdTableSort.redraw(fdTableSort.tableId, identical);
644                 };
645                 fdTableSort.removeSortActiveClass();
646                 if(!noCallback) { fdTableSort.doCallback(false); };
647                 fdTableSort.thNode = null;
648         },
649         redraw: function(tableid, identical) {
650                 if(!tableid || !(tableid in fdTableSort.tableCache)) { return; };
651                 var dataObj     = fdTableSort.tableCache[tableid];
652                 var data        = dataObj.data;
653                 var len1        = data.length;
654                 var len2        = len1 ? data[0].length - 1 : 0;
655                 var hook        = dataObj.hook;
656                 var colStyle    = dataObj.colStyle;
657                 var rowStyle    = dataObj.rowStyle;
658                 var colOrder    = dataObj.colOrder;
659                 var highLight   = 0;
660                 var reg         = /(^|\s)invisibleRow(\s|$)/;
661                 var tr, tds;
662 
663                 for(var i = 0; i < len1; i++) {
664                         tr = data[i][len2];
665                         if(colStyle) {
666                                 tds = tr.cells;
667                                 for(thPos in colOrder) {
668                                         if(!colOrder[thPos]) fdTableSort.removeClass(tds[thPos], colStyle);
669                                         else fdTableSort.addClass(tds[thPos], colStyle);
670                                 };
671                         };
672                         if(!identical) {
673                                 if(rowStyle && tr.className.search(reg) == -1) {
674                                         if(highLight++ & 1) fdTableSort.addClass(tr, rowStyle);
675                                         else fdTableSort.removeClass(tr, rowStyle);
676                                 };
677 
678                                 // Netscape 8.1.2 requires the removeChild call or it freaks out, so add the line if you want to support this browser
679                                 // hook.removeChild(tr);
680                                 hook.appendChild(tr);
681                         };
682                 };
683                 tr = tds = hook = null;
684         },
685         getInnerText: function(el) {
686                 if (typeof el == "string" || typeof el == "undefined") return el;
687                 if(el.innerText) return el.innerText;
688                 var txt = '', i;
689                 for(i = el.firstChild; i; i = i.nextSibling) {
690                         if(i.nodeType == 3)            txt += i.nodeValue;
691                         else if(i.nodeType == 1)       txt += fdTableSort.getInnerText(i);
692                 };
693                 return txt;
694         },
695         dateFormat: function(dateIn, favourDMY) {
696                 var dateTest = [
697                         { 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
698                         { 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
699                         { 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
700                         ];
701                 var start, cnt = 0, numFormats = dateTest.length;
702                 while(cnt < numFormats) {
703                         start = (cnt + (favourDMY ? numFormats + 1 : numFormats)) % numFormats;
704                         if(dateIn.match(dateTest[start].regExp)) {
705                                 res = dateIn.match(dateTest[start].regExp);
706                                 y = res[dateTest[start].y];
707                                 m = res[dateTest[start].m];
708                                 d = res[dateTest[start].d];
709                                 if(m.length == 1) m = "0" + String(m);
710                                 if(d.length == 1) d = "0" + String(d);
711                                 if(y.length != 4) y = (parseInt(y) < 50) ? "20" + String(y) : "19" + String(y);
712 
713                                 return y+String(m)+d;
714                         };
715                         cnt++;
716                 };
717                 return 0;
718         },
719         sortNumeric:function(a,b) {
720                 var aa = a[fdTableSort.pos];
721                 var bb = b[fdTableSort.pos];
722                 if(aa == bb) return 0;
723                 if(aa === "" && !isNaN(bb)) return -1;
724                 if(bb === "" && !isNaN(aa)) return 1;
725                 return aa - bb;
726         },
727         sortText:function(a,b) {
728                 var aa = a[fdTableSort.pos];
729                 var bb = b[fdTableSort.pos];
730                 if(aa == bb) return 0;
731                 if(aa < bb)  return -1;
732                 return 1;
733         }
734 };
735 })();
736 
737 fdTableSort.addEvent(window, "load",   fdTableSort.initEvt);
738 fdTableSort.addEvent(window, "unload", fdTableSort.onUnload);
739