Utilisateur:Phe/sortable table.js
Note : après avoir enregistré la page, vous devrez forcer le rechargement complet du cache de votre navigateur pour voir les changements.
Mozilla / Firefox / Konqueror / Safari : maintenez la touche Majuscule (Shift) en cliquant sur le bouton Actualiser (Reload) ou pressez Maj-Ctrl-R (Cmd-R sur Apple Mac) ;
Firefox (sur GNU/Linux) / Chrome / Internet Explorer / Opera : maintenez la touche Ctrl en cliquant sur le bouton Actualiser ou pressez Ctrl-F5.// <pre>
/**
* Adapté de http://kryogenix.org/code/browser/sorttable/ par Phe
* MIT licence, auteur Stuart Langridge, November 2003
*
* Principales modifications :
*
* Il est possible de spécifier qu'on ne peut pas effectuer de tri
* par rapport à certaines colonnes en leur donnant la class
* "non_triable".
*
* Lorsque des données sont manquantes il est difficile de deviner le
* type de données, on peut dans ce cas sélectionner l'algo utilisé
* en spécifiant l'algo comme nom de class de la colonne e.g.
* « ! class='tri_numerique' | intitulé colonne », les classes
* tri_numerique, tri_chaine et tri_date sont les seules reconnues
* actuellement.
*
* Le code a été assez nettement optimisé en vitesse en pre
* contruisant les chaînes a trié en dehors des fonctions de
* comparaison.
*
* Le code gérant la classe de ligne sortbottom a été supprimé,
* possible qu'il y ait des utilisations de ce truc mais c'est peu
* intuitif comme mode de tri.
*
* Problème connu:
*
* Les caractères unicode utilisés dans les entêtes de colonnes sont
* très moches sous win98.
*
* Localisation :
* le tri alpha ne trie pas correctement les accentués, que ce soit
* avec un linux localisé en en.US ou un win98 localisé en français.
* Le problème est (très) partiellement corrigé par tsfr_fixDiacritic()
* même problème pour les formats en virgule flottante, le script
* transforme 2,52 en 2.52 avant de faire les comparaisons.
*/
var tsfr_image_path = stylepath+"/common/images/";
var tsfr_image_up = "sort_up.gif";
var tsfr_image_down = "sort_down.gif";
var tsfr_image_none = "sort_none.gif";
function ts_parseFloat(num) {
if (!num) return 0;
num = num.replace(/ /, "");
num = parseFloat(num.replace(/,/, ""));
return (isNaN(num) ? 0 : num);
}
function tsfr_sortables_init()
{
// Find all tables with class sortable and make them sortable
if (!document.getElementsByTagName) return;
var tbls = document.getElementsByTagName("table");
for (var ti=0;ti<tbls.length;ti++) {
if ((' '+tbls[ti].className+' ').indexOf(" triable ") != -1) {
tsfr_makeSortable(tbls[ti]);
}
}
}
function tsfr_makeSortable(table)
{
if (table.rows && table.rows.length > 0) {
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;i<firstRow.cells.length;i++) {
var cell = firstRow.cells[i];
if ((" "+cell.className+" ").indexOf(" non_triable ") == -1) {
cell.innerHTML += ' <a href="#" class="sortheader" onclick="tsfr_resortTable(this);return false;"><span class="sortarrow"><img src="'+ tsfr_image_path + tsfr_image_none + '" alt="↓"/></span></a>';
}
}
}
function tsfr_getInnerText(el) {
if (typeof el == "string") return el;
if (typeof el == "undefined") return el;
if (el.innerText) return el.innerText; //Not needed but it is faster
var str = "";
var cs = el.childNodes;
var l = cs.length;
for (var i = 0; i < l; i++) {
switch (cs[i].nodeType) {
case 1: //ELEMENT_NODE
str += tsfr_getInnerText(cs[i]);
break;
case 3: //TEXT_NODE
str += cs[i].nodeValue;
break;
}
}
return str;
}
// used only on lowered string, so now need to handle upper case
// diacritic except in a few special case...
function tsfr_fixDiacritic(str)
{
// Il en manque plein...
str = str.replace(/[áàâä]/g,'a');
str = str.replace(/[éèêë]/g,'e');
str = str.replace(/[íîï]/g,'i');
str = str.replace(/[óôö]/g,'o');
str = str.replace(/[úûü]/g,'u');
str = str.replace(/[ýÿ]/g,'y');
str = str.replace(/[ç]/g,'c');
str = str.replace(/[Œœ]/g, 'oe');
str = str.replace(/[Ææ]/g, 'ae');
return str;
}
function tsfr_getSortFn(text, column_classname)
{
var sortfn = null;
if (column_classname) {
switch(column_classname) {
case 'tri_numerique':
sortfn = tsfr_sortNumeric;
break;
case 'tri_chaine':
sortfn = tsfr_sortCaseInsensitive;
break;
case 'tri_date':
sortfn = tsfr_sortDate;
break;
}
}
if (sortfn == null) {
sortfn = tsfr_sortCaseInsensitive;
// recognize / or - as date separator
if (text.match(/^\d\d[\/-]\d\d[\/-]\d\d\d\d$/)) {
sortfn = tsfr_sortDate;
// all string starting with digit are sorted as numeric
} else if (text.match(/^[-]?[\d]+/)) {
sortfn = tsfr_sortNumeric;
}
// prolly problematic in some case.
if (text.length == 0) sortfn = tsfr_sortNumeric;
}
return sortfn
}
// Used to speedup sort by pre-building the string to compare rather
// to do it in the sort function.
function tsfr_buildSortableText(cell, sortfn)
{
var aa = tsfr_getInnerText(cell);
if (sortfn == tsfr_sortCaseInsensitive) {
aa = aa.toLowerCase();
aa = tsfr_fixDiacritic(aa);
} else if (sortfn == tsfr_sortNumeric) {
// FIXME: is this locale dependant ?
aa = aa.replace(/,/g,'.');
aa = aa.replace(/ /g,'');
aa = parseFloat(aa);
if (isNaN(aa))
aa = -1E200;
} else if (sortfn == tsfr_sortDate) {
// y2k notes: all date must use four digits years format
aa = aa.substr(6,4) + aa.substr(3,2) + aa.substr(0,2);
}
return aa;
}
function tsfr_resortTable(lnk) {
//begin_time();
// get the span
var span;
for (var ci=0;ci<lnk.childNodes.length;ci++) {
if (lnk.childNodes[ci].tagName && lnk.childNodes[ci].tagName.toLowerCase() == 'span')
span = lnk.childNodes[ci];
}
var td = lnk.parentNode;
var column = td.cellIndex;
var table = getParent(td, "table");
// Work out a type for the column
if (table.rows.length <= 1) return;
var rowStart = (table.tHead && table.tHead.rows.length > 0 ? 0 : 1);
var itm = "";
for (var i = rowStart; i < table.rows.length; i++) {
if (table.rows[i].cells.length > column) {
itm = tsfr_getInnerText(table.rows[i].cells[column]);
itm = itm.replace(/^[\s\xa0]+/, "").replace(/[\s\xa0]+$/, "");
if (itm != "") break;
}
}
var sortfn = tsfr_getSortFn(itm, table.rows[0].cells[column].className);
var newRows = new Array();
for (j=1;j<table.rows.length;j++) {
newRows[j-1] = new Array(table.rows[j], tsfr_buildSortableText(table.rows[j].cells[column], sortfn));
}
newRows.sort(sortfn);
var arrow;
if (span.getAttribute("sortdir") == 'down') {
arrow = '<img src="'+ tsfr_image_path + tsfr_image_down + '" alt="↓"/>';
newRows.reverse();
span.setAttribute('sortdir','up');
} else {
arrow = '<img src="'+ tsfr_image_path + tsfr_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
for (i = 0; i < newRows.length; i++) {
table.tBodies[0].appendChild(newRows[i][0]);
}
// Delete any other arrows there may be showing
var allspans = document.getElementsByTagName("span");
for (var ci=0;ci<allspans.length;ci++) {
if (allspans[ci].className == 'sortarrow') {
// in the same table as us?
if (getParent(allspans[ci],"table") == getParent(lnk,"table")) {
allspans[ci].innerHTML = '<img src="'+ tsfr_image_path + tsfr_image_none + '" alt="↓"/>';
}
}
}
span.innerHTML = arrow;
//end_time();
}
// FIXME: what's the exact purpose of this ?
function getParent(el, pTagName) {
if (el == null) return null;
else if (el.nodeType == 1 && el.tagName.toLowerCase() == pTagName) // Gecko bug, supposed to be uppercase
return el;
else
return getParent(el.parentNode, pTagName);
}
function tsfr_sortDate(a,b) {
if (a[1]>b[1]) return 1;
if (a[1]<b[1]) return -1;
return 0;
}
function tsfr_sortNumeric(a,b) {
return a[1]-b[1];
}
function tsfr_sortCaseInsensitive(a,b) {
if (a[1]>b[1]) return 1;
if (a[1]<b[1]) return -1;
return 0;
}
//------- end sortable table
addOnloadHook(tsfr_sortables_init);
var millisecs;
var secs;
function begin_time()
{
date = new Date();
millisecs = date.getMilliseconds();
secs = date.getSeconds();
}
function end_time()
{
date = new Date();
var msec = date.getMilliseconds() - millisecs;
if (msec < 0) { msec += 1000; secs += 1; }
alert((date.getSeconds() - secs) + '.' + msec);
}
// </pre>