split in two
[plewww.git] / plekit / tablesort / customsort.js
diff --git a/plekit/tablesort/customsort.js b/plekit/tablesort/customsort.js
new file mode 100644 (file)
index 0000000..a766898
--- /dev/null
@@ -0,0 +1,356 @@
+/*\r
+    sortEnglishDateTime\r
+    -----------------------\r
+\r
+    This function sorts English dateTime vaues such as:\r
+\r
+    1st January 2003, 23:32:01\r
+    23/03/1972 à 10:22:22\r
+    1970/13/03 at 23:22:01\r
+    \r
+    The function is "safe" i.e. non-dateTime data (like the word "Unknown") can be passed in and is sorted properly.\r
+*/\r
+var sortEnglishDateTime = fdTableSort.sortNumeric;\r
+\r
+function sortEnglishDateTimePrepareData(tdNode, innerText) {\r
+        // You can localise the function here\r
+        var months = ['january','february','march','april','may','june','july','august','september','october','november','december','jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec'];\r
+\r
+        // Lowercase the text\r
+        var aa = innerText.toLowerCase();\r
+\r
+        // Replace the longhand months with an integer equivalent\r
+        for(var i = 0; i < months.length; i++) {\r
+                aa = aa.replace(months[i], (i+13)%12);\r
+        };\r
+\r
+        // Replace multiple spaces and anything that is not valid in the parsing of the date, then trim\r
+        aa = aa.replace(/\s+/g, " ").replace(/([^\d\s\/-:.])/g, "").replace(/^\s\s*/, '').replace(/\s\s*$/, '');\r
+\r
+        // No timestamp at the end, then return -1\r
+        if(aa.search(/(\d){2}:(\d){2}(:(\d){2})?$/) == -1) { return -1; };\r
+\r
+        // Grab the timestamp\r
+        var timestamp = aa.match(/(\d){2}:(\d){2}(:(\d){2})?$/)[0].replace(/:/g, "");\r
+\r
+        // Make the timestamp 6 characters by default\r
+        if(timestamp.length == 4) { timestamp += "00"; };\r
+\r
+        // Remove it from the string to assist the date parser, then trim\r
+        aa = aa.replace(/(\d){2}:(\d){2}(:(\d){2})?$/, "").replace(/\s\s*$/, '');\r
+\r
+        // If you want the parser to favour the parsing of European dd/mm/yyyy dates then leave this set to "true"\r
+        // If you want the parser to favour the parsing of American mm/dd/yyyy dates then set to "false"\r
+        var favourDMY = true;\r
+\r
+        // If you have a regular expression you wish to add, add the Object to the end of the array\r
+        var dateTest = [\r
+                       { regExp:/^(0?[1-9]|1[012])([- \/.])(0?[1-9]|[12][0-9]|3[01])([- \/.])((\d\d)?\d\d)$/, d:3, m:1, y:5 },  // mdy\r
+                       { regExp:/^(0?[1-9]|[12][0-9]|3[01])([- \/.])(0?[1-9]|1[012])([- \/.])((\d\d)?\d\d)$/, d:1, m:3, y:5 },  // dmy\r
+                       { regExp:/^(\d\d\d\d)([- \/.])(0?[1-9]|1[012])([- \/.])(0?[1-9]|[12][0-9]|3[01])$/, d:5, m:3, y:1 }      // ymd\r
+                       ];\r
+\r
+        var start,y,m,d;\r
+        var cnt = 0;\r
+        var numFormats = dateTest.length;\r
+        while(cnt < numFormats) {\r
+               start = (cnt + (favourDMY ? numFormats + 1 : numFormats)) % numFormats;\r
+               if(aa.match(dateTest[start].regExp)) {\r
+                       res = aa.match(dateTest[start].regExp);\r
+                       y = res[dateTest[start].y];\r
+                       m = res[dateTest[start].m];\r
+                       d = res[dateTest[start].d];\r
+                       if(m.length == 1) m = "0" + String(m);\r
+                       if(d.length == 1) d = "0" + String(d);\r
+                       if(y.length != 4) y = (parseInt(y) < 50) ? "20" + String(y) : "19" + String(y);\r
+\r
+                       return y+String(m)+d+String(timestamp);\r
+               };\r
+               cnt++;\r
+        };\r
+        return -1;\r
+};\r
+\r
+/*\r
+    sortAlphaNumeric\r
+    -----------------------\r
+\r
+    This function sorts alphaNumeric values e.g. 1, e, 1a, -23c, 54z\r
+    \r
+    Notice how the prepareData function actually returns an Array i.e. you are not limited\r
+    in the type of data you return to the tableSort script.\r
+*/\r
+function sortAlphaNumericPrepareData(tdNode, innerText){\r
+        var aa = innerText.toLowerCase().replace(" ", "");\r
+        var reg = /((\-|\+)?(\s+)?[0-9]+\.([0-9]+)?|(\-|\+)?(\s+)?(\.)?[0-9]+)([a-z]+)/;\r
+\r
+        if(reg.test(aa)) {\r
+                var aaP = aa.match(reg);\r
+                return [aaP[1], aaP[8]];\r
+        };\r
+\r
+        // Return an array\r
+        return isNaN(aa) ? ["",aa] : [aa,""];\r
+}\r
+\r
+function sortAlphaNumeric(a, b){\r
+        // Get the previously prepared array\r
+        var aa = a[fdTableSort.pos];\r
+        var bb = b[fdTableSort.pos];\r
+\r
+        // If they are equal then return 0\r
+        if(aa[0] == bb[0] && aa[1] == bb[1]) { return 0; };\r
+\r
+        // Check numeric parts if not equal\r
+        if(aa[0] != bb[0]) {\r
+                if(aa[0] != "" && bb[0] != "") { return aa[0] - bb[0]; };\r
+                if(aa[0] == "" && bb[0] != "") { return -1; };\r
+                return 1;\r
+        };\r
+        \r
+        // Check alpha parts if numeric parts equal\r
+        if(aa[1] == bb[1]) return 0;\r
+        if(aa[1] < bb[1])  return -1;\r
+        return 1;\r
+}\r
+\r
+/*\r
+    sortDutchCurrencyValues\r
+    -----------------------\r
+\r
+    This function sorts Dutch currency values (of the type 100.000,00)\r
+    The function is "safe" i.e. non-currency data (like the word "Unknown") can be passed in and is sorted properly.\r
+*/\r
+var sortDutchCurrencyValues = fdTableSort.sortNumeric;\r
+\r
+function sortDutchCurrencyValuesPrepareData(tdNode, innerText) {\r
+        innerText = parseInt(innerText.replace(/[^0-9\.,]+/g, "").replace(/\./g,"").replace(",","."));\r
+        return isNaN(innerText) ? "" : innerText;\r
+}\r
+\r
+/*\r
+   sortByTwelveHourTimestamp\r
+   -------------------------\r
+\r
+   This custom sort function sorts 12 hour timestamps of an hour/minute nature.\r
+   The hour/minute dividor can be a full-stop or a colon and it correctly calculates that 12.30am is before 1am etc\r
+   The am/pm part can be written in lower or uppercase and can optionally contain full-stops e.g.\r
+\r
+   am, a.m, a.m., AM, A.M etc\r
+\r
+   Additionally, the values "12 midnight" and "12 noon" are also handled correctly.\r
+\r
+   The question remains... does "12p.m." mean "midnight" or "12 noon"? I've decided here that it's 12 noon.\r
+\r
+   The function is "safe" i.e. non-timestamp data (like the word "Unknown") can be passed in and is sorted properly.\r
+*/\r
+var sortByTwelveHourTimestamp = fdTableSort.sortNumeric;\r
+\r
+function sortByTwelveHourTimestampPrepareData(tdNode, innerText) {\r
+        tmp = innerText\r
+        innerText = innerText.replace(":",".");\r
+\r
+        // Check for the special cases of "12 noon" or "12 midnight"\r
+        if(innerText.search(/12([\s]*)?noon/i) != -1) return "12.00";\r
+        if(innerText.search(/12([\s]*)?midnight/i) != -1) return "24.00";\r
+\r
+        var regExpPM = /^([0-9]{1,2}).([0-9]{2})([\s]*)?(p[\.]?m)/i;\r
+        var regExpAM = /^([0-9]{1,2}).([0-9]{2})([\s]*)?(a[\.]?m)/i;\r
+\r
+        if(innerText.search(regExpPM) != -1) {\r
+                var bits = innerText.match(regExpPM);\r
+                if(parseInt(bits[1]) < 12) { bits[1] = parseInt(bits[1]) + 12; }\r
+        } else if(innerText.search(regExpAM) != -1) {\r
+                var bits = innerText.match(regExpAM);\r
+                if(bits[1] == "12") { bits[1] = "00"; }\r
+        } else return "";\r
+\r
+        if(bits[2].length < 2) { bits[2] = "0" + String(bits[2]); }\r
+\r
+        innerText = bits[1] + "." + String(bits[2]);\r
+\r
+        return isNaN(innerText) ? "" : innerText;\r
+}\r
+/*\r
+   sortEnglishLonghandDateFormat\r
+   -----------------------------\r
+\r
+   This custom sort function sorts dates of the format:\r
+\r
+   "12th April, 2006" or "12 April 2006" or "12-4-2006" or "12 April" or "12 4" or "12 Apr 2006" etc\r
+\r
+   The function expects dates to be in the format day/month/year. Should no year be stipulated,\r
+   the function treats the year as being the current year.\r
+\r
+   The function is "safe" i.e. non-date data (like the word "Unknown") can be passed in and is sorted properly.\r
+*/\r
+var sortEnglishLonghandDateFormat = fdTableSort.sortNumeric;\r
+\r
+function sortEnglishLonghandDateFormatPrepareData(tdNode, innerText) {\r
+        var months = ['january','february','march','april','may','june','july','august','september','october','november','december'];\r
+\r
+        var aa = innerText.toLowerCase();\r
+\r
+        // Replace the longhand months with an integer equivalent\r
+        for(var i = 0; i < 12; i++) {\r
+                aa = aa.replace(months[i], i+1).replace(months[i].substring(0,3), i+1);\r
+        }\r
+\r
+        // If there are still alpha characters then return -1\r
+        if(aa.search(/a-z/) != -1) return -1;\r
+\r
+        // Replace multiple spaces and anything that is not numeric\r
+        aa = aa.replace(/\s+/g, " ").replace(/[^\d\s]/g, "");\r
+\r
+        // If were left with nothing then return -1\r
+        if(aa.replace(" ", "") == "") return -1;\r
+\r
+        // Split on the (now) single spaces\r
+        aa = aa.split(" ");\r
+\r
+        // If something has gone terribly wrong then return -1\r
+        if(aa.length < 2) return -1;\r
+\r
+        // If no year stipulated, then add this year as default\r
+        if(aa.length == 2) {\r
+                aa[2] = String(new Date().getFullYear());\r
+        }\r
+\r
+        // Equalise the day and month\r
+        if(aa[0].length < 2) aa[0] = "0" + String(aa[0]);\r
+        if(aa[1].length < 2) aa[1] = "0" + String(aa[1]);\r
+\r
+        // Deal with Y2K issues\r
+        if(aa[2].length != 4) {\r
+                aa[2] = (parseInt(aa[2]) < 50) ? '20' + aa[2] : '19' + aa[2];\r
+        }\r
+\r
+        // YMD (can be used as integer during comparison)\r
+        return aa[2] + String(aa[1]) + aa[0];\r
+}\r
+/*\r
+   sortIPAddress\r
+   -------------\r
+\r
+   This custom sort function correctly sorts IP addresses i.e. it checks all of the address parts and not just the first.\r
+\r
+   The function is "safe" i.e. non-IP address data (like the word "Unknown") can be passed in and is sorted properly.\r
+*/\r
+var sortIPAddress = fdTableSort.sortNumeric;\r
+\r
+function sortIPAddressPrepareData(tdNode, innerText) {\r
+        // Get the innerText of the TR nodes\r
+        var aa = innerText;\r
+\r
+        // Remove spaces\r
+        aa = aa.replace(" ","");\r
+\r
+        // If not an IP address then return -1\r
+        if(aa.search(/^([0-9]{1,3}).([0-9]{1,3}).([0-9]{1,3}).([0-9]{1,3})$/) == -1) return -1;\r
+\r
+        // Split on the "."\r
+        aa = aa.split(".");\r
+\r
+        // If we don't have 4 parts then return -1\r
+        if(aa.length != 4) return -1;\r
+\r
+        var retVal = "";\r
+\r
+        // Make all the parts an equal length and create a master integer\r
+        for(var i = 0; i < 4; i++) {\r
+                retVal += (String(aa[i]).length < 3) ? "0000".substr(0, 3 - String(aa[i]).length) + String(aa[i]) : aa[i];\r
+        }\r
+\r
+        return retVal;\r
+}\r
+/*\r
+   sortScientificNotation\r
+   ----------------------\r
+\r
+   This custom sort function sorts numbers stipulated in scientific notation\r
+\r
+   The function is "safe" i.e. data like the word "Unknown" can be passed in and is sorted properly.\r
+\r
+   N.B. The only way I can think to really sort scientific notation is to convert\r
+        it to a floating point number and then perform the sort on that. If you can think of\r
+        an easier/better way then please let me know.\r
+*/\r
+var sortScientificNotation = fdTableSort.sortNumeric;\r
+\r
+function sortScientificNotationPrepareData(tdNode, innerText) {\r
+        var aa = innerText;\r
+\r
+        var floatRegExp = /((\-|\+)?(\s+)?[0-9]+\.([0-9]+)?|(\-|\+)?(\s+)?(\.)?[0-9]+)/g;\r
+\r
+        aa = aa.match(floatRegExp);\r
+\r
+        if(!aa || aa.length != 2) return "";\r
+\r
+        var f1 = parseFloat(aa[0].replace(" ",""))*Math.pow(10,parseFloat(aa[1].replace(" ","")));\r
+        return isNaN(f1) ? "" : f1;\r
+}\r
+\r
+/*\r
+        sortImage\r
+        ---------\r
+\r
+        This is the function called in order to sort the data previously prepared by the function\r
+        "sortImagePrepareData". It does a basic case sensitive comparison on the data using the\r
+        tableSort's in-built sortText method.\r
+*/\r
+var sortImage = fdTableSort.sortText;\r
+\r
+/*\r
+        This is the function used to prepare i.e. parse data, to be used during the sort\r
+        of the images within the last table.\r
+\r
+        In this case, we are checking to see if the TD node has any child nodes that are\r
+        images and, if an image exists, return it's "src" attribute.\r
+        If no image exists, then we return an empty string.\r
+\r
+        The "prepareData" functions are passed the actual TD node and also the TD node inner text\r
+        which means you are free to check for child nodes etc and are not just limited to\r
+        sorting on the TD node's inner text.\r
+\r
+        The prepareData functions are not required (only your bespoke sort function is required)\r
+        and only called by the script should they exist.\r
+*/\r
+function sortImagePrepareData(td, innerText) {\r
+        var img = td.getElementsByTagName('img');\r
+        return img.length ? img[0].src: "";\r
+}\r
+\r
+/*\r
+        sortFileSize\r
+        ------------\r
+\r
+        1 Byte = 8 Bit\r
+        1 Kilobyte = 1024 Bytes\r
+        1 Megabyte = 1048576 Bytes\r
+        1 Gigabyte = 1073741824 Bytes\r
+*/\r
+var sortFileSize = fdTableSort.sortNumeric;\r
+\r
+function sortFileSizePrepareData(td, innerText) {\r
+        var regExp = /(kb|mb|gb)/i;\r
+\r
+        var type = innerText.search(regExp) != -1 ? innerText.match(regExp)[0] : "";\r
+\r
+        switch (type.toLowerCase()) {\r
+                case "kb" :\r
+                        mult = 1024;\r
+                        break;\r
+                case "mb" :\r
+                        mult = 1048576;\r
+                        break;\r
+                case "gb" :\r
+                        mult = 1073741824;\r
+                        break;\r
+                default :\r
+                        mult = 1;\r
+        };\r
+\r
+        innerText = parseFloat(innerText.replace(/[^0-9\.\-]/g,''));\r
+\r
+        return isNaN(innerText) ? "" : innerText * mult;\r
+};\r