3 On page load, the SortableManager:
5 - Finds the table by its id (sortable_table).
6 - Parses its thead for columns with a "mochi:format" attribute.
7 - Parses the data out of the tbody based upon information given in the
8 "mochi:format" attribute, and clones the tr elements for later re-use.
9 - Clones the column header th elements for use as a template when drawing
11 - Stores away a reference to the tbody, as it will be replaced on each sort.
12 - Performs the first sort.
17 - Sorts the data based on the given key and direction
18 - Creates a new tbody from the rows in the new ordering
19 - Replaces the column header th elements with clickable versions, adding an
20 indicator (↑ or ↓) to the most recently sorted column.
24 SortableManager = function () {
33 mouseOverFunc = function () {
34 addElementClass(this, "over");
37 mouseOutFunc = function () {
38 removeElementClass(this, "over");
41 ignoreEvent = function (ev) {
42 if (ev && ev.preventDefault) {
45 } else if (typeof(event) != 'undefined') {
46 event.cancelBubble = false;
47 event.returnValue = false;
52 update(SortableManager.prototype, {
54 "initWithTable": function (table) {
57 Initialize the SortableManager with a table object
60 // Ensure that it's a DOM element
61 table = getElement(table);
63 this.thead = table.getElementsByTagName('thead')[0];
64 // get the mochi:format key and contents for each column header
65 var cols = this.thead.getElementsByTagName('th');
66 for (var i = 0; i < cols.length; i++) {
70 attr = node.getAttribute("mochi:format");
74 var o = node.childNodes;
78 "proto": node.cloneNode(true)
81 // scrape the tbody for data
82 this.tbody = table.getElementsByTagName('tbody')[0];
84 var rows = this.tbody.getElementsByTagName('tr');
85 for (var i = 0; i < rows.length; i++) {
88 var cols = row.getElementsByTagName('td');
90 for (var j = 0; j < cols.length; j++) {
91 // scrape the text and build the appropriate object out of it
93 var obj = scrapeText(cell);
94 switch (this.columns[j].format) {
104 obj = obj.toLowerCase();
106 // cases for numbers, etc. could be here
112 // stow away a reference to the TR and save it
113 rowData.row = row.cloneNode(true);
114 this.rows.push(rowData);
118 // do initial sort on first column
119 this.drawSortedRows(this.sortkey, true, false);
123 "onSortClick": function (name) {
126 Return a sort function for click events
129 return method(this, function () {
130 log('onSortClick', name);
131 var order = this.sortState[name];
134 } else if (name == this.sortkey) {
137 this.drawSortedRows(name, order, true);
141 "drawSortedRows": function (key, forward, clicked) {
144 Draw the new sorted table body, and modify the column headers
148 log('drawSortedRows', key, forward);
150 // sort based on the state given (forward or reverse)
151 var cmp = (forward ? keyComparator : reverseKeyComparator);
152 this.rows.sort(cmp(key));
153 // save it so we can flip next time
154 this.sortState[key] = forward;
155 // get every "row" element from this.rows and make a new tbody
156 var newBody = TBODY(null, map(itemgetter("row"), this.rows));
157 // swap in the new tbody
158 this.tbody = swapDOM(this.tbody, newBody);
159 // replace first column with row count.
160 var rows = this.tbody.getElementsByTagName('tr');
161 for (var i=0; i < rows.length; i++) {
163 var cols = row.getElementsByTagName('td');
164 // var cell = cols[0];
165 cols[0].innerHTML = String(i);
167 for (var i = 0; i < this.columns.length; i++) {
168 var col = this.columns[i];
169 var node = col.proto.cloneNode(true);
170 // remove the existing events to minimize IE leaks
171 col.element.onclick = null;
172 col.element.onmousedown = null;
173 col.element.onmouseover = null;
174 col.element.onmouseout = null;
175 // set new events for the new node
176 node.onclick = this.onSortClick(i);
177 node.onmousedown = ignoreEvent;
178 node.onmouseover = mouseOverFunc;
179 node.onmouseout = mouseOutFunc;
180 // if this is the sorted column
182 // \u2193 is down arrow, \u2191 is up arrow
183 // forward sorts mean the rows get bigger going down
184 var arrow = (forward ? "\u2193" : "\u2191");
185 // add the character to the column header
186 node.appendChild(SPAN(null, arrow));
192 // swap in the new th
193 col.element = swapDOM(col.element, node);
198 sortableManager = new SortableManager();
200 addLoadEvent(function () {
201 sortableManager.initWithTable('sortable_table');
204 // rewrite the view-source links
205 addLoadEvent(function () {
206 var elems = getElementsByTagAndClassName("A", "view-source");
207 var page = "sortable_tables/";
208 for (var i = 0; i < elems.length; i++) {
210 var href = elem.href.split(/\//).pop();
211 elem.target = "_blank";
212 elem.href = "../view-source/view-source.html#" + page + href;