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