2 * From: http://www.kryogenix.org/code/browser/sorttable/
6 hookEvent( "load", sortables_init
);
8 var NO_ARROW
= stylepath
+'/common/sort_none.gif';
9 var UP_ARROW
= stylepath
+'/common/sort_up.gif';
10 var DOWN_ARROW
= stylepath
+'/common/sort_down.gif';
12 function sortables_init() {
14 // Find all tables with class sortable and make them sortable
15 if (!document
.getElementsByTagName
) return;
16 tbls
= document
.getElementsByTagName("table");
17 for (ti
=0;ti
<tbls
.length
;ti
++) {
19 if ((' '+thisTbl
.className
+' ').indexOf(" sortable ") != -1) {
21 thisTbl
.setAttribute('id','sortable_table_id_'+idnum
);
24 //initTable(thisTbl.id);
25 ts_makeSortable(thisTbl
);
30 function ts_makeSortable(table
) {
31 if (table
.rows
&& table
.rows
.length
> 0) {
32 var firstRow
= table
.rows
[0];
34 if (!firstRow
) return;
36 // We have a first row: assume it's the header, and make its contents clickable links
37 for (var i
=0;i
<firstRow
.cells
.length
;i
++) {
38 var cell
= firstRow
.cells
[i
];
39 var txt
= ts_getInnerText(cell
);
40 cell
.innerHTML
= txt
+'<a href="#" class="sortheader" onclick="ts_resortTable(this);return false;"><img class="sortarrow" src="'+NO_ARROW
+'" alt="↕" /></a>';
44 function ts_getInnerText(el
) {
45 if (typeof el
== "string") return el
;
46 if (typeof el
== "undefined") { return el
};
47 if (el
.innerText
) return el
.innerText
; //Not needed but it is faster
50 var cs
= el
.childNodes
;
52 for (var i
= 0; i
< l
; i
++) {
53 switch (cs
[i
].nodeType
) {
54 case 1: //ELEMENT_NODE
55 str
+= ts_getInnerText(cs
[i
]);
58 str
+= cs
[i
].nodeValue
;
65 function ts_resortTable(lnk
) {
66 // get the arrow image
68 for (var ci
=0;ci
<lnk
.childNodes
.length
;ci
++) {
69 if (lnk
.childNodes
[ci
].tagName
&& lnk
.childNodes
[ci
].tagName
.toLowerCase() == 'img') img
= lnk
.childNodes
[ci
];
71 var reverse
= (img
.getAttribute("sortdir") == 'down');
73 var td
= lnk
.parentNode
;
74 var column
= td
.cellIndex
;
75 var table
= getParent(td
,'TABLE');
77 // Work out a type for the column
78 if (table
.rows
.length
<= 1) return;
79 var itm
= ts_getInnerText(table
.rows
[1].cells
[column
]);
80 sortfn
= ts_sort_caseinsensitive
;
81 // Note: The trailing \n$ is needed because that's how MediaWiki spits out its table syntax.
82 if (itm
.match(/^\s*\d{2}[\/-]\d{2}[\/-]\d{4}\s*$/)) sortfn
= ts_sort_date
;
83 if (itm
.match(/^\s*\d{2}[\/-]\d{2}[\/-]\d{2}\s*$/)) sortfn
= ts_sort_date
;
84 if (itm
.match(/^\s*[?$]/)) sortfn
= ts_sort_currency
;
85 if (itm
.match(/^\s*[\d\.]+\s*$/)) sortfn
= ts_sort_numeric
;
86 var firstRow
= new Array();
87 var newRows
= new Array();
88 for (i
=0;i
<table
.rows
[0].length
;i
++) { firstRow
[i
] = table
.rows
[0][i
]; }
89 for (j
=1;j
<table
.rows
.length
;j
++) {
90 var obj
= new Object();
91 obj
.row
= table
.rows
[j
];
92 obj
.grp
= ((' '+obj
.row
.className
+' ').indexOf(' sortbottom ') == -1 ? 0 : reverse
? -1 : 1);
93 obj
.txt
= ts_getInnerText(obj
.row
.cells
[column
]);
94 obj
.idx
= (reverse
? -j
: j
);
103 img
.setAttribute('sortdir','up');
106 img
.setAttribute('sortdir','down');
109 // We appendChild rows that already exist to the tbody, so it moves them rather than creating new ones
110 for (i
=0;i
<newRows
.length
;i
++) { table
.tBodies
[0].appendChild(newRows
[i
].row
); }
112 // Delete any other arrows there may be showing
113 var allimgs
= document
.getElementsByTagName("img");
114 for (var ci
=0;ci
<allimgs
.length
;ci
++) {
115 if (allimgs
[ci
].className
== 'sortarrow') {
116 if (getParent(allimgs
[ci
],"table") == getParent(lnk
,"table")) { // in the same table as us?
117 allimgs
[ci
].setAttribute('src',NO_ARROW
);
122 img
.setAttribute('src',ARROW
);
123 img
.setAttribute('alt',img
.getAttribute("sortdir") == 'down' ? '↓' : '↑');
126 function getParent(el
, pTagName
) {
127 if (el
== null) return null;
128 else if (el
.nodeType
== 1 && el
.tagName
.toLowerCase() == pTagName
.toLowerCase()) // Gecko bug, supposed to be uppercase
131 return getParent(el
.parentNode
, pTagName
);
133 function ts_sort_date(a
,b
) {
134 if (a
.grp
!= b
.grp
) return a
.grp
-b
.grp
;
135 // y2k notes: two digit years less than 50 are treated as 20XX, greater than 50 are treated as 19XX
138 if (aa
.length
== 10) {
139 dt1
= aa
.substr(6,4)+aa
.substr(3,2)+aa
.substr(0,2);
142 if (parseInt(yr
) < 50) { yr
= '20'+yr
; } else { yr
= '19'+yr
; }
143 dt1
= yr
+aa
.substr(3,2)+aa
.substr(0,2);
145 if (bb
.length
== 10) {
146 dt2
= bb
.substr(6,4)+bb
.substr(3,2)+bb
.substr(0,2);
149 if (parseInt(yr
) < 50) { yr
= '20'+yr
; } else { yr
= '19'+yr
; }
150 dt2
= yr
+bb
.substr(3,2)+bb
.substr(0,2);
152 if (dt1
==dt2
) return a
.idx
-b
.idx
;
153 if (dt1
<dt2
) return -1;
157 function ts_sort_currency(a
,b
) {
158 if (a
.grp
!= b
.grp
) return a
.grp
-b
.grp
;
159 aa
= parseFloat(a
.txt
.replace(/[^0-9.]/g,''));
160 bb
= parseFloat(b
.txt
.replace(/[^0-9.]/g,''));
161 if (isNaN(aa
)) aa
= 0;
162 if (isNaN(bb
)) bb
= 0;
163 if (aa
==bb
) return a
.idx
-b
.idx
;
167 function ts_sort_numeric(a
,b
) {
168 if (a
.grp
!= b
.grp
) return a
.grp
-b
.grp
;
169 aa
= parseFloat(a
.txt
);
170 bb
= parseFloat(b
.txt
);
171 if (isNaN(aa
)) aa
= 0;
172 if (isNaN(bb
)) bb
= 0;
173 if (aa
==bb
) return a
.idx
-b
.idx
;
177 function ts_sort_caseinsensitive(a
,b
) {
178 if (a
.grp
!= b
.grp
) return a
.grp
-b
.grp
;
179 aa
= a
.txt
.toLowerCase();
180 bb
= b
.txt
.toLowerCase();
181 if (aa
==bb
) return a
.idx
-b
.idx
;
182 if (aa
<bb
) return -1;
186 function ts_sort_default(a
,b
) {
187 if (a
.grp
!= b
.grp
) return a
.grp
-b
.grp
;
190 if (aa
==bb
) return a
.idx
-b
.idx
;
191 if (aa
<bb
) return -1;