1282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  SortTable
3282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  version 2
4282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  7th April 2007
5282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/
6282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
7282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  Instructions:
8282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  Download this file
9282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  Add <script src="sorttable.js"></script> to your HTML
10282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  Add class="sortable" to any table you'd like to make sortable
11282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  Click on the headers to sort
12282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
13282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  Thanks to many, many people for contributions and suggestions.
14282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  Licenced as X11: http://www.kryogenix.org/code/browser/licence.html
15282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  This basically means: do what you want with it.
16282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski*/
17282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
18282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
19282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskivar stIsIE = /*@cc_on!@*/false;
20282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
21282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskisorttable = {
22282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  init: function() {
23282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // quit if this function has already been called
24282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (arguments.callee.done) return;
25282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // flag this function so we don't do the same thing twice
26282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    arguments.callee.done = true;
27282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // kill the timer
28282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (_timer) clearInterval(_timer);
29282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
30282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!document.createElement || !document.getElementsByTagName) return;
31282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
32282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/;
33282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
34282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    forEach(document.getElementsByTagName('table'), function(table) {
35282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      if (table.className.search(/\bsortable\b/) != -1) {
36282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sorttable.makeSortable(table);
37282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      }
38282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    });
39282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
40282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  },
41282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
42282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  makeSortable: function(table) {
43282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (table.getElementsByTagName('thead').length == 0) {
44282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      // table doesn't have a tHead. Since it should have, create one and
45282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      // put the first table row in it.
46282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      the = document.createElement('thead');
47282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      the.appendChild(table.rows[0]);
48282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      table.insertBefore(the,table.firstChild);
49282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
50282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Safari doesn't support table.tHead, sigh
51282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0];
52282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
53282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (table.tHead.rows.length != 1) return; // can't cope with two header rows
54282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
55282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as
56282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // "total" rows, for example). This is B&R, since what you're supposed
57282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // to do is put them in a tfoot. So, if there are sortbottom rows,
58282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // for backwards compatibility, move them to tfoot (creating it if needed).
59282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sortbottomrows = [];
60282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (var i=0; i<table.rows.length; i++) {
61282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      if (table.rows[i].className.search(/\bsortbottom\b/) != -1) {
62282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sortbottomrows[sortbottomrows.length] = table.rows[i];
63282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      }
64282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
65282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (sortbottomrows) {
66282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      if (table.tFoot == null) {
67282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // table doesn't have a tfoot. Create one.
68282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        tfo = document.createElement('tfoot');
69282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        table.appendChild(tfo);
70282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      }
71282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      for (var i=0; i<sortbottomrows.length; i++) {
72282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        tfo.appendChild(sortbottomrows[i]);
73282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      }
74282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      delete sortbottomrows;
75282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
76282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
77282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // work through each column and calculate its type
78282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    headrow = table.tHead.rows[0].cells;
79282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (var i=0; i<headrow.length; i++) {
80282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      // manually override the type with a sorttable_type attribute
81282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      if (!headrow[i].className.match(/\bsorttable_nosort\b/)) { // skip this col
82282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mtch = headrow[i].className.match(/\bsorttable_([a-z0-9]+)\b/);
83282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (mtch) { override = mtch[1]; }
84282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	      if (mtch && typeof sorttable["sort_"+override] == 'function') {
85282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	        headrow[i].sorttable_sortfunction = sorttable["sort_"+override];
86282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	      } else {
87282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	        headrow[i].sorttable_sortfunction = sorttable.guessType(table,i);
88282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	      }
89282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	      // make it clickable to sort
90282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	      headrow[i].sorttable_columnindex = i;
91282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	      headrow[i].sorttable_tbody = table.tBodies[0];
92282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	      dean_addEvent(headrow[i],"click", function(e) {
93282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
94282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          if (this.className.search(/\bsorttable_sorted\b/) != -1) {
95282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // if we're already sorted by this column, just
96282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // reverse the table, which is quicker
97282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sorttable.reverse(this.sorttable_tbody);
98282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            this.className = this.className.replace('sorttable_sorted',
99282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                    'sorttable_sorted_reverse');
100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            this.removeChild(document.getElementById('sorttable_sortfwdind'));
101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sortrevind = document.createElement('span');
102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sortrevind.id = "sorttable_sortrevind";
103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sortrevind.innerHTML = stIsIE ? '&nbsp<font face="webdings">5</font>' : '&nbsp;&#x25B4;';
104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            this.appendChild(sortrevind);
105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return;
106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          }
107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) {
108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // if we're already sorted by this column in reverse, just
109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // re-reverse the table, which is quicker
110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sorttable.reverse(this.sorttable_tbody);
111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            this.className = this.className.replace('sorttable_sorted_reverse',
112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                    'sorttable_sorted');
113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            this.removeChild(document.getElementById('sorttable_sortrevind'));
114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sortfwdind = document.createElement('span');
115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sortfwdind.id = "sorttable_sortfwdind";
116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sortfwdind.innerHTML = stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25BE;';
117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            this.appendChild(sortfwdind);
118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return;
119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          }
120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          // remove sorttable_sorted classes
122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          theadrow = this.parentNode;
123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          forEach(theadrow.childNodes, function(cell) {
124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (cell.nodeType == 1) { // an element
125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski              cell.className = cell.className.replace('sorttable_sorted_reverse','');
126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski              cell.className = cell.className.replace('sorttable_sorted','');
127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          });
129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          sortfwdind = document.getElementById('sorttable_sortfwdind');
130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); }
131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          sortrevind = document.getElementById('sorttable_sortrevind');
132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); }
133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          this.className += ' sorttable_sorted';
135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          sortfwdind = document.createElement('span');
136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          sortfwdind.id = "sorttable_sortfwdind";
137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          sortfwdind.innerHTML = stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25BE;';
138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          this.appendChild(sortfwdind);
139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	        // build an array to sort. This is a Schwartzian transform thing,
141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	        // i.e., we "decorate" each row with the actual sort key,
142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	        // sort based on the sort keys, and then put the rows back in order
143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	        // which is a lot faster because you only do getInnerText once per row
144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	        row_array = [];
145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	        col = this.sorttable_columnindex;
146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	        rows = this.sorttable_tbody.rows;
147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	        for (var j=0; j<rows.length; j++) {
148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	          row_array[row_array.length] = [sorttable.getInnerText(rows[j].cells[col]), rows[j]];
149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	        }
150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	        /* If you want a stable sort, uncomment the following line */
151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	        //sorttable.shaker_sort(row_array, this.sorttable_sortfunction);
152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	        /* and comment out this one */
153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	        row_array.sort(this.sorttable_sortfunction);
154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	        tb = this.sorttable_tbody;
156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	        for (var j=0; j<row_array.length; j++) {
157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	          tb.appendChild(row_array[j][1]);
158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	        }
159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	        delete row_array;
161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	      });
162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	    }
163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  },
165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  guessType: function(table, column) {
167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // guess the type of a column based on its first non-blank row
168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sortfn = sorttable.sort_alpha;
169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (var i=0; i<table.tBodies[0].rows.length; i++) {
170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      text = sorttable.getInnerText(table.tBodies[0].rows[i].cells[column]);
171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      if (text != '') {
172282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (text.match(/^-?[�$�]?[\d,.]+%?$/)) {
173282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          return sorttable.sort_numeric;
174282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
175282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // check for a date: dd/mm/yyyy or dd/mm/yy
176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // can have / or . or - as separator
177282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // can be mm/dd as well
178282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        possdate = text.match(sorttable.DATE_RE)
179282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (possdate) {
180282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          // looks like a date
181282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          first = parseInt(possdate[1]);
182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          second = parseInt(possdate[2]);
183282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          if (first > 12) {
184282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // definitely dd/mm
185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return sorttable.sort_ddmm;
186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          } else if (second > 12) {
187282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return sorttable.sort_mmdd;
188282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          } else {
189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // looks like a date, but we can't tell which, so assume
190282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // that it's dd/mm (English imperialism!) and keep looking
191282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sortfn = sorttable.sort_ddmm;
192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          }
193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      }
195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return sortfn;
197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  },
198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  getInnerText: function(node) {
200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // gets the text we want to use for sorting for a cell.
201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // strips leading and trailing whitespace.
202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // this is *not* a generic getInnerText function; it's special to sorttable.
203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // for example, you can override the cell text with a customkey attribute.
204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // it also gets .value for <input> fields.
205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    hasInputs = (typeof node.getElementsByTagName == 'function') &&
207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                 node.getElementsByTagName('input').length;
208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (node.getAttribute("sorttable_customkey") != null) {
210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      return node.getAttribute("sorttable_customkey");
211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    else if (typeof node.textContent != 'undefined' && !hasInputs) {
213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      return node.textContent.replace(/^\s+|\s+$/g, '');
214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    else if (typeof node.innerText != 'undefined' && !hasInputs) {
216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      return node.innerText.replace(/^\s+|\s+$/g, '');
217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    else if (typeof node.text != 'undefined' && !hasInputs) {
219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      return node.text.replace(/^\s+|\s+$/g, '');
220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    else {
222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      switch (node.nodeType) {
223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        case 3:
224282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          if (node.nodeName.toLowerCase() == 'input') {
225282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return node.value.replace(/^\s+|\s+$/g, '');
226282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          }
227282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        case 4:
228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          return node.nodeValue.replace(/^\s+|\s+$/g, '');
229282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          break;
230282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        case 1:
231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        case 11:
232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          var innerText = '';
233282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          for (var i = 0; i < node.childNodes.length; i++) {
234282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            innerText += sorttable.getInnerText(node.childNodes[i]);
235282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          }
236282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          return innerText.replace(/^\s+|\s+$/g, '');
237282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          break;
238282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        default:
239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski          return '';
240282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      }
241282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
242282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  },
243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
244282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  reverse: function(tbody) {
245282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // reverse the rows in a tbody
246282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    newrows = [];
247282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (var i=0; i<tbody.rows.length; i++) {
248282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      newrows[newrows.length] = tbody.rows[i];
249282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
250282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (var i=newrows.length-1; i>=0; i--) {
251282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski       tbody.appendChild(newrows[i]);
252282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
253282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    delete newrows;
254282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  },
255282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
256282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  /* sort functions
257282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     each sort function takes two parameters, a and b
258282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     you are comparing a[0] and b[0] */
259282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  sort_numeric: function(a,b) {
260282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    aa = parseFloat(a[0].replace(/[^0-9.-]/g,''));
261282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (isNaN(aa)) aa = 0;
262282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    bb = parseFloat(b[0].replace(/[^0-9.-]/g,''));
263282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (isNaN(bb)) bb = 0;
264282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return aa-bb;
265282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  },
266282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  sort_alpha: function(a,b) {
267282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (a[0]==b[0]) return 0;
268282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (a[0]<b[0]) return -1;
269282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return 1;
270282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  },
271282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  sort_ddmm: function(a,b) {
272282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mtch = a[0].match(sorttable.DATE_RE);
273282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    y = mtch[3]; m = mtch[2]; d = mtch[1];
274282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (m.length == 1) m = '0'+m;
275282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (d.length == 1) d = '0'+d;
276282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    dt1 = y+m+d;
277282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mtch = b[0].match(sorttable.DATE_RE);
278282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    y = mtch[3]; m = mtch[2]; d = mtch[1];
279282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (m.length == 1) m = '0'+m;
280282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (d.length == 1) d = '0'+d;
281282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    dt2 = y+m+d;
282282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (dt1==dt2) return 0;
283282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (dt1<dt2) return -1;
284282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return 1;
285282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  },
286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  sort_mmdd: function(a,b) {
287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mtch = a[0].match(sorttable.DATE_RE);
288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    y = mtch[3]; d = mtch[2]; m = mtch[1];
289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (m.length == 1) m = '0'+m;
290282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (d.length == 1) d = '0'+d;
291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    dt1 = y+m+d;
292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mtch = b[0].match(sorttable.DATE_RE);
293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    y = mtch[3]; d = mtch[2]; m = mtch[1];
294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (m.length == 1) m = '0'+m;
295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (d.length == 1) d = '0'+d;
296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    dt2 = y+m+d;
297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (dt1==dt2) return 0;
298282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (dt1<dt2) return -1;
299282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return 1;
300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  },
301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
302282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  shaker_sort: function(list, comp_func) {
303282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // A stable sort function to allow multi-level sorting of data
304282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // see: http://en.wikipedia.org/wiki/Cocktail_sort
305282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // thanks to Joseph Nahmias
306282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    var b = 0;
307282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    var t = list.length - 1;
308282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    var swap = true;
309282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
310282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    while(swap) {
311282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        swap = false;
312282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for(var i = b; i < t; ++i) {
313282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if ( comp_func(list[i], list[i+1]) > 0 ) {
314282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                var q = list[i]; list[i] = list[i+1]; list[i+1] = q;
315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                swap = true;
316282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
317282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } // for
318282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        t--;
319282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
320282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (!swap) break;
321282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
322282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for(var i = t; i > b; --i) {
323282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if ( comp_func(list[i], list[i-1]) < 0 ) {
324282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                var q = list[i]; list[i] = list[i-1]; list[i-1] = q;
325282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                swap = true;
326282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
327282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } // for
328282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        b++;
329282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
330282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } // while(swap)
331282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  }
332282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
333282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/* ******************************************************************
335282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski   Supporting functions: bundled here to avoid depending on a library
336282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski   ****************************************************************** */
337282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
338282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// Dean Edwards/Matthias Miller/John Resig
339282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
340282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/* for Mozilla/Opera9 */
341282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiif (document.addEventListener) {
342282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    document.addEventListener("DOMContentLoaded", sorttable.init, false);
343282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
344282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
345282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/* for Internet Explorer */
346282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*@cc_on @*/
347282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*@if (@_win32)
348282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
349282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    var script = document.getElementById("__ie_onload");
350282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    script.onreadystatechange = function() {
351282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (this.readyState == "complete") {
352282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sorttable.init(); // call the onload handler
353282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
354282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    };
355282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*@end @*/
356282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
357282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/* for Safari */
358282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiif (/WebKit/i.test(navigator.userAgent)) { // sniff
359282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    var _timer = setInterval(function() {
360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (/loaded|complete/.test(document.readyState)) {
361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sorttable.init(); // call the onload handler
362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }, 10);
364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
366282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/* for other browsers */
367282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiwindow.onload = sorttable.init;
368282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
369282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// written by Dean Edwards, 2005
370282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// with input from Tino Zijdel, Matthias Miller, Diego Perini
371282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
372282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// http://dean.edwards.name/weblog/2005/10/add-event/
373282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
374282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskifunction dean_addEvent(element, type, handler) {
375282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	if (element.addEventListener) {
376282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		element.addEventListener(type, handler, false);
377282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	} else {
378282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		// assign each event handler a unique ID
379282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		if (!handler.$$guid) handler.$$guid = dean_addEvent.guid++;
380282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		// create a hash table of event types for the element
381282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		if (!element.events) element.events = {};
382282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		// create a hash table of event handlers for each element/event pair
383282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		var handlers = element.events[type];
384282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		if (!handlers) {
385282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski			handlers = element.events[type] = {};
386282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski			// store the existing event handler (if there is one)
387282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski			if (element["on" + type]) {
388282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski				handlers[0] = element["on" + type];
389282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski			}
390282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		}
391282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		// store the event handler in the hash table
392282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		handlers[handler.$$guid] = handler;
393282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		// assign a global event handler to do all the work
394282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		element["on" + type] = handleEvent;
395282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	}
396282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski};
397282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// a counter used to create unique IDs
398282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskidean_addEvent.guid = 1;
399282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
400282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskifunction removeEvent(element, type, handler) {
401282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	if (element.removeEventListener) {
402282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		element.removeEventListener(type, handler, false);
403282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	} else {
404282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		// delete the event handler from the hash table
405282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		if (element.events && element.events[type]) {
406282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski			delete element.events[type][handler.$$guid];
407282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		}
408282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	}
409282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski};
410282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
411282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskifunction handleEvent(event) {
412282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	var returnValue = true;
413282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	// grab the event object (IE uses a global event object)
414282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event);
415282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	// get a reference to the hash table of event handlers
416282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	var handlers = this.events[event.type];
417282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	// execute each event handler
418282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	for (var i in handlers) {
419282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		this.$$handleEvent = handlers[i];
420282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		if (this.$$handleEvent(event) === false) {
421282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski			returnValue = false;
422282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		}
423282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	}
424282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	return returnValue;
425282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski};
426282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
427282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskifunction fixEvent(event) {
428282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	// add W3C standard event methods
429282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	event.preventDefault = fixEvent.preventDefault;
430282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	event.stopPropagation = fixEvent.stopPropagation;
431282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	return event;
432282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski};
433282e181b58cf72b6ca770dc7ca5f91f135444502Adam LesinskifixEvent.preventDefault = function() {
434282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	this.returnValue = false;
435282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski};
436282e181b58cf72b6ca770dc7ca5f91f135444502Adam LesinskifixEvent.stopPropagation = function() {
437282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  this.cancelBubble = true;
438282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
439282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
440282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// Dean's forEach: http://dean.edwards.name/base/forEach.js
441282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
442282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	forEach, version 1.0
443282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	Copyright 2006, Dean Edwards
444282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	License: http://www.opensource.org/licenses/mit-license.php
445282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski*/
446282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
447282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// array-like enumeration
448282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiif (!Array.forEach) { // mozilla already supports this
449282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	Array.forEach = function(array, block, context) {
450282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		for (var i = 0; i < array.length; i++) {
451282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski			block.call(context, array[i], i, array);
452282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		}
453282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	};
454282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
455282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
456282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// generic enumeration
457282e181b58cf72b6ca770dc7ca5f91f135444502Adam LesinskiFunction.prototype.forEach = function(object, block, context) {
458282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	for (var key in object) {
459282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		if (typeof this.prototype[key] == "undefined") {
460282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski			block.call(context, object[key], key, object);
461282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		}
462282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	}
463282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski};
464282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
465282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// character enumeration
466282e181b58cf72b6ca770dc7ca5f91f135444502Adam LesinskiString.forEach = function(string, block, context) {
467282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	Array.forEach(string.split(""), function(chr, index) {
468282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		block.call(context, chr, index, string);
469282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	});
470282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski};
471282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
472282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// globally resolve forEach enumeration
473282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskivar forEach = function(object, block, context) {
474282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	if (object) {
475282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		var resolve = Object; // default
476282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		if (object instanceof Function) {
477282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski			// functions have a "length" property
478282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski			resolve = Function;
479282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		} else if (object.forEach instanceof Function) {
480282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski			// the object implements a custom forEach method so use that
481282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski			object.forEach(block, context);
482282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski			return;
483282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		} else if (typeof object == "string") {
484282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski			// the object is a string
485282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski			resolve = String;
486282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		} else if (typeof object.length == "number") {
487282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski			// the object is array-like
488282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski			resolve = Array;
489282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		}
490282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski		resolve.forEach(object, block, context);
491282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski	}
492282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski};
493282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
494