2 TableSort revisited v5.0 by frequency-decoder.com
4 Released under a creative commons Attribution-ShareAlike 2.5 license (http://creativecommons.org/licenses/by-sa/2.5/)
6 Please credit frequency decoder in any derivative work - thanks
10 * to copy, distribute, display, and perform the work
11 * to make derivative works
12 * to make commercial use of the work
14 Under the following conditions:
18 You must attribute the work in the manner specified by the author or licensor.
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.
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.
32 regExp_Currency: /^[£$€¥¤]/,
33 regExp_Number: /^(\-)?[0-9]+(\.[0-9]*)?$/,
40 sortActiveClass: "sort-active",
51 addEvent: function(obj, type, fn, tmp) {
53 if( obj.attachEvent ) {
54 obj["e"+type+fn] = fn;
55 obj[type+fn] = function(){obj["e"+type+fn]( window.event );};
56 obj.attachEvent( "on"+type, obj[type+fn] );
58 obj.addEventListener( type, fn, true );
61 removeEvent: function(obj, type, fn, tmp) {
64 if( obj.detachEvent ) {
65 obj.detachEvent( "on"+type, obj[type+fn] );
68 obj.removeEventListener( type, fn, true );
72 stopEvent: function(e) {
73 e = e || window.event;
75 if(e.stopPropagation) {
82 e.cancelBubble = true;
83 e.returnValue = false;
87 parseClassName: function(head, tbl) {
88 var colMatch = tbl.className.match(new RegExp(head + "((-[\\d]+([r]){0,1})+)"));
89 return colMatch && colMatch.length ? colMatch[0].replace(head, "").split("-") : [];
91 disableSelection: function(element) {
92 element.onselectstart = function() {
95 element.unselectable = "on";
96 element.style.MozUserSelect = "none";
98 removeTableCache: function(tableId) {
99 if(!(tableId in fdTableSort.tableCache)) return;
101 fdTableSort.tableCache[tableId] = null;
102 delete fdTableSort.tableCache[tableId];
104 var tbl = document.getElementById(tableId);
106 var ths = tbl.getElementsByTagName("th");
108 for(var i = 0, th; th = ths[i]; i++) {
109 a = th.getElementsByTagName("a");
110 if(a.length) a[0].onkeydown = a[0].onclick = null;
111 th.onclick = th.onselectstart = th = a = null;
114 removeTmpCache: function(tableId) {
115 if(!(tableId in fdTableSort.tmpCache)) return;
116 var headers = fdTableSort.tmpCache[tableId].headers;
118 for(var i = 0, row; row = headers[i]; i++) {
119 for(var j = 0, th; th = row[j]; j++) {
120 a = th.getElementsByTagName("a");
121 if(a.length) a[0].onkeydown = a[0].onclick = null;
122 th.onclick = th.onselectstart = th = a = null;
125 fdTableSort.tmpCache[tableId] = null;
126 delete fdTableSort.tmpCache[tableId];
128 initEvt: function(e) {
129 fdTableSort.init(false);
131 init: function(tableId) {
132 if (debug) plc_message ('entering tablesort.init');
133 if (!document.getElementsByTagName || !document.createElement || !document.getElementById) return;
135 var tables = tableId && document.getElementById(tableId) ? [document.getElementById(tableId)] : document.getElementsByTagName("table");
136 var c, ii, len, colMatch, showOnly, match, showArrow, columnNumSortObj, obj, workArr, headers, thtext, aclone, multi, colCnt, cel, allRowArr, rowArr, sortableTable, celCount, colspan, rowspan, rowLength;
138 var a = document.createElement("a");
140 a.className = "fdTableSortTrigger";
142 var span = document.createElement("span");
144 for(var k = 0, tbl; tbl = tables[k]; k++) {
147 fdTableSort.removeTableCache(tbl.id);
148 fdTableSort.removeTmpCache(tbl.id);
151 allRowArr = tbl.getElementsByTagName('thead').length ? tbl.getElementsByTagName('thead')[0].getElementsByTagName('tr') : tbl.getElementsByTagName('tr');
153 sortableTable = false;
155 for(var i = 0, tr; tr = allRowArr[i]; i++) {
156 if(tr.getElementsByTagName('td').length || !tr.getElementsByTagName('th').length) { continue; };
157 rowArr[rowArr.length] = tr.getElementsByTagName('th');
158 for(var j = 0, th; th = rowArr[rowArr.length - 1][j]; j++) {
159 if(th.className.search(/sortable/) != -1) { sortableTable = true; };
163 if(!sortableTable) continue;
165 if(!tbl.id) { tbl.id = "fd-table-" + fdTableSort.uniqueHash++; };
167 showArrow = tbl.className.search("no-arrow") == -1;
168 showOnly = tbl.className.search("sortable-onload-show") != -1;
170 columnNumSortObj = {};
171 colMatch = fdTableSort.parseClassName(showOnly ? "sortable-onload-show" : "sortable-onload", tbl);
172 for(match = 1; match < colMatch.length; match++) {
173 columnNumSortObj[parseInt(colMatch[match], 10)] = { "reverse":colMatch[match].search("r") != -1 };
176 rowLength = rowArr[0].length;
178 for(c = 0;c < rowArr[0].length;c++){
179 if(rowArr[0][c].getAttribute(fdTableSort.colspan) && rowArr[0][c].getAttribute(fdTableSort.colspan) > 1){
180 rowLength = rowLength + (rowArr[0][c].getAttribute(fdTableSort.colspan) - 1);
184 workArr = new Array(rowArr.length);
185 for(c = rowArr.length;c--;){ workArr[c]= new Array(rowLength); };
187 for(c = 0;c < workArr.length;c++){
189 for(i = 0;i < rowLength;i++){
191 cel = rowArr[c][celCount];
192 colspan = (cel.getAttribute(fdTableSort.colspan) > 1) ? cel.getAttribute(fdTableSort.colspan):1;
193 rowspan = (cel.getAttribute(fdTableSort.rowspan) > 1) ? cel.getAttribute(fdTableSort.rowspan):1;
194 for(var t = 0;((t < colspan)&&((i+t) < rowLength));t++){
195 for(var n = 0;((n < rowspan)&&((c+n) < workArr.length));n++) {
196 workArr[(c+n)][(i+t)] = cel;
199 if(++celCount == rowArr[c].length) break;
204 for(c = 0;c < workArr.length;c++) {
205 for(i = 0;i < workArr[c].length;i++){
207 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;
209 if(workArr[c][i].className.match('sortable')) {
210 workArr[c][i].className = workArr[c][i].className.replace(/forwardSort|reverseSort/, "");
212 if(i in columnNumSortObj) {
213 columnNumSortObj[i]["thNode"] = workArr[c][i];
214 columnNumSortObj["active"] = true;
216 th_elt = workArr[c][i];
217 thtext = fdTableSort.getInnerText(th_elt, true);
219 for(var cn = workArr[c][i].childNodes.length; cn--;) {
220 // Skip image nodes and links created by the filter script.
221 if(workArr[c][i].childNodes[cn].nodeType == 1 && (workArr[c][i].childNodes[cn].className == "fdFilterTrigger" || /img/i.test(workArr[c][i].childNodes[cn].nodeName))) {
224 if(workArr[c][i].childNodes[cn].nodeType == 1 && /^a$/i.test(workArr[c][i].childNodes[cn].nodeName)) {
225 workArr[c][i].childNodes[cn].onclick = workArr[c][i].childNodes[cn].onkeydown = null;
227 workArr[c][i].removeChild(workArr[c][i].childNodes[cn]);
230 aclone = a.cloneNode(true);
231 //aclone.appendChild(document.createTextNode(thtext));
232 aclone.innerHTML = thtext;
233 //if the <th> has title set, use this as an alternate text for the 'sort on ...'
235 aclone.title = th_elt.title;
237 aclone.title = "Sort on \u201c" + (th_elt.title ? th_elt.title : thtext.replace('<br />', '')) + "\u201d";
239 aclone.onclick = aclone.onkeydown = workArr[c][i].onclick = fdTableSort.initWrapper;
240 workArr[c][i].appendChild(aclone);
241 if(showArrow) workArr[c][i].appendChild(span.cloneNode(false));
242 workArr[c][i].className = workArr[c][i].className.replace(/fd-identical|fd-not-identical/, "");
243 fdTableSort.disableSelection(workArr[c][i]);
249 fdTableSort.tmpCache[tbl.id] = {cols:rowLength, headers:workArr};
254 if("active" in columnNumSortObj) {
255 fdTableSort.tableId = tbl.id;
256 fdTableSort.prepareTableData(document.getElementById(fdTableSort.tableId));
258 delete columnNumSortObj["active"];
260 for(col in columnNumSortObj) {
261 obj = columnNumSortObj[col];
262 if(!("thNode" in obj)) { continue; };
263 fdTableSort.multi = true;
265 len = obj.reverse ? 2 : 1;
267 for(ii = 0; ii < len; ii++) {
268 fdTableSort.thNode = obj.thNode;
270 fdTableSort.initSort(false, true);
272 fdTableSort.addThNode();
277 fdTableSort.removeClass(obj.thNode, "(forwardSort|reverseSort)");
278 fdTableSort.addClass(obj.thNode, obj.reverse ? "reverseSort" : "forwardSort");
280 span = fdTableSort.thNode.getElementsByTagName('span')[0];
281 if(span.firstChild) { span.removeChild(span.firstChild); };
282 span.appendChild(document.createTextNode(len == 1 ? " \u2193" : " \u2191"));
286 if(showOnly && (fdTableSort.tableCache[tbl.id].colStyle || fdTableSort.tableCache[tbl.id].rowStyle)) {
287 fdTableSort.redraw(tbl.id, false);
289 } else if(tbl.className.search(/onload-zebra/) != -1) {
290 fdTableSort.tableId = tbl.id;
291 fdTableSort.prepareTableData(tbl);
292 if(fdTableSort.tableCache[tbl.id].rowStyle) { fdTableSort.redraw(tbl.id, false); };
296 fdTableSort.thNode = aclone = a = span = columnNumSortObj = thNode = tbl = allRowArr = rowArr = null;
297 if (debug) plc_message ('exiting tablesort.init');
299 initWrapper: function(e) {
300 e = e || window.event;
301 var kc = e.type == "keydown" ? e.keyCode != null ? e.keyCode : e.charCode : -1;
302 if(fdTableSort.thNode == null && (e.type == "click" || kc == 13)) {
304 while(targ.tagName.toLowerCase() != "th") { targ = targ.parentNode; };
305 fdTableSort.thNode = targ;
306 while(targ.tagName.toLowerCase() != "table") { targ = targ.parentNode; };
307 fdTableSort.tableId = targ.id;
308 fdTableSort.multi = e.shiftKey;
309 fdTableSort.addSortActiveClass();
310 setTimeout(fdTableSort.initSort,5,false);
311 return fdTableSort.stopEvent(e);
313 return kc != -1 ? true : fdTableSort.stopEvent(e);
315 jsWrapper: function(tableid, colNums) {
316 if(!(tableid in fdTableSort.tmpCache)) { return false; };
317 if(!(tableid in fdTableSort.tableCache)) { fdTableSort.prepareTableData(document.getElementById(tableid)); };
318 if(!(colNums instanceof Array)) { colNums = [colNums]; };
320 fdTableSort.tableId = tableid;
321 var len = colNums.length, colNum;
323 if(fdTableSort.tableCache[tableid].thList.length == colNums.length) {
324 var identical = true;
326 for(var i = 0; i < len; i++) {
328 th = fdTableSort.tmpCache[tableid].headers[0][colNum];
329 if(th != fdTableSort.tableCache[tableid].thList[i]) {
335 fdTableSort.thNode = th;
336 fdTableSort.initSort(true);
341 fdTableSort.addSortActiveClass();
343 for(var i = 0; i < len; i++) {
344 fdTableSort.multi = i;
346 fdTableSort.thNode = fdTableSort.tmpCache[tableid].headers[0][colNum];
347 fdTableSort.initSort(true);
350 addSortActiveClass: function() {
351 if(fdTableSort.thNode == null) { return; };
352 fdTableSort.addClass(fdTableSort.thNode, fdTableSort.sortActiveClass);
353 fdTableSort.addClass(document.getElementsByTagName('body')[0], fdTableSort.sortActiveClass);
355 removeSortActiveClass: function() {
356 if(fdTableSort.thNode == null) return;
357 fdTableSort.removeClass(fdTableSort.thNode, fdTableSort.sortActiveClass);
358 fdTableSort.removeClass(document.getElementsByTagName('body')[0], fdTableSort.sortActiveClass);
360 doCallback: function(init) {
361 if(!fdTableSort.tableId || !(fdTableSort.tableId in fdTableSort.tableCache)) { return; };
362 fdTableSort.callback(fdTableSort.tableId, init ? fdTableSort.tableCache[fdTableSort.tableId].initiatedCallback : fdTableSort.tableCache[fdTableSort.tableId].completeCallback);
364 addClass: function(e,c) {
365 if(new RegExp("(^|\\s)" + c + "(\\s|$)").test(e.className)) { return; };
366 e.className += ( e.className ? " " : "" ) + c;
370 removeClass: function(e,c) {
371 e.className = !c ? "" : e.className.replace(new RegExp("(^|\\s)" + c + "(\\s|$)"), " ").replace(/^\s*((?:[\S\s]*\S)?)\s*$/, '$1');
374 removeClass: function(e,c) {
375 e.className = !c ? "" : e.className.replace(new RegExp("(^|\\s)" + c + "(\\s|$)"), " ").replace(/^\s\s*/, '').replace(/\s\s*$/, '');
379 callback: function(tblId, cb) {
382 if(cb.indexOf(".") != -1) {
383 parts = cb.split('.');
385 for (var x = 0, part; part = obj[parts[x]]; x++) {
386 if(part instanceof Function) {
389 func = function (data) { method.apply(obj, [data]) };
395 } else if(cb + tblId in window) {
396 func = window[cb + tblId];
397 } else if(cb in window) {
404 if(!(func instanceof Function)) return;
405 func(tblId, fdTableSort.tableCache[tblId].thList);
407 prepareTableData: function(table) {
410 var start = table.getElementsByTagName('tbody');
411 start = start.length ? start[0] : table;
413 var trs = start.rows;
414 var ths = table.getElementsByTagName('th');
416 var numberOfRows = trs.length;
417 var numberOfCols = fdTableSort.tmpCache[table.id].cols;
420 var identical = new Array(numberOfCols);
421 var identVal = new Array(numberOfCols);
423 for(var tmp = 0; tmp < numberOfCols; tmp++) identical[tmp] = true;
425 var tr, td, th, txt, tds, col, row;
427 var re = new RegExp(/fd-column-([0-9]+)/);
430 var sortableColumnNumbers = [];
432 for(var tmp = 0, th; th = ths[tmp]; tmp++) {
433 if(th.className.search(re) == -1) continue;
434 sortableColumnNumbers[sortableColumnNumbers.length] = th;
437 for(row = 0; row < numberOfRows; row++) {
440 if(tr.parentNode != start || tr.getElementsByTagName("th").length || (tr.parentNode && tr.parentNode.tagName.toLowerCase().search(/thead|tfoot/) != -1)) continue;
444 for(var tmp = 0, th; th = sortableColumnNumbers[tmp]; tmp++) {
445 col = th.className.match(re)[1];
448 txt = fdTableSort.getInnerText(td) + " ";
449 txt = txt.replace(/^\s+/,'').replace(/\s+$/,'');
451 if(th.className.search(/sortable-date/) != -1) {
452 txt = fdTableSort.dateFormat(txt, th.className.search(/sortable-date-dmy/) != -1);
453 } else if(th.className.search(/sortable-numeric|sortable-currency/) != -1) {
454 txt = parseFloat(txt.replace(/[^0-9\.\-]/g,''));
455 if(isNaN(txt)) txt = "";
456 } else if(th.className.search(/sortable-text/) != -1) {
457 txt = txt.toLowerCase();
458 } else if (th.className.search(/sortable-keep/) != -1) {
460 } else if(th.className.search(/sortable-([a-zA-Z\_]+)/) != -1) {
461 if((th.className.match(/sortable-([a-zA-Z\_]+)/)[1] + "PrepareData") in window) {
462 txt = window[th.className.match(/sortable-([a-zA-Z\_]+)/)[1] + "PrepareData"](td, txt);
464 } else if(txt != "") {
465 fdTableSort.removeClass(th, "sortable");
466 if(fdTableSort.dateFormat(txt) != 0) {
467 fdTableSort.addClass(th, "sortable-date");
468 txt = fdTableSort.dateFormat(txt);
469 } else if(txt.search(fdTableSort.regExp_Number) != -1 || txt.search(fdTableSort.regExp_Currency) != -1) {
470 fdTableSort.addClass(th, "sortable-numeric");
471 txt = parseFloat(txt.replace(/[^0-9\.\-]/g,''));
472 if(isNaN(txt)) txt = "";
474 fdTableSort.addClass(th, "sortable-text");
475 txt = txt.toLowerCase();
479 if(rowCnt > 0 && identical[col] && identVal[col] != txt) { identical[col] = false; };
482 data[rowCnt][col] = txt;
484 data[rowCnt][numberOfCols] = tr;
488 var colStyle = table.className.search(/colstyle-([\S]+)/) != -1 ? table.className.match(/colstyle-([\S]+)/)[1] : false;
489 var rowStyle = table.className.search(/rowstyle-([\S]+)/) != -1 ? table.className.match(/rowstyle-([\S]+)/)[1] : false;
490 var iCBack = table.className.search(/sortinitiatedcallback-([\S-]+)/) == -1 ? "sortInitiatedCallback" : table.className.match(/sortinitiatedcallback-([\S]+)/)[1];
491 var cCBack = table.className.search(/sortcompletecallback-([\S-]+)/) == -1 ? "sortCompleteCallback" : table.className.match(/sortcompletecallback-([\S]+)/)[1];
492 iCBack = iCBack.replace("-", ".");
493 cCBack = cCBack.replace("-", ".");
494 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 };
495 sortableColumnNumbers = data = tr = td = th = trs = identical = identVal = null;
497 onUnload: function() {
498 for(tbl in fdTableSort.tableCache) { fdTableSort.removeTableCache(tbl); };
499 for(tbl in fdTableSort.tmpCache) { fdTableSort.removeTmpCache(tbl); };
500 fdTableSort.removeEvent(window, "load", fdTableSort.initEvt);
501 fdTableSort.removeEvent(window, "unload", fdTableSort.onUnload);
502 fdTableSort.tmpCache = fdTableSort.tableCache = null;
504 addThNode: function() {
505 var dataObj = fdTableSort.tableCache[fdTableSort.tableId];
506 var pos = fdTableSort.thNode.className.match(/fd-column-([0-9]+)/)[1];
509 if(!fdTableSort.multi) {
510 if(dataObj.colStyle) {
511 var len = dataObj.thList.length;
512 for(var i = 0; i < len; i++) {
513 dataObj.colOrder[dataObj.thList[i].className.match(/fd-column-([0-9]+)/)[1]] = false;
516 if(dataObj.thList.length && dataObj.thList[0] == fdTableSort.thNode) alt = true;
521 var l = dataObj.thList.length;
523 for(var i = 0, n; n = dataObj.thList[i]; i++) {
524 if(n == fdTableSort.thNode) {
531 dataObj.thList.push(fdTableSort.thNode);
532 if(dataObj.colStyle) { dataObj.colOrder[pos] = true; };
535 var ths = document.getElementById(fdTableSort.tableId).getElementsByTagName("th");
536 for(var i = 0, th; th = ths[i]; i++) {
538 for(var z = 0, n; n = dataObj.thList[z]; z++) {
545 fdTableSort.removeClass(th, "(forwardSort|reverseSort)");
546 if(!dataObj.noArrow) {
547 span = th.getElementsByTagName('span');
550 while(span.firstChild) span.removeChild(span.firstChild);
556 if(dataObj.thList.length > 1) {
557 classToAdd = fdTableSort.thNode.className.search(/forwardSort/) != -1 ? "reverseSort" : "forwardSort";
558 fdTableSort.removeClass(fdTableSort.thNode, "(forwardSort|reverseSort)");
559 fdTableSort.addClass(fdTableSort.thNode, classToAdd);
561 } else if(alt) { dataObj.pos = fdTableSort.thNode };
563 initSort: function(noCallback, ident) {
564 var thNode = fdTableSort.thNode;
565 var tableElem = document.getElementById(fdTableSort.tableId);
567 if(!(fdTableSort.tableId in fdTableSort.tableCache)) { fdTableSort.prepareTableData(document.getElementById(fdTableSort.tableId)); };
569 fdTableSort.addThNode();
571 if(!noCallback) { fdTableSort.doCallback(true); };
573 fdTableSort.pos = thNode.className.match(/fd-column-([0-9]+)/)[1];
574 var dataObj = fdTableSort.tableCache[tableElem.id];
575 var lastPos = dataObj.pos && dataObj.pos.className ? dataObj.pos.className.match(/fd-column-([0-9]+)/)[1] : -1;
576 var len1 = dataObj.data.length;
577 var len2 = dataObj.data.length > 0 ? dataObj.data[0].length - 1 : 0;
578 var identical = dataObj.identical[fdTableSort.pos];
579 var classToAdd = "forwardSort";
581 if(dataObj.thList.length > 1) {
582 var js = "var sortWrapper = function(a,b) {\n";
583 var l = dataObj.thList.length;
587 for(var i=0; i < l; i++) {
588 th = dataObj.thList[i];
589 p = th.className.match(/fd-column-([0-9]+)/)[1];
590 if(dataObj.identical[p]) { continue; };
593 if(th.className.match(/sortable-(numeric|currency|date|keep)/)) {
594 f = "fdTableSort.sortNumeric";
595 } else if(th.className.match('sortable-text')) {
596 f = "fdTableSort.sortText";
597 } else if(th.className.search(/sortable-([a-zA-Z\_]+)/) != -1 && th.className.match(/sortable-([a-zA-Z\_]+)/)[1] in window) {
598 f = "window['" + th.className.match(/sortable-([a-zA-Z\_]+)/)[1] + "']";
599 } else f = "fdTableSort.sortText";
602 d = th.className.search('forwardSort') != -1 ? "a,b" : "b,a";
603 js += "fdTableSort.pos = " + p + ";\n";
604 js += "var " + e + " = "+f+"(" + d +");\n";
605 js += "if(" + e + ") return " + e + ";\n";
611 for(var i=0; i < cnt; i++) {
615 if(cnt) js += "return 0;\n";
619 dataObj.data.sort(sortWrapper);
621 } else if((lastPos == fdTableSort.pos && !identical) || (thNode.className.search(/sortable-keep/) != -1 && lastPos == -1)) {
622 dataObj.data.reverse();
623 classToAdd = thNode.className.search(/reverseSort/) != -1 ? "forwardSort" : "reverseSort";
624 if(thNode.className.search(/sortable-keep/) != -1 && lastPos == -1) fdTableSort.tableCache[tableElem.id].pos = thNode;
626 fdTableSort.tableCache[tableElem.id].pos = thNode;
627 classToAdd = thNode.className.search(/forwardSort/) != -1 ? "reverseSort" : "forwardSort";
629 if(thNode.className.match(/sortable-(numeric|currency|date|keep)/)) {
630 dataObj.data.sort(fdTableSort.sortNumeric);
631 } else if(thNode.className.match('sortable-text')) {
632 dataObj.data.sort(fdTableSort.sortText);
633 } else if(thNode.className.search(/sortable-([a-zA-Z\_]+)/) != -1 && thNode.className.match(/sortable-([a-zA-Z\_]+)/)[1] in window) {
634 dataObj.data.sort(window[thNode.className.match(/sortable-([a-zA-Z\_]+)/)[1]]);
637 if(thNode.className.search(/(^|\s)favour-reverse($|\s)/) != -1) {
638 classToAdd = classToAdd == "forwardSort" ? "reverseSort" : "forwardSort";
639 dataObj.data.reverse();
643 if(ident) { identical = false; };
644 if(dataObj.thList.length == 1) {
645 fdTableSort.removeClass(thNode, "(forwardSort|reverseSort)");
646 fdTableSort.addClass(thNode, classToAdd);
648 if(!dataObj.noArrow) {
649 var span = fdTableSort.thNode.getElementsByTagName('span')[0];
650 if(span.firstChild) span.removeChild(span.firstChild);
651 span.appendChild(document.createTextNode(fdTableSort.thNode.className.search(/forwardSort/) != -1 ? " \u2193" : " \u2191"));
653 if(!dataObj.rowStyle && !dataObj.colStyle && identical) {
654 fdTableSort.removeSortActiveClass();
655 if(!noCallback) { fdTableSort.doCallback(false); };
656 fdTableSort.thNode = null;
659 if("tablePaginater" in window && tablePaginater.tableIsPaginated(fdTableSort.tableId)) {
660 tablePaginater.redraw(fdTableSort.tableId, identical);
662 fdTableSort.redraw(fdTableSort.tableId, identical);
664 fdTableSort.removeSortActiveClass();
665 if(!noCallback) { fdTableSort.doCallback(false); };
666 fdTableSort.thNode = null;
668 redraw: function(tableid, identical) {
669 if (debug) plc_message ('entering tablesort.redraw');
670 if(!tableid || !(tableid in fdTableSort.tableCache)) { return; };
671 var dataObj = fdTableSort.tableCache[tableid];
672 var data = dataObj.data;
673 var len1 = data.length;
674 var len2 = len1 ? data[0].length - 1 : 0;
675 var hook = dataObj.hook;
676 var colStyle = dataObj.colStyle;
677 var rowStyle = dataObj.rowStyle;
678 var colOrder = dataObj.colOrder;
680 var reg = /(^|\s)invisibleRow(\s|$)/;
683 for(var i = 0; i < len1; i++) {
687 for(thPos in colOrder) {
688 if(!colOrder[thPos]) fdTableSort.removeClass(tds[thPos], colStyle);
689 else fdTableSort.addClass(tds[thPos], colStyle);
693 if(rowStyle && tr.className.search(reg) == -1) {
694 if(highLight++ & 1) fdTableSort.addClass(tr, rowStyle);
695 else fdTableSort.removeClass(tr, rowStyle);
698 // Netscape 8.1.2 requires the removeChild call or it freaks out, so add the line if you want to support this browser
699 // hook.removeChild(tr);
700 hook.appendChild(tr);
703 tr = tds = hook = null;
704 if (debug) plc_message ('exiting tablesort.redraw');
706 getInnerText: function(el, allowBrTags) {
707 if (typeof el == "string" || typeof el == "undefined") return el;
708 if(el.innerText) return el.innerText;
710 for(i = el.firstChild; i; i = i.nextSibling) {
711 if(allowBrTags && i.nodeName && i.nodeName == "BR") txt += "<br />";
712 else if(i.nodeType == 3) txt += i.nodeValue;
713 else if(i.nodeType == 1) txt += fdTableSort.getInnerText(i);
717 dateFormat: function(dateIn, favourDMY) {
719 { 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
720 { 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
721 { 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
723 var start, cnt = 0, numFormats = dateTest.length;
724 while(cnt < numFormats) {
725 start = (cnt + (favourDMY ? numFormats + 1 : numFormats)) % numFormats;
726 if(dateIn.match(dateTest[start].regExp)) {
727 res = dateIn.match(dateTest[start].regExp);
728 y = res[dateTest[start].y];
729 m = res[dateTest[start].m];
730 d = res[dateTest[start].d];
731 if(m.length == 1) m = "0" + String(m);
732 if(d.length == 1) d = "0" + String(d);
733 if(y.length != 4) y = (parseInt(y) < 50) ? "20" + String(y) : "19" + String(y);
735 return y+String(m)+d;
741 sortNumeric:function(a,b) {
742 var aa = a[fdTableSort.pos];
743 var bb = b[fdTableSort.pos];
744 if(aa == bb) return 0;
745 if(aa === "" && !isNaN(bb)) return -1;
746 if(bb === "" && !isNaN(aa)) return 1;
749 sortText:function(a,b) {
750 var aa = a[fdTableSort.pos];
751 var bb = b[fdTableSort.pos];
752 if(aa == bb) return 0;
753 if(aa < bb) return -1;
758 fdTableSort.addEvent(window, "load", fdTableSort.initEvt);
759 fdTableSort.addEvent(window, "unload", fdTableSort.onUnload);