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