// Code adapted by Franamax from wikibits.js table sort functions
// The wikibits.js code is based on code (c) 1997-2006 Stuart Langridge and Joost de Valk:
// http://www.joostdevalk.nl/code/sortable-table/
// http://www.kryogenix.org/code/browser/sorttable/
function sortables_init() {
var idnum = 0;
// Find all tables with class sortable and make them sortable
// sortable2 begin
var srch = "sortable";
for (x=0; x<2; ++x) {
if (x==1) srch = "sortable2";
var tables = getElementsByClassName(document, "table", srch);
// sortable2 end
for (var ti = 0; ti < tables.length ; ti++) {
if (!tables[ti].id) {
tables[ti].setAttribute('id','sortable_table_id_'+idnum);
++idnum;
}
// sortable2 begin
(x==0 ? ts_makeSortable(tables[ti]) : ts_makeSortable2(tables[ti]));
}
// sortable2 end
}
}
function ts_makeSortable2(table) {
var firstRow;
/* if (table.rows && table.rows.length > 0) {
if (table.tHead && table.tHead.rows.length > 0) {
firstRow = table.tHead.rows[table.tHead.rows.length-1];
} else {
firstRow = table.rows[0];
}
}
if (!firstRow) return;
// We have a first row: assume it's the header, and make its contents clickable links
for (var i = 0; i < firstRow.cells.length; i++) {
var cell = firstRow.cells[i];
*/
// sortable2 begin
for (var x=0;x<table.rows.length;++x) {
if ( (" "+table.rows[x].className+" ").indexOf(" sorthdg ") <0) break;
for (var i=0; i<table.rows[x].cells.length; ++i) {
var cell = table.rows[x].cells[i];
if ((" "+cell.className+" ").indexOf(" sortkey ") >= 0) {
// sortable2 end
cell.innerHTML += ' <a href="#" class="sortheader" onclick="ts_resortTable(this);return false;"><span class="sortarrow"><img src="'+ ts_image_path + ts_image_none + '" alt="↓"/></span></a>';
}
}
// sortable2 begin
}
//sortable2 end
if (ts_alternate_row_colors) {
ts_alternate(table);
}
}
function ts_resortTable(lnk) {
// get the span
var span = lnk.getElementsByTagName('span')[0];
var td = lnk.parentNode;
var tr = td.parentNode;
var column = td.cellIndex;
var table = tr.parentNode;
while (table && !(table.tagName && table.tagName.toLowerCase() == 'table'))
table = table.parentNode;
if (!table) return;
// Work out a type for the column
if (table.rows.length <= 1) return;
// Skip the first row if that's where the headings are
var rowStart = (table.tHead && table.tHead.rows.length > 0 ? 0 : 1);
// sortable2 begin
for (var i=0; i<table.rows.length; ++i) {
if ((" "+table.rows[i].className+" ").indexOf(" sorthdg ") == -1) break;
rowStart = i+1;
}
// find the column index in the actual table data
// uncol is the number of columns rowspanned from higher up in the table
// tgtrow is the rowspan adjusted row index of the clock target
// tgtcol is the colspan adjusted column index of the click target
// stop is a counter for when to stop examining columns in the previous rows
// thisrow is an indexed row for span-counting, thiscell is an indexed cell
// tgtspan is the rowspan of the cell in thisrow above the target
// minspan is the smallest rowspan in thisrow, for the rare occasion when all the rowspans are >1
// x, y and rspan are work variables
var uncol = 0; var stop = 0; var x = 0; var y = 0; var rspan = 0; var tgtspan = 0; var minspan = 0;
var tgtrow = tr.rowIndex; var tgtcol = column;
// find the "true" column index of the target within its own row
for (x=0; x<column; ++x) {
tgtcol += tr.cells[x].colSpan - 1;
}
// first pass - find the "real" target row by counting the rowspans of the cells above the target
for (x=0; x<tgtrow; ++x) {
stop = 0; // count the non-interfering columns before the target
minspan = 999; tgtspan = 0;
thisrow = table.rows[x];
for (y=0; y<thisrow.cells.length; ++y) {
thiscell = thisrow.cells[y];
rspan = thiscell.rowSpan; if (rspan < minspan) minspan = rspan;
// if the rowspan interferes with the current tgtrow, ignore it - we're just trying to find the cell above the target on thisrow in pass 1.
if ( (x+rspan) >= (tgtrow+1) ) continue;
stop += thiscell.colSpan;
if (stop >= tgtcol && tgtspan <= 0) tgtspn = rspan;
}
// increment the target row by the rowspan in the cell above it (minus the smallest span in the row)
if (tgtspan > 0 && minspan != 999) { // sanity check, should always be true
tgtrow += tgtspan - minspan;
if (tgtrow < 1) tgtrow = 1; // this would be serious bad news if true
if (tgtrow > 100) {
tgtrow = 1; break; // this would be horrible news of breakage
}
}
}
// 2nd pass - now run down the rows above the target, find and count the cells with rowspans that will intrude onto the target row
for (x=0;x<tgtrow;++x) {
stop = 0; // count the non-interfering columns before the target
thisrow = table.rows[x];
for (y=0; y<thisrow.cells.length; ++y) {
thiscell = thisrow.cells[y];
rspan = thiscell.rowSpan;
// if the current column interferes with our target, it's an uncol!
if ( (x+rspan) >= (tgtrow+1) ) {
uncol += thiscell.colSpan; continue;
}
stop += thiscell.colSspan;
if (stop >= tgtcol) break;
}
}
// now set the "real" column in the actual table
column = tgtcol + uncol;
// sortable2 end
var itm = "";
for (var i = rowStart; i < table.rows.length; i++) {
if (table.rows[i].cells.length > column) {
itm = ts_getInnerText(table.rows[i].cells[column]);
itm = itm.replace(/^[\s\xa0]+/, "").replace(/[\s\xa0]+$/, "");
if (itm != "") break;
}
}
var sortfn = ts_sort_caseinsensitive;
if (itm.match(/^\d\d[\/. -][a-zA-Z]{3}[\/. -]\d\d\d\d$/))
sortfn = ts_sort_date;
else if (itm.match(/^\d\d[\/.-]\d\d[\/.-]\d\d\d\d$/))
sortfn = ts_sort_date;
else if (itm.match(/^\d\d[\/.-]\d\d[\/.-]\d\d$/))
sortfn = ts_sort_date;
// pound dollar euro yen currency cents
else if (itm.match(/(^[\u00a3$\u20ac\u00a4\u00a5]|\u00a2$)/))
sortfn = ts_sort_currency;
// We allow a trailing percent sign, which we just strip. This works fine
// if percents and regular numbers aren't being mixed.
else if (itm.match(/^[+-]?\d[\d,]*(\.[\d,]*)?([eE][+-]?\d[\d,]*)?\%?$/) ||
itm.match(/^[+-]?\.\d[\d,]*([eE][+-]?\d[\d,]*)?\%?$/) ||
itm.match(/^0x[\da-f]+$/i))
sortfn = ts_sort_numeric;
var reverse = (span.getAttribute("sortdir") == 'down');
var newRows = new Array();
for (var j = rowStart; j < table.rows.length; j++) {
var row = table.rows[j];
var keyText = ts_getInnerText(row.cells[column]);
var oldIndex = (reverse ? -j : j);
newRows[newRows.length] = new Array(row, keyText, oldIndex);
}
newRows.sort(sortfn);
var arrowHTML;
if (reverse) {
arrowHTML = '<img src="'+ ts_image_path + ts_image_down + '" alt="↓"/>';
newRows.reverse();
span.setAttribute('sortdir','up');
} else {
arrowHTML = '<img src="'+ ts_image_path + ts_image_up + '" alt="↑"/>';
span.setAttribute('sortdir','down');
}
// We appendChild rows that already exist to the tbody, so it moves them rather than creating new ones
// don't do sortbottom rows
for (var i = 0; i < newRows.length; i++) {
if ((" "+newRows[i][0].className+" ").indexOf(" sortbottom ") == -1)
table.tBodies[0].appendChild(newRows[i][0]);
}
// do sortbottom rows only
for (var i = 0; i < newRows.length; i++) {
if ((" "+newRows[i][0].className+" ").indexOf(" sortbottom ") != -1)
table.tBodies[0].appendChild(newRows[i][0]);
}
// Delete any other arrows there may be showing
var spans = getElementsByClassName(tr, "span", "sortarrow");
for (var i = 0; i < spans.length; i++) {
spans[i].innerHTML = '<img src="'+ ts_image_path + ts_image_none + '" alt="↓"/>';
}
span.innerHTML = arrowHTML;
if (ts_alternate_row_colors) {
ts_alternate(table);
}
}