Utilisateur:Phe/sortable table.js
Un article de Wikipédia, l'encyclopédie libre.
Note : Après avoir publié la page, vous devrez forcer son rechargement pour voir les changements : Mozilla / Konqueror / Firefox : Shift-Ctrl-R, Internet Explorer / Opera : Ctrl-F5, Safari : Cmd-R.
// <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>