datatable.js - jscancer - Javascript crap (relatively small)
(HTM) git clone git://git.codemadness.org/jscancer
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
datatable.js (9134B)
---
1 var datatable_parse_date = Date.parse,
2 datatable_parse_float = parseFloat,
3 datatable_parse_int = parseInt,
4 datatable_parse_string = String;
5
6 function datatable_sort_default(x, y) {
7 return x > y ? 1 : (x == y ? 0 : -1);
8 }
9
10 function datatable_init(el) {
11 var thead = el.tHead;
12 var ths = thead.children[0].children,
13 cols = [];
14 for (var i = 0; i < ths.length; i++)
15 cols.push({
16 filterable: ["1", "true"].indexOf(ths[i].getAttribute("data-filterable") || "true") != -1,
17 parsefn: window["datatable_parse_" + (ths[i].getAttribute("data-parse") || "string")],
18 sortfn: window["datatable_sort_" + (ths[i].getAttribute("data-sort") || "default")],
19 sortable: ["1", "true"].indexOf(ths[i].getAttribute("data-sortable") || "true") != -1
20 });
21 var d = {
22 table: el,
23 thead: thead,
24 ths: ths,
25 tbody: el.tBodies[0],
26 cols: cols,
27 sort: [], // sort options: [colidx, order (ASC = 0, DESC = 1)].
28 lazyscroll: ["1", "true"].indexOf(el.getAttribute("data-lazyscroll") || "") != -1,
29 search: "" // previous search text.
30 };
31 d.data_raw = d.data = datatable_data_parse(d);
32
33 if (d.lazyscroll) {
34 var bodytable = document.createElement("table");
35 bodytable.className = el.className;
36 bodytable.cellSpacing = bodytable.cellPadding = bodytable.border = "0";
37
38 var tr = document.createElement("tr");
39 for (var i = 0; i < ths.length; i++) {
40 var th = ths[i].cloneNode(true);
41 th.innerHTML = "";
42 tr.appendChild(th);
43 }
44 var bodythead = document.createElement("thead");
45 bodythead.appendChild(tr);
46
47 tr = document.createElement("tr");
48 var newths = [];
49 for (var i = 0; i < ths.length; i++)
50 newths.push(tr.appendChild(ths[i].cloneNode(true)));
51 d.ths = newths; // set new columns (for sorting etc)..
52 var elthead = document.createElement("thead");
53 elthead.appendChild(tr);
54
55 var headerstable = document.createElement("table");
56 headerstable.cellSpacing = headerstable.cellPadding = headerstable.border = "0";
57 headerstable.className = el.className;
58 headerstable.appendChild(elthead);
59
60 var headersel = document.createElement("div");
61 headersel.className = "datatable-lazyscroll-headers";
62 headersel.appendChild(headerstable);
63
64 bodytable.appendChild(bodythead);
65
66 var bodyel = document.createElement("div");
67 bodyel.className = "datatable-lazyscroll-body";
68 bodyel.appendChild(bodytable);
69
70 var containerel = document.createElement("div");
71 containerel.className = "datatable-lazyscroll-container";
72 containerel.appendChild(headersel);
73 containerel.appendChild(bodyel);
74
75 var bodytbody = bodytable.appendChild(document.createElement("tbody"));
76 var startfiller = bodytbody.appendChild(document.createElement("tr"));
77 var endfiller = bodytbody.appendChild(document.createElement("tr"));
78
79 el.parentNode.insertBefore(containerel, el);
80
81 var rowheight = 25;
82 d.display = function(data) {
83 var nrows = data.length;
84
85 bodytable.style.height = (nrows * rowheight) + "px";
86
87 var start = parseInt(bodyel.scrollTop / rowheight),
88 end = Math.min(parseInt((bodyel.scrollTop + bodyel.offsetHeight) / rowheight), nrows - 1);
89
90 startfiller.style.height = (start * rowheight) + "px";
91 endfiller.style.height = ((nrows - end - 1) * rowheight) + "px";
92
93 // remove nodes but keep first startfiller and endfiller.
94 for (var c = bodytbody.childNodes; c.length > 2; )
95 bodytbody.removeChild(startfiller.nextSibling);
96
97 for (var i = start, prev = startfiller, p = bodytbody; i <= end; i++)
98 prev = p.insertBefore(d.data[i].tr, prev.nextSibling);
99 };
100 d.scroll = function(y) {
101 bodyel.scrollTop = y;
102 };
103
104 var curscrollleft, verticalscrolltimer;
105 var scroll = function() {
106 // handle left / right scroll.
107 var scrolleft = bodyel.scrollLeft;
108 if (curscrollleft !== scrolleft)
109 headersel.scrollLeft = curscrollleft = scrolleft;
110 // handle up/down scroll.
111 clearTimeout(verticalscrolltimer);
112 verticalscrolltimer = setTimeout(function() {
113 d.display(d.data);
114 }, 16);
115 };
116 window.addEventListener("resize", scroll);
117 bodyel.addEventListener("scroll", scroll);
118 d.display(d.data);
119 } else {
120 d.display = function(data) {
121 var tbody = document.createElement("tbody");
122 for (var i = 0; i < data.length; i++)
123 tbody.appendChild(data[i].tr);
124 d.table.replaceChild(tbody, d.tbody);
125 tbody.style.display = data.length ? "table-row-group" : "none";
126 d.tbody = tbody;
127 };
128 }
129 // setup click event handlers for sorting.
130 for (var i = 0; i < d.ths.length; i++)
131 d.cols[i].sortable && d.ths[i].addEventListener("click", function(idx) {
132 return function(e) {
133 // shift-click for multi-select modifier.
134 datatable_sort_column_toggle(d, idx, e.shiftKey);
135 d.data = datatable_sort(d, d.data);
136 d.display(d.data);
137 };
138 }(i), false);
139 return d;
140 }
141
142 function datatable_sort_column_get(d, idx) {
143 for (var i = 0; i < d.sort.length; i++)
144 if (d.sort[i][0] == idx)
145 return i;
146 return -1;
147 }
148
149 function datatable_sort_column_set(d, idx, order, multi) {
150 var c = datatable_sort_column_get(d, idx);
151 if (multi)
152 if (c != -1)
153 d.sort[c][1] = order;
154 else
155 d.sort.push([ idx, order ]);
156 else
157 d.sort = [ [idx, order] ];
158
159 for (var i = 0; i < d.ths.length; i++) {
160 var c = " " + d.ths[i].className + " ";
161 d.ths[i].className = c.replace(/ sort-(asc|desc) /g, " ").replace(/\s+/g, " ").trim();
162 }
163 for (var i = 0; i < d.sort.length; i++)
164 d.ths[d.sort[i][0]].className += " sort-" + (d.sort[i][1] ? "desc" : "asc");
165 }
166
167 // toggle sort or use default order: ASC.
168 function datatable_sort_column_toggle(d, idx, multi) {
169 var c = datatable_sort_column_get(d, idx);
170 datatable_sort_column_set(d, idx, c == -1 || d.sort[c][1] ? 0 : 1, multi);
171 }
172
173 function datatable_data_parse(d) {
174 var data = [], trs = d.tbody.children;
175 // NOTE: assumes each tr has only "<td>" childnodes.
176 for (var i = 0; i < trs.length; i++) {
177 var values = [], fv = [];
178 for (var j = 0, trc = trs[i].children; j < trc.length; j++) {
179 var td = trc[j], v = td.getAttribute("data-value");
180 // prefer data-value attribute, else use cell contents,
181 // also set preprocess values to filter on cell content
182 // and data-value (case-insensitive).
183 var s = td.textContent || td.innerText;
184 if (typeof(v) != "undefined" && v !== null) {
185 fv.push([ s.toLowerCase(), v.toLowerCase() ]);
186 values.push(d.cols[j].parsefn(v));
187 } else {
188 fv.push([ s.toLowerCase() ]);
189 values.push(d.cols[j].parsefn(s));
190 }
191 }
192 data.push({
193 filtervalues: fv,
194 tr: trs[i],
195 values: values
196 });
197 }
198 return data;
199 }
200
201 function datatable_sort(d, data) {
202 // setup sort functions once (in order for multi-select).
203 var sortfns = d.sort.map(function(s) {
204 return (function(c, o, fn) {
205 if (o)
206 return function(xvals, yvals) {
207 return -fn(xvals[c], yvals[c]);
208 };
209 else
210 return function(xvals, yvals) {
211 return fn(xvals[c], yvals[c]);
212 };
213 })(s[0], s[1], d.cols[s[0]].sortfn);
214 });
215 return data.sort(function(x, y) {
216 for (var i = 0, r; i < sortfns.length; i++)
217 if ((r = sortfns[i](x.values, y.values)) != 0)
218 return r;
219 return r;
220 });
221 }
222
223 function datatable_filter(d, data, s) {
224 var ret = [], tok = s.toLowerCase().split(" ");
225 for (var i = 0; i < data.length; i++) {
226 var fc = 0;
227 for (var k = 0; k < tok.length && fc < tok.length; k++) {
228 var f = false;
229 for (var j = 0; j < data[i].filtervalues.length && fc < tok.length && !f; j++)
230 for (var l = 0; l < data[i].filtervalues[j].length && !f &&
231 d.cols[j].filterable; l++)
232 if (data[i].filtervalues[j][l].indexOf(tok[k]) != -1)
233 f = true;
234 if (f)
235 fc++;
236 }
237 // all tokens (separated by space) must match.
238 if (fc == tok.length)
239 ret.push(data[i]);
240 }
241 return ret;
242 }
243
244 function datatable_filter_text(d, s) {
245 s = s.toLowerCase();
246 if (d.search == s)
247 return;
248 // if token string is different or string not in previous search: use raw data,
249 // else filter on existing data and no need to sort.
250 if ((d.search.split(" ").length != s.split(" ").length) ||
251 s.indexOf(d.search) == -1) {
252 d.data = datatable_sort(d, datatable_filter(d, d.data_raw, s));
253 } else {
254 d.data = datatable_filter(d, d.data, s);
255 }
256 d.search = s;
257 d.display(d.data);
258 if (d.scroll)
259 d.scroll(0);
260 }
261
262 function datatable_filter_delayed(d, fn, e) {
263 clearTimeout(d.filter_timer);
264 d.filter_timer = setTimeout(function() {
265 fn(e);
266 }, 150); // filter delay in ms.
267 }
268
269 function datatable_autoload() {
270 // convert to Array (not changed in-place, mandatory).
271 var ds = [], dl = [], els = document.getElementsByClassName && document.getElementsByClassName("datatable") || [];
272 for (var i = 0; i < els.length; i++)
273 dl.push(els[i]);
274 for (var i = 0, d; i < dl.length; i++) {
275 if ((d = datatable_init(dl[i])) === null)
276 continue;
277 var input = dl[i].parentNode.getElementsByClassName("filter-text");
278 // delayed filtering.
279 for (var j = 0; j < input.length; j++) {
280 input[j].addEventListener("input", (function(d, el) {
281 return function(e) {
282 datatable_filter_delayed(d, function() {
283 datatable_filter_text(d, el.value);
284 }, e);
285 };
286 })(d, input[j]), false);
287 }
288 ds.push(d);
289 }
290 return ds;
291 }