1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 | function SortableTable(oTable, oSortTypes) {
|
45 |
|
46 | this.sortTypes = oSortTypes || [];
|
47 |
|
48 | this.sortColumn = null;
|
49 | this.descending = null;
|
50 |
|
51 | var oThis = this;
|
52 | this._headerOnclick = function (e) {
|
53 | oThis.headerOnclick(e);
|
54 | };
|
55 |
|
56 | if (oTable) {
|
57 | this.setTable( oTable );
|
58 | this.document = oTable.ownerDocument || oTable.document;
|
59 | }
|
60 | else {
|
61 | this.document = document;
|
62 | }
|
63 |
|
64 |
|
65 |
|
66 | var win = this.document.defaultView || this.document.parentWindow;
|
67 | this._onunload = function () {
|
68 | oThis.destroy();
|
69 | };
|
70 | if (win && typeof win.attachEvent != "undefined") {
|
71 | win.attachEvent("onunload", this._onunload);
|
72 | }
|
73 | }
|
74 |
|
75 | SortableTable.gecko = navigator.product == "Gecko";
|
76 | SortableTable.msie = /msie/i.test(navigator.userAgent);
|
77 |
|
78 |
|
79 | SortableTable.removeBeforeSort = SortableTable.gecko;
|
80 |
|
81 | SortableTable.prototype.onsort = function () {};
|
82 |
|
83 |
|
84 | SortableTable.prototype.defaultDescending = false;
|
85 |
|
86 |
|
87 |
|
88 | SortableTable.prototype._sortTypeInfo = {};
|
89 |
|
90 | SortableTable.prototype.setTable = function (oTable) {
|
91 | if ( this.tHead )
|
92 | this.uninitHeader();
|
93 | this.element = oTable;
|
94 | this.setTHead( oTable.tHead );
|
95 | this.setTBody( oTable.tBodies[0] );
|
96 | };
|
97 |
|
98 | SortableTable.prototype.setTHead = function (oTHead) {
|
99 | if (this.tHead && this.tHead != oTHead )
|
100 | this.uninitHeader();
|
101 | this.tHead = oTHead;
|
102 | this.initHeader( this.sortTypes );
|
103 | };
|
104 |
|
105 | SortableTable.prototype.setTBody = function (oTBody) {
|
106 | this.tBody = oTBody;
|
107 | };
|
108 |
|
109 | SortableTable.prototype.setSortTypes = function ( oSortTypes ) {
|
110 | if ( this.tHead )
|
111 | this.uninitHeader();
|
112 | this.sortTypes = oSortTypes || [];
|
113 | if ( this.tHead )
|
114 | this.initHeader( this.sortTypes );
|
115 | };
|
116 |
|
117 |
|
118 |
|
119 |
|
120 | SortableTable.prototype.initHeader = function (oSortTypes) {
|
121 | if (!this.tHead) return;
|
122 | var cells = this.tHead.rows[0].cells;
|
123 | var doc = this.tHead.ownerDocument || this.tHead.document;
|
124 | this.sortTypes = oSortTypes || [];
|
125 | var l = cells.length;
|
126 | var img, c;
|
127 | for (var i = 0; i < l; i++) {
|
128 | c = cells[i];
|
129 | if (this.sortTypes[i] != null && this.sortTypes[i] != "None") {
|
130 | img = doc.createElement("IMG");
|
131 | img.src = "images/blank.png";
|
132 | c.appendChild(img);
|
133 | if (this.sortTypes[i] != null)
|
134 | c._sortType = this.sortTypes[i];
|
135 | if (typeof c.addEventListener != "undefined")
|
136 | c.addEventListener("click", this._headerOnclick, false);
|
137 | else if (typeof c.attachEvent != "undefined")
|
138 | c.attachEvent("onclick", this._headerOnclick);
|
139 | else
|
140 | c.onclick = this._headerOnclick;
|
141 | }
|
142 | else
|
143 | {
|
144 | c.setAttribute( "_sortType", oSortTypes[i] );
|
145 | c._sortType = "None";
|
146 | }
|
147 | }
|
148 | this.updateHeaderArrows();
|
149 | };
|
150 |
|
151 |
|
152 | SortableTable.prototype.uninitHeader = function () {
|
153 | if (!this.tHead) return;
|
154 | var cells = this.tHead.rows[0].cells;
|
155 | var l = cells.length;
|
156 | var c;
|
157 | for (var i = 0; i < l; i++) {
|
158 | c = cells[i];
|
159 | if (c._sortType != null && c._sortType != "None") {
|
160 | c.removeChild(c.lastChild);
|
161 | if (typeof c.removeEventListener != "undefined")
|
162 | c.removeEventListener("click", this._headerOnclick, false);
|
163 | else if (typeof c.detachEvent != "undefined")
|
164 | c.detachEvent("onclick", this._headerOnclick);
|
165 | c._sortType = null;
|
166 | c.removeAttribute( "_sortType" );
|
167 | }
|
168 | }
|
169 | };
|
170 |
|
171 | SortableTable.prototype.updateHeaderArrows = function () {
|
172 | if (!this.tHead) return;
|
173 | var cells = this.tHead.rows[0].cells;
|
174 | var l = cells.length;
|
175 | var img;
|
176 | for (var i = 0; i < l; i++) {
|
177 | if (cells[i]._sortType != null && cells[i]._sortType != "None") {
|
178 | img = cells[i].lastChild;
|
179 | if (i == this.sortColumn)
|
180 | img.className = "sort-arrow " + (this.descending ? "descending" : "ascending");
|
181 | else
|
182 | img.className = "sort-arrow";
|
183 | }
|
184 | }
|
185 | };
|
186 |
|
187 | SortableTable.prototype.headerOnclick = function (e) {
|
188 |
|
189 | var el = e.target || e.srcElement;
|
190 | while (el.tagName != "TD")
|
191 | el = el.parentNode;
|
192 |
|
193 | this.sort(SortableTable.msie ? SortableTable.getCellIndex(el) : el.cellIndex);
|
194 | };
|
195 |
|
196 |
|
197 | SortableTable.getCellIndex = function (oTd) {
|
198 | var cells = oTd.parentNode.childNodes
|
199 | var l = cells.length;
|
200 | var i;
|
201 | for (i = 0; cells[i] != oTd && i < l; i++)
|
202 | ;
|
203 | return i;
|
204 | };
|
205 |
|
206 | SortableTable.prototype.getSortType = function (nColumn) {
|
207 | return this.sortTypes[nColumn] || "String";
|
208 | };
|
209 |
|
210 |
|
211 |
|
212 |
|
213 |
|
214 | SortableTable.prototype.sort = function (nColumn, bDescending, sSortType) {
|
215 | if (!this.tBody) return;
|
216 | if (sSortType == null)
|
217 | sSortType = this.getSortType(nColumn);
|
218 |
|
219 |
|
220 | if (sSortType == "None")
|
221 | return;
|
222 |
|
223 | if (bDescending == null) {
|
224 | if (this.sortColumn != nColumn)
|
225 | this.descending = this.defaultDescending;
|
226 | else
|
227 | this.descending = !this.descending;
|
228 | }
|
229 | else
|
230 | this.descending = bDescending;
|
231 |
|
232 | this.sortColumn = nColumn;
|
233 |
|
234 | if (typeof this.onbeforesort == "function")
|
235 | this.onbeforesort();
|
236 |
|
237 | var f = this.getSortFunction(sSortType, nColumn);
|
238 | var a = this.getCache(sSortType, nColumn);
|
239 | var tBody = this.tBody;
|
240 |
|
241 | a.sort(f);
|
242 |
|
243 | if (this.descending)
|
244 | a.reverse();
|
245 |
|
246 | if (SortableTable.removeBeforeSort) {
|
247 |
|
248 | var nextSibling = tBody.nextSibling;
|
249 | var p = tBody.parentNode;
|
250 | p.removeChild(tBody);
|
251 | }
|
252 |
|
253 |
|
254 | var l = a.length;
|
255 | for (var i = 0; i < l; i++)
|
256 | tBody.appendChild(a[i].element);
|
257 |
|
258 | if (SortableTable.removeBeforeSort) {
|
259 |
|
260 | p.insertBefore(tBody, nextSibling);
|
261 | }
|
262 |
|
263 | this.updateHeaderArrows();
|
264 |
|
265 | this.destroyCache(a);
|
266 |
|
267 | if (typeof this.onsort == "function")
|
268 | this.onsort();
|
269 | };
|
270 |
|
271 | SortableTable.prototype.asyncSort = function (nColumn, bDescending, sSortType) {
|
272 | var oThis = this;
|
273 | this._asyncsort = function () {
|
274 | oThis.sort(nColumn, bDescending, sSortType);
|
275 | };
|
276 | window.setTimeout(this._asyncsort, 1);
|
277 | };
|
278 |
|
279 | SortableTable.prototype.getCache = function (sType, nColumn) {
|
280 | if (!this.tBody) return [];
|
281 | var rows = this.tBody.rows;
|
282 | var l = rows.length;
|
283 | var a = new Array(l);
|
284 | var r;
|
285 | for (var i = 0; i < l; i++) {
|
286 | r = rows[i];
|
287 | a[i] = {
|
288 | value: this.getRowValue(r, sType, nColumn),
|
289 | element: r
|
290 | };
|
291 | };
|
292 | return a;
|
293 | };
|
294 |
|
295 | SortableTable.prototype.destroyCache = function (oArray) {
|
296 | var l = oArray.length;
|
297 | for (var i = 0; i < l; i++) {
|
298 | oArray[i].value = null;
|
299 | oArray[i].element = null;
|
300 | oArray[i] = null;
|
301 | }
|
302 | };
|
303 |
|
304 | SortableTable.prototype.getRowValue = function (oRow, sType, nColumn) {
|
305 |
|
306 | if (this._sortTypeInfo[sType] && this._sortTypeInfo[sType].getRowValue)
|
307 | return this._sortTypeInfo[sType].getRowValue(oRow, nColumn);
|
308 |
|
309 | var s;
|
310 | var c = oRow.cells[nColumn];
|
311 | if (typeof c.innerText != "undefined")
|
312 | s = c.innerText;
|
313 | else
|
314 | s = SortableTable.getInnerText(c);
|
315 | return this.getValueFromString(s, sType);
|
316 | };
|
317 |
|
318 | SortableTable.getInnerText = function (oNode) {
|
319 | var s = "";
|
320 | var cs = oNode.childNodes;
|
321 | var l = cs.length;
|
322 | for (var i = 0; i < l; i++) {
|
323 | switch (cs[i].nodeType) {
|
324 | case 1:
|
325 | s += SortableTable.getInnerText(cs[i]);
|
326 | break;
|
327 | case 3:
|
328 | s += cs[i].nodeValue;
|
329 | break;
|
330 | }
|
331 | }
|
332 | return s;
|
333 | };
|
334 |
|
335 | SortableTable.prototype.getValueFromString = function (sText, sType) {
|
336 | if (this._sortTypeInfo[sType])
|
337 | return this._sortTypeInfo[sType].getValueFromString( sText );
|
338 | return sText;
|
339 | |
340 |
|
341 |
|
342 |
|
343 |
|
344 |
|
345 |
|
346 |
|
347 |
|
348 |
|
349 |
|
350 |
|
351 |
|
352 |
|
353 |
|
354 |
|
355 | };
|
356 |
|
357 | SortableTable.prototype.getSortFunction = function (sType, nColumn) {
|
358 | if (this._sortTypeInfo[sType])
|
359 | return this._sortTypeInfo[sType].compare;
|
360 | return SortableTable.basicCompare;
|
361 | };
|
362 |
|
363 | SortableTable.prototype.destroy = function () {
|
364 | this.uninitHeader();
|
365 | var win = this.document.parentWindow;
|
366 | if (win && typeof win.detachEvent != "undefined") {
|
367 | win.detachEvent("onunload", this._onunload);
|
368 | }
|
369 | this._onunload = null;
|
370 | this.element = null;
|
371 | this.tHead = null;
|
372 | this.tBody = null;
|
373 | this.document = null;
|
374 | this._headerOnclick = null;
|
375 | this.sortTypes = null;
|
376 | this._asyncsort = null;
|
377 | this.onsort = null;
|
378 | };
|
379 |
|
380 |
|
381 |
|
382 |
|
383 |
|
384 |
|
385 |
|
386 |
|
387 |
|
388 |
|
389 |
|
390 |
|
391 |
|
392 |
|
393 | SortableTable.prototype.addSortType = function (sType, fGetValueFromString, fCompareFunction, fGetRowValue) {
|
394 | this._sortTypeInfo[sType] = {
|
395 | type: sType,
|
396 | getValueFromString: fGetValueFromString || SortableTable.idFunction,
|
397 | compare: fCompareFunction || SortableTable.basicCompare,
|
398 | getRowValue: fGetRowValue
|
399 | };
|
400 | };
|
401 |
|
402 |
|
403 | SortableTable.prototype.removeSortType = function (sType) {
|
404 | delete this._sortTypeInfo[sType];
|
405 | };
|
406 |
|
407 | SortableTable.basicCompare = function compare(n1, n2) {
|
408 | if (n1.value < n2.value)
|
409 | return -1;
|
410 | if (n2.value < n1.value)
|
411 | return 1;
|
412 | return 0;
|
413 | };
|
414 |
|
415 | SortableTable.idFunction = function (x) {
|
416 | return x;
|
417 | };
|
418 |
|
419 | SortableTable.toUpperCase = function (s) {
|
420 | return s.toUpperCase();
|
421 | };
|
422 |
|
423 | SortableTable.toDate = function (s) {
|
424 | var parts = s.split("-");
|
425 | var d = new Date(0);
|
426 | d.setFullYear(parts[0]);
|
427 | d.setDate(parts[2]);
|
428 | d.setMonth(parts[1] - 1);
|
429 | return d.valueOf();
|
430 | };
|
431 |
|
432 |
|
433 |
|
434 | SortableTable.prototype.addSortType("Number", Number);
|
435 | SortableTable.prototype.addSortType("CaseInsensitiveString", SortableTable.toUpperCase);
|
436 | SortableTable.prototype.addSortType("Date", SortableTable.toDate);
|
437 | SortableTable.prototype.addSortType("String");
|
438 |
|