Possible improvements to Sortable Tables Javascript code used by MediaWiki.
- The code is in wikibits.js in SVN
- Original code: sortable_us.js from http://www.joostdevalk.nl/code/sortable-table/
SharkD's changes can be found here (note: the diffs may no longer be up-to-date):
User:SharkD/Sandbox/wikibits_1User:SharkD/Sandbox/wikibits_2User:SharkD/Sandbox/wikibits_3- User:SharkD/Sandbox/wikibits_4 - (Note: there are several "disabled" bits of code (formatting of alternate rows, detection of THEAD elements, auto-sorting of fractions/ratios) that can be removed if it is determined they will never be used.)
Diff: Table sorting sectionDiff: Entire file
Fix: remove alternate rows code
editThis code marks table rows with classes "odd" and "even":
- It is apparently not used by anyone
- It executes on the page load, slowing loading time
The code in question is:
var ts_alternate_row_colors = true;
function ts_alternate(table) { ...
- and two calls to this function
Comments 1
editit could be used by introducing another class into site CSS, something like table.alternate tr.even {background-color: #F5F5F5}
- I would also prefer if it were enabled instead of removed. The fact that people don't know about it is because it isn't advertised. Template:Infobox VG (backlinks edit) for instance could feasably switch from using templates to using JavaScript for alternate row coloring. SharkD (talk) 00:50, 18 August 2008 (UTC)
Simplification: remove THEAD check
editAs MediaWiki does not support THEAD, nor through wiki-syntax, neither as HTML tag.
function ts_makeSortable(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;
can be replaced with
function ts_makeSortable(table) {
if (!table.rows || table.rows.length == 0) return
var firstRow = table.rows[0]
and the line
var rowStart = (table.tHead && table.tHead.rows.length > 0 ? 0 : 1);
in function ts_resortTable(lnk)
can be replaced with
var rowStart = 1
Comments 2
editThe THEAD element may make an appearance in the future, so a link to some record of this code block's former existence would at least be warranted. SharkD (talk) 04:11, 28 August 2008 (UTC)
Simplification: month conversion
editfunction ts_dateToSortKey(date) {
// y2k notes: two digit years less than 50 are treated as 20XX, greater than 50 are treated as 19XX
if (date.length == 11) {
switch (date.substr(3,3).toLowerCase()) {
case "jan": var month = "01"; break;
case "feb": var month = "02"; break;
case "mar": var month = "03"; break;
case "apr": var month = "04"; break;
case "may": var month = "05"; break;
case "jun": var month = "06"; break;
case "jul": var month = "07"; break;
case "aug": var month = "08"; break;
case "sep": var month = "09"; break;
case "oct": var month = "10"; break;
case "nov": var month = "11"; break;
case "dec": var month = "12"; break;
// default: var month = "00";
}
can be replaced with
function ts_dateToSortKey(date) {
// y2k notes: two digit years less than 50 are treated as 20XX, greater than 50 are treated as 19XX
if (date.length == 11) {
var month = date.substr(3,3).toLowerCase()
month = "janfebmaraprmayjunjulaugsepoctnovdec".indexOf(month)/3 + 1
if (month == -1) month = "00"
else if (month<10) month = "0" + month
Comments 3
editIn either case, it is not clear to me what format the input dates take. I.e., what do the input dates look like? SharkD (talk) 04:14, 28 August 2008 (UTC)
- Nevermind. I'll have to take a closer look at those regexps. SharkD (talk) 04:26, 28 August 2008 (UTC)
It might speed things up if only the ISO 8601 YYYY-MM-DD format were supported, leaving it up to editors to convert dates to this format (either visibly, or invisibly using a template such as {{dts}}). SharkD (talk) 07:43, 28 August 2008 (UTC)
This line:
if (month == -1) month = "00"
can be removed from your proposal, as the condition will never be met. SharkD (talk) 19:02, 29 August 2008 (UTC)
I started a bugzilla report on the locale-specific issues. SharkD (talk) 03:30, 1 September 2008 (UTC)
Proposal: input date format localization
editSortable Tables code determines the sorting mode by analyzing the top non-empty cell. The first RegExp used for possible dates is
if (itm.match(/^\d\d[\/. -][a-zA-Z]{3}[\/. -]\d\d\d\d$/))
Proposal: accept arbitrary months names, something like
if (itm.match(/^\d\d[\/. -][^\d ]{1,12}[\/. -]\d\d\d\d$/))
and then introduce another parameter ts_months_names, which is set in local Common.js and is equivalent to English "janfebmaraprmayjunjulaugsepoctnovdec"
Then the function ts_dateToSortKey
(see above section) is modified to use ts_months_names if month name was not found in the English string of month names.
Comments 4
editIs the above supposed to replace the latter two date regexprs as well, or just the first? Also, what if the day value is only a single digit long? SharkD (talk) 04:40, 28 August 2008 (UTC)
- Also, is this change supposed to make the script language-agnostic? What if a month name in another language has more than 12 characters or has spaces in it (I have no idea if this will actually ever happen)? SharkD (talk) 05:07, 28 August 2008 (UTC)
The
.
in [\/. -]
matches any character. Is this a good idea? Doesn't that make searching for the other characters redundant? Is it a mistake, and is it supposed to be [\. -]
instead? SharkD (talk) 05:55, 28 August 2008 (UTC)
Proposal: comma/dot localization
editThe JavaScript hack
//fix for sortable tables: comma as decimal dot
function ts_parseFloat(num){
if (!num) return 0
num = parseFloat(num.replace(/\./g, '').replace(/,/, '.'))
return (isNaN(num) ? 0 : num)
}
which can be found in de:MediaWiki:Common.js or ru:MediaWiki:Common.js, should be replaced with another configuration variable set in local Common.js.
Of course, if MediaWiki can automatically set this parameter depending on wgContentLanguage, this would be even better (this applies to the previous proposal as well).
Comments 5
editI'm not sure the above will work. For instance, if the number has decimal values, removing the period will turn them into integers. I suggest the following:
function ts_parseFloat(num) {
if (!num) return 0;
if (ts_europeandate == true)
num = parseFloat(num.replace(/\./g, "").replace(/,/g, "."));
else
num = parseFloat(num.replace(/,/g, ""));
return (isNaN(num) ? 0 : num);
}
Regardless if using ts_europeandate
is the wrong way of going about doing it, some fix must be put into place to detect and handle this scenario. SharkD (talk) 13:36, 28 August 2008 (UTC)
Change variables in for
statements so that the DOM is not traversed each time the block is looped
edit
Change:
for (var i = 0; i < thing.length ; i++)
To:
for (var i = thing.length; i > 0 ; i--)
Or (if the above is not possible):
for (var i = 0, n = thing.length; i < n ; i++)
Use a local variable instead of global, and use conditions to eliminate cases
editChange:
sortfn = ts_sort_caseinsensitive;
if (itm.match(/^\d\d[\/. -][a-zA-Z]{3}[\/. -]\d\d\d\d$/))
sortfn = ts_sort_date;
if (itm.match(/^\d\d[\/.-]\d\d[\/.-]\d\d\d\d$/))
sortfn = ts_sort_date;
if (itm.match(/^\d\d[\/.-]\d\d[\/.-]\d\d$/))
sortfn = ts_sort_date;
if (itm.match(/^[\u00a3$\u20ac]/)) // pound dollar euro
sortfn = ts_sort_currency;
if (itm.match(/^[\d.,]+\%?$/))
sortfn = ts_sort_numeric;
To:
if (itm.match(/^\d\d[\/. -][a-zA-Z]{3}[\/. -]\d\d\d\d$/))
var sortfn = ts_sort_date;
else if (itm.match(/^\d\d[\/.-]\d\d[\/.-]\d\d\d\d$/))
var sortfn = ts_sort_date;
else if (itm.match(/^\d\d[\/.-]\d\d[\/.-]\d\d$/))
var sortfn = ts_sort_date;
else if (itm.match(/^[\u00a3$\u20ac]/)) // pound dollar euro
var sortfn = ts_sort_currency;
else if (itm.match(/^[\d.,]+\%?$/))
var sortfn = ts_sort_numeric;
else
var sortfn = ts_sort_caseinsensitive;
Store DOM nodes in variables so that the DOM is not traversed each time
editChange:
for (var k = 0; k < oldClasses.length; k++) {
if (oldClasses[k] != "" && oldClasses[k] != "even" && oldClasses[k] != "odd")
newClassName += oldClasses[k] + " ";
}
To:
for (var k = 0, p = oldClasses.length; k < p; k++) {
var thisClass = oldClasses[k];
if (thisClass != "" && thisClass != "even" && thisClass != "odd")
newClassName += thisClass + " ";
}
Change:
for (var ti = 0; ti < tables.length ; ti++) {
if (!tables[ti].id) {
tables[ti].setAttribute('id','sortable_table_id_'+idnum);
++idnum;
}
ts_makeSortable(tables[ti]);
}
}
To:
for (var ti = 0, n = tables.length; ti < n ; ti++) {
var thisTable = tables[ti];
if (!thisTable.id) {
thisTable.setAttribute('id','sortable_table_id_'+idnum);
++idnum;
}
ts_makeSortable(thisTable);
}
}
Bug: the first (header) row is included in the row count, so only enable sorting when there are three or more rows
editChange:
// Work out a type for the column
if (table.rows.length <= 1) return;
To:
// Work out a type for the column.
if (table.rows.length < 3) return;
Change:
sortfn = ts_sort_caseinsensitive;
if (itm.match(/^\d\d[\/. -][a-zA-Z]{3}[\/. -]\d\d\d\d$/))
sortfn = ts_sort_date;
if (itm.match(/^\d\d[\/.-]\d\d[\/.-]\d\d\d\d$/))
sortfn = ts_sort_date;
if (itm.match(/^\d\d[\/.-]\d\d[\/.-]\d\d$/))
sortfn = ts_sort_date;
if (itm.match(/^[\u00a3$\u20ac]/)) // pound dollar euro
sortfn = ts_sort_currency;
if (itm.match(/^[\d.,]+\%?$/))
sortfn = ts_sort_numeric;
To:
if (itm.match(/^[^\d]+$/))
var sortfn = ts_sort_caseinsensitive;
else if (itm.match(/^[\d.,]+\%?$/))
var sortfn = ts_sort_numeric;
else if (itm.match(/^\d\d[\/. -][a-zA-Z]{3}[\/. -]\d\d\d\d$/))
var sortfn = ts_sort_date;
else if (itm.match(/^\d\d[\/.-]\d\d[\/.-]\d\d\d\d$/))
var sortfn = ts_sort_date;
else if (itm.match(/^\d\d[\/.-]\d\d[\/.-]\d\d$/))
var sortfn = ts_sort_date;
else if (itm.match(/^[\u00a3$\u20ac]/)) // pound dollar euro
var sortfn = ts_sort_currency;
else
var sortfn = ts_sort_caseinsensitive;
Proposal: "sortreverse" header cell class for default reverse sorting of a column (SharkD (talk))
editThis proposal is meant to make it possible that a certain column should be sorted in reverse order by default. This works similarly to the "unsortable" class, in that the class is added to the column header, not the table.
Change:
// 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];
if ((" "+cell.className+" ").indexOf(" unsortable ") == -1) {
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>';
}
}
To:
// We have a first row: assume it's the header, and make its contents clickable links
for (var i = 0, n = firstRow.cells.length; i < n; i++) {
var cell = firstRow.cells[i];
var cellClass = " " + cell.className + " ";
if (cellClass.indexOf(" unsortable ") == -1) {
if (cellClass.indexOf(" sortreverse ") == -1)
cell.innerHTML += ' <a href="#" class="sortheader" onclick="ts_resortTable(this);return false;"><span class="sortarrow" sortdir="up"><img src="'+ ts_image_path + ts_image_none + '" alt="Sort in ascending order."/></span></a>';
else
cell.innerHTML += ' <a href="#" class="sortheader" onclick="ts_resortTable(this);return false;"><span class="sortarrow" sortdir="down"><img src="'+ ts_image_path + ts_image_none + '" alt="Sort in descending order."/></span></a>';
}
}
Change:
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');
}
To:
if (reverse) {
span.innerHTML = '<img src="'+ ts_image_path + ts_image_down + '" alt="Sort in ascending order."/>';
newRows.reverse();
span.setAttribute('sortdir','up');
} else {
span.innerHTML = '<img src="'+ ts_image_path + ts_image_up + '" alt="Sort in descending order."/>';
span.setAttribute('sortdir','down');
}
Change:
// 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;
To:
// Delete any other arrows there may be showing
var spans = getElementsByClassName(tr, "span", "sortarrow");
for (var i = 0, n = spans.length; i < n; i++) {
var thisSpan = spans[i];
if (thisSpan != span) {
var cellClass = " " + thisSpan.parentNode.parentNode.className + " ";
if (cellClass.indexOf(" sortreverse ") == -1) {
thisSpan.setAttribute("sortdir","up");
thisSpan.innerHTML = '<img src="'+ ts_image_path + ts_image_none + '" alt="Sort in ascending order."/>';
} else {
thisSpan.setAttribute("sortdir","down");
thisSpan.innerHTML = '<img src="'+ ts_image_path + ts_image_none + '" alt="Sort in descending order."/>';
}
}
}
Remove all brackets from conditions with only a single line of code
editChange:
if (ts_europeandate == false) {
return date.substr(6,4)+date.substr(0,2)+date.substr(3,2);
} else {
return date.substr(6,4)+date.substr(3,2)+date.substr(0,2);
}
To:
if (ts_europeandate == false)
return date.substr(6,4)+date.substr(0,2)+date.substr(3,2);
else
return date.substr(6,4)+date.substr(3,2)+date.substr(0,2);
Use literal definitions for arrays
editChange:
var newRows = new Array();
To:
var newRows = [];
Change:
newRows[newRows.length] = new Array(row, keyText, oldIndex);
To:
newRows[newRows.length] = [row, keyText, oldIndex];
Remove all semicolons
editChange:
var cs = el.childNodes;
To:
var cs = el.childNodes
The reason is so that it aligns more nicely and doesn't break onto new lines like inline elements tend to do. This involves wrapping each header cell within its own table. The existing header text is placed in the first cell of the new table; the clickable icon is placed in the second cell. All style/class attributes are copied to the new tables/cells, except for the "sortable" class which should not be copied.
Change the ts_makeSortable()
function to this:
function ts_makeSortable(table) {
var newTableClass = (" " + table.className + " ").replace(" sortable ", " ");
if (table.rows && table.rows.length > 0) {
if (table.tHead && table.tHead.rows.length > 0)
var firstRow = table.tHead.rows[table.tHead.rows.length - 1];
else
var 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, n = firstRow.cells.length; i < n; i++) {
var cell = firstRow.cells[i];
var cellClass = " " + cell.className + " ";
var cellType = cell.tagName.toLowerCase();
var newTable = document.createElement('table');
var newTbody = document.createElement('tbody');
var newRow = document.createElement('tr');
var newCell1 = document.createElement(cellType);
while (cell.hasChildNodes())
newCell1.appendChild(cell.removeChild(cell.firstChild));
cell.style.padding = '0px';
newTable.className = newTableClass;
newTable.style.border = '0px';
newTable.style.margin = '0px';
newTable.style.width = '100%';
newCell1.className = cellClass;
newCell1.style.border = '0px';
newRow.appendChild(newCell1);
if (cellClass.indexOf(" unsortable ") == -1) {
var newCell2 = document.createElement(cellType);
if (cellClass.indexOf(" sortreverse ") == -1)
newCell2.innerHTML = '<a href="#" class="sortheader" onclick="ts_resortTable(this);return false;"><span class="sortarrow" sortdir="up"><img src="' + ts_image_path + ts_image_none + '" alt="Sort in ascending order."/></span></a>';
else
newCell2.innerHTML = '<a href="#" class="sortheader" onclick="ts_resortTable(this);return false;"><span class="sortarrow" sortdir="down"><img src="' + ts_image_path + ts_image_none + '" alt="Sort in descending order."/></span></a>';
newCell2.className = cellClass;
newCell2.style.border = '0px';
newCell2.style.width = '12px';
newRow.appendChild(newCell2);
}
newTbody.appendChild(newRow);
newTable.appendChild(newTbody);
cell.appendChild(newTable);
}
if (ts_alternate_row_colors)
ts_alternate(table);
}
Change:
var td = lnk.parentNode;
To:
var td = lnk.parentNode.parentNode.parentNode.parentNode.parentNode;
Change:
itm.match(/^[\u00a3$\u20ac]/)
To:
itm.match(/^[\u00a3$\u20ac\u00a5]/)
I'm not as enthusiastic about this one. There's no real sense in beginning to evaluate expressions and then not continuing to handle all types of them. Anyway, the change amounts to adding the following:
else if (itm.match(/^[\d\.,]+\s*[\/\:]\s*[\d\.,]+$/))
var sortfn = ts_sort_fraction;
And:
function ts_sort_fraction(a, b) {
a[1] = a[1].replace(/\s+/g, '');
b[1] = b[1].replace(/\s+/g, '');
var aa1 = a[1].match(/^[\d\.,]+[\/\:]/)[0].replace(/[\/\:]/, '');
var aa2 = a[1].match(/[\/\:][\d\.,]+$/)[0].replace(/[\/\:]/, '');
var bb1 = b[1].match(/^[\d\.,]+[\/\:]/)[0].replace(/[\/\:]/, '');
var bb2 = b[1].match(/[\/\:][\d\.,]+$/)[0].replace(/[\/\:]/, '');
if (ts_europeandate == true) {
aa1 = aa1.replace(/\./g, "");
aa2 = aa2.replace(/\./g, "");
bb1 = bb1.replace(/\./g, "");
bb2 = bb2.replace(/\./g, "");
} else {
aa1 = aa1.replace(/,/g, "");
aa2 = aa2.replace(/,/g, "");
bb1 = bb1.replace(/,/g, "");
bb2 = bb2.replace(/,/g, "");
}
var aa = parseFloat(aa1) / parseFloat(aa2);
var bb = parseFloat(bb1) / parseFloat(bb2);
return (aa != bb ? aa - bb : a[2] - b[2]);
}
Note that the above code interprets the colon in addition to the forward slash as signifying a fraction or ratio. This may present a problem with certain dates or times.
Proposal: Increase the number of detected date formats; split them into different functions. (SharkD (talk))
editIn its current status, the script uses a lot of code to detect only a few date formats. This change is meant to open the sorting function up to more date formats as well as split them the different formate into separate functions, thereby reducing the number of conditional statements required.
Change:
sortfn = ts_sort_caseinsensitive;
if (itm.match(/^\d\d[\/. -][a-zA-Z]{3}[\/. -]\d\d\d\d$/))
sortfn = ts_sort_date;
if (itm.match(/^\d\d[\/.-]\d\d[\/.-]\d\d\d\d$/))
sortfn = ts_sort_date;
if (itm.match(/^\d\d[\/.-]\d\d[\/.-]\d\d$/))
sortfn = ts_sort_date;
if (itm.match(/^[\u00a3$\u20ac]/)) // pound dollar euro
sortfn = ts_sort_currency;
if (itm.match(/^[\d.,]+\%?$/))
sortfn = ts_sort_numeric;
To:
if (itm.match(/^\d{1,2}[\/\.\-]\d{1,2}[\/\.\-](\d{2}|\d{4})$/)) // matches: D(D)-M(M)-YY(YY) or M(M)-D(D)-YY(YY)
var sortfn = ts_sort_date_1;
else if (itm.match(/^(\w+[\/\.\- ]\d{1,2}|\d{1,2}[\/\.\- ]\w+),?[\/\.\- ](\d{2}|\d{4})$/)) // matches: D(D)-MONTHABV-YY(YY) or MONTHABV-D(D)-YY(YY) or MONTHABV D(D), YY(YY)
var sortfn = ts_sort_date_2;
else if (itm.match(/^[\u00a3$\u20ac\u00a5]/)) // pound dollar euro yen
var sortfn = ts_sort_currency;
else if (itm.match(/^[\d\.\,]+\%?$/)) // matches: nn.nnn or nn,nnn or nn.nnn% or nn,nnn% or nn.nnn,nnn% or nn,nnn.nnn%
var sortfn = ts_sort_numeric;
else
var sortfn = ts_sort_caseinsensitive;
Change:
function ts_sort_date(a,b) {
var aa = ts_dateToSortKey(a[1]);
var bb = ts_dateToSortKey(b[1]);
return (aa < bb ? -1 : aa > bb ? 1 : a[2] - b[2]);
}
To:
function ts_sort_date_1(a, b) {
var aa = ts_dateToSortKey_1(a[1]);
var bb = ts_dateToSortKey_1(b[1]);
return (aa < bb ? -1 : aa > bb ? 1 : a[2] - b[2]);
}
function ts_sort_date_2(a, b) {
var aa = ts_dateToSortKey_2(a[1]);
var bb = ts_dateToSortKey_2(b[1]);
return (aa < bb ? -1 : aa > bb ? 1 : a[2] - b[2]);
}
Change:
function ts_dateToSortKey(date) {
// y2k notes: two digit years less than 50 are treated as 20XX, greater than 50 are treated as 19XX
if (date.length == 11) {
switch (date.substr(3,3).toLowerCase()) {
case "jan": var month = "01"; break;
case "feb": var month = "02"; break;
case "mar": var month = "03"; break;
case "apr": var month = "04"; break;
case "may": var month = "05"; break;
case "jun": var month = "06"; break;
case "jul": var month = "07"; break;
case "aug": var month = "08"; break;
case "sep": var month = "09"; break;
case "oct": var month = "10"; break;
case "nov": var month = "11"; break;
case "dec": var month = "12"; break;
// default: var month = "00";
}
return date.substr(7,4)+month+date.substr(0,2);
} else if (date.length == 10) {
if (ts_europeandate == false) {
return date.substr(6,4)+date.substr(0,2)+date.substr(3,2);
} else {
return date.substr(6,4)+date.substr(3,2)+date.substr(0,2);
}
} else if (date.length == 8) {
yr = date.substr(6,2);
if (parseInt(yr) < 50) {
yr = '20'+yr;
} else {
yr = '19'+yr;
}
if (ts_europeandate == true) {
return yr+date.substr(3,2)+date.substr(0,2);
} else {
return yr+date.substr(0,2)+date.substr(3,2);
}
}
return "00000000";
}
To:
function ts_dateToSortKey_1(date) {
// matches: D(D)-M(M)-YY(YY) or M(M)-D(D)-YY(YY)
// y2k notes: two digit years less than 50 are treated as 20XX, greater than 50 are treated as 19XX
date = date.replace(/[\/\.]/g, '-')
var dateLen = date.length
var firstIdx = date.indexOf('-')
var secndIdx = date.indexOf('-', firstIdx + 1)
var yearIdx = secndIdx + 1
var yearLen = dateLen - yearIdx
var secndLen = dateLen - yearLen - firstIdx - 2
var year = parseInt(date.substr(yearIdx, yearLen))
if (yearLen == 2)
year += year < 50 ? 2000 : 1900
if (ts_europeandate) {
var month = date.substr(firstIdx + 1, secndLen)
var day = date.substr(0, firstIdx)
} else {
var month = date.substr(0, firstIdx)
var day = date.substr(firstIdx + 1, secndLen)
}
month = parseInt(month)
day = parseInt(day)
if (month < 10) month = "0" + month
if (day < 10) day = "0" + day
return "".concat(year, month, day)
}
function ts_dateToSortKey_2(date) {
// matches: D(D)-MONTHABV-YY(YY) or MONTHABV-D(D)-YY(YY) or MONTHABV D(D), YY(YY)
// y2k notes: two digit years less than 50 are treated as 20XX, greater than 50 are treated as 19XX
// the following is valid only for the English language, and should ideally be set as a global variable in "common.js"
var monthStr = "janfebmaraprmayjunjulaugsepoctnovdec"
var monthLen = 3
var monthNam = date.match(/[^\d\/\.\- ]+/)[0]
var monthAbv = monthNam.substr(0, monthLen)
date = date.replace(/[^\d\/\.\- ]+/, monthAbv)
date = date.replace(/[\/\. ]/g, '-')
date = date.replace(/,/g, '')
var dateLen = date.length
var firstIdx = date.indexOf('-')
var secndIdx = date.indexOf('-', firstIdx + 1)
var yearIdx = secndIdx + 1
var yearLen = dateLen - yearIdx
var secndLen = dateLen - yearLen - firstIdx - 2
var year = parseInt(date.substr(yearIdx, yearLen))
if (yearLen == 2)
year += year < 50 ? 2000 : 1900
if (date.charCodeAt(0) < 58) {
var month = date.substr(firstIdx + 1, secndLen)
var day = date.substr(0, firstIdx)
} else {
var month = date.substr(0, firstIdx)
var day = date.substr(firstIdx + 1, secndLen)
}
month = monthStr.indexOf(month.toLowerCase()) / monthLen + 1
day = parseInt(day)
if (month < 10) month = "0" + month
if (day < 10) day = "0" + day
return "".concat(year, month, day)
}
Proposal: change "sortable" from classname to attribute; add column attributes to force sorting function (SharkD (talk))
editThis proposal is to change the "sortable" table class from a class to an attribute and add a "sortorder" attribute to column headers. The first part would involve the following:
Change:
class="sortable"
To:
sortable="true"
The second part would allow users to force the use of a particular sorting function for a column. The "unsortable" class could also be merged with this item. I.e.:
Change:
sortfn = ts_sort_caseinsensitive;
if (itm.match(/^\d\d[\/. -][a-zA-Z]{3}[\/. -]\d\d\d\d$/))
sortfn = ts_sort_date;
if (itm.match(/^\d\d[\/.-]\d\d[\/.-]\d\d\d\d$/))
sortfn = ts_sort_date;
if (itm.match(/^\d\d[\/.-]\d\d[\/.-]\d\d$/))
sortfn = ts_sort_date;
if (itm.match(/^[\u00a3$\u20ac]/)) // pound dollar euro
sortfn = ts_sort_currency;
if (itm.match(/^[\d.,]+\%?$/))
sortfn = ts_sort_numeric;
To something like this (a rough sketch):
if (cell.getAttribute('sortorder'))
sortfn = cell.getAttribute('sortorder')
else {
sortfn = ts_sort_caseinsensitive;
if (itm.match(/^\d\d[\/. -][a-zA-Z]{3}[\/. -]\d\d\d\d$/))
sortfn = ts_sort_date;
if (itm.match(/^\d\d[\/.-]\d\d[\/.-]\d\d\d\d$/))
sortfn = ts_sort_date;
if (itm.match(/^\d\d[\/.-]\d\d[\/.-]\d\d$/))
sortfn = ts_sort_date;
if (itm.match(/^[\u00a3$\u20ac]/)) // pound dollar euro
sortfn = ts_sort_currency;
if (itm.match(/^[\d.,]+\%?$/))
sortfn = ts_sort_numeric;
}