//====== //====== // // Template- TABLE_SORT_JS.IHT by S.Huang 07-MAR-05 / 27-NOV-06 // // Purpose- // // javascript functions to support table sorting // // Notes- // // - This script must be included in header of templates that // have tables with class="sortable_table" to be sorted. // - Items within and are not sorted // - Requires W3C DOM and Javascript 1.5 compliant browsers // (also works on IE 5.x which is not fully compliant). // - TH> note: I suspect the restriction to 1.5 had more // to do with the DOM support, which is not explicitly // tied to the version of Javascript. We test for DOM // support by testing the required DOM functionality // directly, as per industry standard. // // - Table must be in standard format: // // // // ... // // // ... // //
col1
// // - Currently, the
element is not supported. // // Modifications- // // 18-APR-05 SH / TH / KB 4=17168 // - Created. // // 26-APR-05 SH / SH / KB 4=17168 // - Treat number string starting with '0' as a decimal number. // // 6-MAY-05 SH / SH / SH 17= // - Correct a typo for function call getFullYear(). // // 5-MAY-06 SH / JY / SH 17= // - Supported float point sorting. // // 9-AUG-06 TH / SZ / TH 4=18545 // - Update search for sortable_table class attribute so that // it works on all browsers. // - Add workaround for Safari sometimes returning the #text node // as the target of the event. // // 10-AUG-06 TH / BH / TH 17= // - Fix date compare to work on non-IE browsers, which do not // accept ", undefined" being passed as the hour component. // - Allow single digit dates to be specified without a // leading 0. // - Explicitly exclude < javascript 1.2 so we don't have to test // for the existance of RegExp wherever we use it. // - Explicitly exclude browsers without minimum basic DOM support // by testing for getElementsByTagName. // - Use various standardized cross-browser event handling // facilities from event_js.iht. // // 22-AUG-06 TH / BH / HD 17=18635 // - Correct compare to sort on the actual text node, rather // than all the contents of the array passed in. // - Correct compare to sort alphabetically if there are any // alphabetic characters in any elements in the column // being sorted. // // 27-NOV-06 TH / BH / TH 4=18616 // - Update getDateStr to drop the comma output before // the hh:mm field, as it is apparently unnecessary and // Safari has problems parsing it. // // 04-Jul-07 BG / BG / BG 12=18420 // - Converted to from .iht to .js. // //====== //====== // - The table comparison was originally implemented by Paul Sowden. // - Some modifications have been added for Medianet specific purposes. var prjNum="225"; var sortCount = new Array(); // - Alphabetic compare is case insensitive. function compare(a,b) { var au = new String(a[0]); var bu = new String(b[0]); // - parseFloat will read the first number in the // string, so "92 Hal" would return 92. In this case, // since there are alphabetic characters present, // alphaCharsInCol will be set. // - Strings starting with a number followed by non // alphabetic characters will currently be sorted // only based on the starting number. var an = 0; var bn = 0; if (!alphaCharsInCol) { an = parseFloat(au); bn = parseFloat(bu); } if ( alphaCharsInCol || isNaN(an) || isNaN(bn)) { if(isDate(au) && isDate(bu)) { var dateStr1=getDateStr(au); var dateStr2=getDateStr(bu); var date1 = new Date(dateStr1); var date2 = new Date(dateStr2); return date1-date2; } else { var as = au.toLowerCase(); var bs = bu.toLowerCase(); if (as > bs) { return 1; } else { return -1; } } } else { return an - bn; } } // The date on Medianet tables is in format of "Mon dd {yyyy}{hh:mm}" var regDate=/^\s*(\w{3}\s+\d{1,2})\s*(\d{4})?\s*(\d{1,2}:\d{1,2})?/; function isDate(str) { if(str.search(regDate) != -1) { return true; } else { return false; } } function getDateStr(str) { var re = new RegExp(regDate); var match = re.exec(str); if (match[2] == "" || match[2] == undefined) { if(prjNum=="029") { match[2]="1983"; } else { Today = new Date(); match[2]=Today.getFullYear().toString(); } } // Construct date string in format "Mon dd, yyyy hh:mm" which is // recognized by the Date constructor. var finalDate = match[1] + ", " + match[2]; if (match[3] != "" && match[3] != undefined) { finalDate += " " + match[3]; } return finalDate; } // DOM table sorter borrowed (but modified) from Paul Sowden // Finally somone that does it the right way // function borrowed from those lovely people at the w3c function getConcatenedTextContent(node) { var _result = ""; if (node == null) { return _result; } var childrens = node.childNodes; var i = 0; while (i < childrens.length) { var child = childrens.item(i); switch (child.nodeType) { case 1: // ELEMENT_NODE case 5: // ENTITY_REFERENCE_NODE _result += getConcatenedTextContent(child); break; case 3: // TEXT_NODE case 2: // ATTRIBUTE_NODE case 4: // CDATA_SECTION_NODE _result += child.nodeValue; break; case 6: // ENTITY_NODE case 7: // PROCESSING_INSTRUCTION_NODE case 8: // COMMENT_NODE case 9: // DOCUMENT_NODE case 10: // DOCUMENT_TYPE_NODE case 11: // DOCUMENT_FRAGMENT_NODE case 12: // NOTATION_NODE // skip break; } i ++; } return _result; } var alphaCharsInCol; function sort(e) { // Skip if the necessary level of DOM support isn't present. if (!document.getElementsByTagName) return; // - We can't pass extra arguments to the compare routine, as its // just a function pointer of a constrained type. // - We want to ensure if there are any alphabetic entries in // the current column, an alphabetic sort is used, but compare // can only compare the current 2 items being sorted. // - Thus, we signal whether to use an alphabetic sort from // the outside. alphaCharsInCol = false; var ev = dy_get_event(e); var el = dy_get_event_target(ev); var a = new Array(); var name = el.firstChild.nodeValue; var dad = el.parentNode; var node; var colInx; // Determine which column we are sorting on. for (var i = 0; (node = dad.getElementsByTagName("td").item(i)); i++) { if (node.firstChild.nodeValue == name) { colInx = i; sortCount[colInx] += 1; } else { // Clearing the sort count for column i as the data is no // longer sorted by column i. sortCount[i] = 0; } } var tbody = dad.parentNode.parentNode.getElementsByTagName("tbody").item(0); // For every row in the table... for (var j = 0; (node = tbody.getElementsByTagName("tr").item(j)); j++) { a[j] = new Array(); // The required sort text. a[j][0] = getConcatenedTextContent( node.getElementsByTagName("td").item(colInx)); alphaCharsInCol = (alphaCharsInCol || a[j][0].match(/[a-zA-Z]/)); // - sh>The following two lines were designed to sort the original // table by surname (in column 2) and name (in column 1) after // whatever column is chosen to sort in first. // - We leave this design here for the future reference in case // we ever need a second sort choice // a[j][1] = getConcatenedTextContent(node.getElementsByTagName("td").item(1)); // a[j][2] = getConcatenedTextContent(node.getElementsByTagName("td").item(0)); a[j][3] = node; } a.sort(compare); // - SH>The following code from the owner won't work if the first two // rows in original display remain their previous positions after // sorting. I.e. In such cases, the first time column head click // always leads to a descending order sorting. // - We introduce a sortCount array to solve this problem. /*-------------------------------------------------------- // not a perfect way to check, but hell, it suits me fine if (a[0][0] == getConcatenedTextContent(tbody.getElementsByTagName("tr").item(0).getElementsByTagName("td").item(i)) && a[1][0] == getConcatenedTextContent(tbody.getElementsByTagName("tr").item(1).getElementsByTagName("td").item(i))) a.reverse(); ---------------------------------------------------------*/ // For consecutive clicks(sorting) under a specific column, the // even number click leads to a descending order sorting. if(sortCount[colInx]%2 == 0) a.reverse(); for (var j = 0; j < a.length; j++) { // - Since each node is unique, appending the nodes will move them // from their current location. // - This has issues on Netscape 7 which has problem re-rendering // the table. Since there's no easy to find workaround and // Netscape 7 has less than 1% market share, we won't be fixing // the issue at this time. tbody.appendChild(a[j][3]); } } function init(e) { // Skip if the necessary level of DOM support isn't present. if (!document.getElementsByTagName) return; // Tables to be sorted must have class="sortable_table" in // tag var tbl; for (var j=0; (tbl=document.body.getElementsByTagName("table").item(j)); j++) { var namedItem = tbl.attributes.getNamedItem("class"); // - tbl.getAttribute("class") doesn't work on Internet // Explorer. Thus, we have to use a different method to get // the class attribute. // - tbl.attributes.getNamedItem("class") always returns an object on // Internet Explorer. On some other browsers (eg. Firefox) // it returns null if the attribute is not found, so we have to check // that the attribute exists before accessing the value. if (namedItem && namedItem.value == "sortable_table") { var thead = tbl.getElementsByTagName("thead").item(0); var node; for (var i = 0; (node =thead.getElementsByTagName("td").item(i)); i++) { if (node.addEventListener) { sortCount[i] = 0; node.addEventListener("click",sort,false); } else if (node.attachEvent) { sortCount[i] = 0; node.attachEvent("onclick",sort); } } } } } dy_attach_onload_event(init);