moving the onelab www to a fresh location
[plewww.git] / planetlab / tablesort / customsort.js
1 /*\r
2     sortEnglishDateTime\r
3     -----------------------\r
4 \r
5     This function sorts English dateTime vaues such as:\r
6 \r
7     1st January 2003, 23:32:01\r
8     23/03/1972 à 10:22:22\r
9     1970/13/03 at 23:22:01\r
10     \r
11     The function is "safe" i.e. non-dateTime data (like the word "Unknown") can be passed in and is sorted properly.\r
12 */\r
13 var sortEnglishDateTime = fdTableSort.sortNumeric;\r
14 \r
15 function sortEnglishDateTimePrepareData(tdNode, innerText) {\r
16         // You can localise the function here\r
17         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
18 \r
19         // Lowercase the text\r
20         var aa = innerText.toLowerCase();\r
21 \r
22         // Replace the longhand months with an integer equivalent\r
23         for(var i = 0; i < months.length; i++) {\r
24                 aa = aa.replace(months[i], (i+13)%12);\r
25         };\r
26 \r
27         // Replace multiple spaces and anything that is not valid in the parsing of the date, then trim\r
28         aa = aa.replace(/\s+/g, " ").replace(/([^\d\s\/-:.])/g, "").replace(/^\s\s*/, '').replace(/\s\s*$/, '');\r
29 \r
30         // No timestamp at the end, then return -1\r
31         if(aa.search(/(\d){2}:(\d){2}(:(\d){2})?$/) == -1) { return -1; };\r
32 \r
33         // Grab the timestamp\r
34         var timestamp = aa.match(/(\d){2}:(\d){2}(:(\d){2})?$/)[0].replace(/:/g, "");\r
35 \r
36         // Make the timestamp 6 characters by default\r
37         if(timestamp.length == 4) { timestamp += "00"; };\r
38 \r
39         // Remove it from the string to assist the date parser, then trim\r
40         aa = aa.replace(/(\d){2}:(\d){2}(:(\d){2})?$/, "").replace(/\s\s*$/, '');\r
41 \r
42         // If you want the parser to favour the parsing of European dd/mm/yyyy dates then leave this set to "true"\r
43         // If you want the parser to favour the parsing of American mm/dd/yyyy dates then set to "false"\r
44         var favourDMY = true;\r
45 \r
46         // If you have a regular expression you wish to add, add the Object to the end of the array\r
47         var dateTest = [\r
48                        { 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
49                        { 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
50                        { 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
51                        ];\r
52 \r
53         var start,y,m,d;\r
54         var cnt = 0;\r
55         var numFormats = dateTest.length;\r
56         while(cnt < numFormats) {\r
57                start = (cnt + (favourDMY ? numFormats + 1 : numFormats)) % numFormats;\r
58                if(aa.match(dateTest[start].regExp)) {\r
59                        res = aa.match(dateTest[start].regExp);\r
60                        y = res[dateTest[start].y];\r
61                        m = res[dateTest[start].m];\r
62                        d = res[dateTest[start].d];\r
63                        if(m.length == 1) m = "0" + String(m);\r
64                        if(d.length == 1) d = "0" + String(d);\r
65                        if(y.length != 4) y = (parseInt(y) < 50) ? "20" + String(y) : "19" + String(y);\r
66 \r
67                        return y+String(m)+d+String(timestamp);\r
68                };\r
69                cnt++;\r
70         };\r
71         return -1;\r
72 };\r
73 \r
74 /*\r
75     sortAlphaNumeric\r
76     -----------------------\r
77 \r
78     This function sorts alphaNumeric values e.g. 1, e, 1a, -23c, 54z\r
79     \r
80     Notice how the prepareData function actually returns an Array i.e. you are not limited\r
81     in the type of data you return to the tableSort script.\r
82 */\r
83 function sortAlphaNumericPrepareData(tdNode, innerText){\r
84         var aa = innerText.toLowerCase().replace(" ", "");\r
85         var reg = /((\-|\+)?(\s+)?[0-9]+\.([0-9]+)?|(\-|\+)?(\s+)?(\.)?[0-9]+)([a-z]+)/;\r
86 \r
87         if(reg.test(aa)) {\r
88                 var aaP = aa.match(reg);\r
89                 return [aaP[1], aaP[8]];\r
90         };\r
91 \r
92         // Return an array\r
93         return isNaN(aa) ? ["",aa] : [aa,""];\r
94 }\r
95 \r
96 function sortAlphaNumeric(a, b){\r
97         // Get the previously prepared array\r
98         var aa = a[fdTableSort.pos];\r
99         var bb = b[fdTableSort.pos];\r
100 \r
101         // If they are equal then return 0\r
102         if(aa[0] == bb[0] && aa[1] == bb[1]) { return 0; };\r
103 \r
104         // Check numeric parts if not equal\r
105         if(aa[0] != bb[0]) {\r
106                 if(aa[0] != "" && bb[0] != "") { return aa[0] - bb[0]; };\r
107                 if(aa[0] == "" && bb[0] != "") { return -1; };\r
108                 return 1;\r
109         };\r
110         \r
111         // Check alpha parts if numeric parts equal\r
112         if(aa[1] == bb[1]) return 0;\r
113         if(aa[1] < bb[1])  return -1;\r
114         return 1;\r
115 }\r
116 \r
117 /*\r
118     sortDutchCurrencyValues\r
119     -----------------------\r
120 \r
121     This function sorts Dutch currency values (of the type 100.000,00)\r
122     The function is "safe" i.e. non-currency data (like the word "Unknown") can be passed in and is sorted properly.\r
123 */\r
124 var sortDutchCurrencyValues = fdTableSort.sortNumeric;\r
125 \r
126 function sortDutchCurrencyValuesPrepareData(tdNode, innerText) {\r
127         innerText = parseInt(innerText.replace(/[^0-9\.,]+/g, "").replace(/\./g,"").replace(",","."));\r
128         return isNaN(innerText) ? "" : innerText;\r
129 }\r
130 \r
131 /*\r
132    sortByTwelveHourTimestamp\r
133    -------------------------\r
134 \r
135    This custom sort function sorts 12 hour timestamps of an hour/minute nature.\r
136    The hour/minute dividor can be a full-stop or a colon and it correctly calculates that 12.30am is before 1am etc\r
137    The am/pm part can be written in lower or uppercase and can optionally contain full-stops e.g.\r
138 \r
139    am, a.m, a.m., AM, A.M etc\r
140 \r
141    Additionally, the values "12 midnight" and "12 noon" are also handled correctly.\r
142 \r
143    The question remains... does "12p.m." mean "midnight" or "12 noon"? I've decided here that it's 12 noon.\r
144 \r
145    The function is "safe" i.e. non-timestamp data (like the word "Unknown") can be passed in and is sorted properly.\r
146 */\r
147 var sortByTwelveHourTimestamp = fdTableSort.sortNumeric;\r
148 \r
149 function sortByTwelveHourTimestampPrepareData(tdNode, innerText) {\r
150         tmp = innerText\r
151         innerText = innerText.replace(":",".");\r
152 \r
153         // Check for the special cases of "12 noon" or "12 midnight"\r
154         if(innerText.search(/12([\s]*)?noon/i) != -1) return "12.00";\r
155         if(innerText.search(/12([\s]*)?midnight/i) != -1) return "24.00";\r
156 \r
157         var regExpPM = /^([0-9]{1,2}).([0-9]{2})([\s]*)?(p[\.]?m)/i;\r
158         var regExpAM = /^([0-9]{1,2}).([0-9]{2})([\s]*)?(a[\.]?m)/i;\r
159 \r
160         if(innerText.search(regExpPM) != -1) {\r
161                 var bits = innerText.match(regExpPM);\r
162                 if(parseInt(bits[1]) < 12) { bits[1] = parseInt(bits[1]) + 12; }\r
163         } else if(innerText.search(regExpAM) != -1) {\r
164                 var bits = innerText.match(regExpAM);\r
165                 if(bits[1] == "12") { bits[1] = "00"; }\r
166         } else return "";\r
167 \r
168         if(bits[2].length < 2) { bits[2] = "0" + String(bits[2]); }\r
169 \r
170         innerText = bits[1] + "." + String(bits[2]);\r
171 \r
172         return isNaN(innerText) ? "" : innerText;\r
173 }\r
174 /*\r
175    sortEnglishLonghandDateFormat\r
176    -----------------------------\r
177 \r
178    This custom sort function sorts dates of the format:\r
179 \r
180    "12th April, 2006" or "12 April 2006" or "12-4-2006" or "12 April" or "12 4" or "12 Apr 2006" etc\r
181 \r
182    The function expects dates to be in the format day/month/year. Should no year be stipulated,\r
183    the function treats the year as being the current year.\r
184 \r
185    The function is "safe" i.e. non-date data (like the word "Unknown") can be passed in and is sorted properly.\r
186 */\r
187 var sortEnglishLonghandDateFormat = fdTableSort.sortNumeric;\r
188 \r
189 function sortEnglishLonghandDateFormatPrepareData(tdNode, innerText) {\r
190         var months = ['january','february','march','april','may','june','july','august','september','october','november','december'];\r
191 \r
192         var aa = innerText.toLowerCase();\r
193 \r
194         // Replace the longhand months with an integer equivalent\r
195         for(var i = 0; i < 12; i++) {\r
196                 aa = aa.replace(months[i], i+1).replace(months[i].substring(0,3), i+1);\r
197         }\r
198 \r
199         // If there are still alpha characters then return -1\r
200         if(aa.search(/a-z/) != -1) return -1;\r
201 \r
202         // Replace multiple spaces and anything that is not numeric\r
203         aa = aa.replace(/\s+/g, " ").replace(/[^\d\s]/g, "");\r
204 \r
205         // If were left with nothing then return -1\r
206         if(aa.replace(" ", "") == "") return -1;\r
207 \r
208         // Split on the (now) single spaces\r
209         aa = aa.split(" ");\r
210 \r
211         // If something has gone terribly wrong then return -1\r
212         if(aa.length < 2) return -1;\r
213 \r
214         // If no year stipulated, then add this year as default\r
215         if(aa.length == 2) {\r
216                 aa[2] = String(new Date().getFullYear());\r
217         }\r
218 \r
219         // Equalise the day and month\r
220         if(aa[0].length < 2) aa[0] = "0" + String(aa[0]);\r
221         if(aa[1].length < 2) aa[1] = "0" + String(aa[1]);\r
222 \r
223         // Deal with Y2K issues\r
224         if(aa[2].length != 4) {\r
225                 aa[2] = (parseInt(aa[2]) < 50) ? '20' + aa[2] : '19' + aa[2];\r
226         }\r
227 \r
228         // YMD (can be used as integer during comparison)\r
229         return aa[2] + String(aa[1]) + aa[0];\r
230 }\r
231 /*\r
232    sortIPAddress\r
233    -------------\r
234 \r
235    This custom sort function correctly sorts IP addresses i.e. it checks all of the address parts and not just the first.\r
236 \r
237    The function is "safe" i.e. non-IP address data (like the word "Unknown") can be passed in and is sorted properly.\r
238 */\r
239 var sortIPAddress = fdTableSort.sortNumeric;\r
240 \r
241 function sortIPAddressPrepareData(tdNode, innerText) {\r
242         // Get the innerText of the TR nodes\r
243         var aa = innerText;\r
244 \r
245         // Remove spaces\r
246         aa = aa.replace(" ","");\r
247 \r
248         // If not an IP address then return -1\r
249         if(aa.search(/^([0-9]{1,3}).([0-9]{1,3}).([0-9]{1,3}).([0-9]{1,3})$/) == -1) return -1;\r
250 \r
251         // Split on the "."\r
252         aa = aa.split(".");\r
253 \r
254         // If we don't have 4 parts then return -1\r
255         if(aa.length != 4) return -1;\r
256 \r
257         var retVal = "";\r
258 \r
259         // Make all the parts an equal length and create a master integer\r
260         for(var i = 0; i < 4; i++) {\r
261                 retVal += (String(aa[i]).length < 3) ? "0000".substr(0, 3 - String(aa[i]).length) + String(aa[i]) : aa[i];\r
262         }\r
263 \r
264         return retVal;\r
265 }\r
266 /*\r
267    sortScientificNotation\r
268    ----------------------\r
269 \r
270    This custom sort function sorts numbers stipulated in scientific notation\r
271 \r
272    The function is "safe" i.e. data like the word "Unknown" can be passed in and is sorted properly.\r
273 \r
274    N.B. The only way I can think to really sort scientific notation is to convert\r
275         it to a floating point number and then perform the sort on that. If you can think of\r
276         an easier/better way then please let me know.\r
277 */\r
278 var sortScientificNotation = fdTableSort.sortNumeric;\r
279 \r
280 function sortScientificNotationPrepareData(tdNode, innerText) {\r
281         var aa = innerText;\r
282 \r
283         var floatRegExp = /((\-|\+)?(\s+)?[0-9]+\.([0-9]+)?|(\-|\+)?(\s+)?(\.)?[0-9]+)/g;\r
284 \r
285         aa = aa.match(floatRegExp);\r
286 \r
287         if(!aa || aa.length != 2) return "";\r
288 \r
289         var f1 = parseFloat(aa[0].replace(" ",""))*Math.pow(10,parseFloat(aa[1].replace(" ","")));\r
290         return isNaN(f1) ? "" : f1;\r
291 }\r
292 \r
293 /*\r
294         sortImage\r
295         ---------\r
296 \r
297         This is the function called in order to sort the data previously prepared by the function\r
298         "sortImagePrepareData". It does a basic case sensitive comparison on the data using the\r
299         tableSort's in-built sortText method.\r
300 */\r
301 var sortImage = fdTableSort.sortText;\r
302 \r
303 /*\r
304         This is the function used to prepare i.e. parse data, to be used during the sort\r
305         of the images within the last table.\r
306 \r
307         In this case, we are checking to see if the TD node has any child nodes that are\r
308         images and, if an image exists, return it's "src" attribute.\r
309         If no image exists, then we return an empty string.\r
310 \r
311         The "prepareData" functions are passed the actual TD node and also the TD node inner text\r
312         which means you are free to check for child nodes etc and are not just limited to\r
313         sorting on the TD node's inner text.\r
314 \r
315         The prepareData functions are not required (only your bespoke sort function is required)\r
316         and only called by the script should they exist.\r
317 */\r
318 function sortImagePrepareData(td, innerText) {\r
319         var img = td.getElementsByTagName('img');\r
320         return img.length ? img[0].src: "";\r
321 }\r
322 \r
323 /*\r
324         sortFileSize\r
325         ------------\r
326 \r
327         1 Byte = 8 Bit\r
328         1 Kilobyte = 1024 Bytes\r
329         1 Megabyte = 1048576 Bytes\r
330         1 Gigabyte = 1073741824 Bytes\r
331 */\r
332 var sortFileSize = fdTableSort.sortNumeric;\r
333 \r
334 function sortFileSizePrepareData(td, innerText) {\r
335         var regExp = /(kb|mb|gb)/i;\r
336 \r
337         var type = innerText.search(regExp) != -1 ? innerText.match(regExp)[0] : "";\r
338 \r
339         switch (type.toLowerCase()) {\r
340                 case "kb" :\r
341                         mult = 1024;\r
342                         break;\r
343                 case "mb" :\r
344                         mult = 1048576;\r
345                         break;\r
346                 case "gb" :\r
347                         mult = 1073741824;\r
348                         break;\r
349                 default :\r
350                         mult = 1;\r
351         };\r
352 \r
353         innerText = parseFloat(innerText.replace(/[^0-9\.\-]/g,''));\r
354 \r
355         return isNaN(innerText) ? "" : innerText * mult;\r
356 };\r