diff --git a/js/longtable/longtable.js b/js/longtable/longtable.js new file mode 100644 index 00000000..fe3ad1c6 --- /dev/null +++ b/js/longtable/longtable.js @@ -0,0 +1,184 @@ +$.fn.longtable = function(fields, options, data) { + var elem = $(this).addClass("longtable"); + + var orig_data = data; + + options.row_h = options.row_h || 22; + options.checkbox = options.checkbox || false; + + var shown_rows = {}; + + var sorted_by = undefined; + var sorted_reverse = false; + + var filter = function() { return true; }; + + var lt = { + _gen_field_td: function(field, id) { + var el; + if (id === undefined) { + el = $(""); + el.html(fields[field].name || field); + + if (!fields[field].sort_disable) { + el.addClass("sortable").click(function() { + lt._sort_by(field); + }); + } + } + else { + el = $(""); + if (fields[field].fmt) { // Special formatting? + el.html(fields[field].fmt(data[id])); + } + else { + el.html(data[id][field]); + } + } + el.css("width", fields[field].width); + el.css("height", options.row_h); + return el; + }, + _gen_tr: function(id) { + var el = $(""); + $.each(fields, function(field, f) { + lt._gen_field_td(field, id).appendTo(el); + }); + if (id !== undefined) { + el.addClass("row").addClass("row_"+id); + el.css({position: "absolute", top: options.row_h * (id+1)}); + } + return el; + }, + _clean: function() { + elem.find('.row').remove(); + shown_rows = {}; + }, + _remove: function(id) { + elem.find('.row_'+id).remove(); + delete shown_rows[id]; + }, + _insert: function(id) { + var el = lt._gen_tr(id).appendTo(elem); + $(elem).trigger("new-row", [data[id], el]); + shown_rows[id] = true; + }, + + _sort_by: function(field) { + if (field !== undefined) { + if (sorted_by == field) { + sorted_reverse = !sorted_reverse; + } + else { + sorted_reverse = !!fields[field].sort_reverse; + sorted_by = field; + } + } + lt.sort_by(sorted_by, sorted_reverse); + }, + + _apply_filter: function() { + data = data.filter(filter); + }, + _reset_data: function() { + data = orig_data; + }, + + + set_filter: function(f) { + filter = f; + lt._reset_data(); + lt._apply_filter(); + lt._sort_by(); + }, + + sort_by: function(field, reverse) { + if (field !== undefined) { + sorted_by = field; + sorted_reverse = reverse; + + var ord = fields[field].sort_fun || function(a,b) { return lt.sort_alphanum(a[field], b[field]); }; + + data = data.sort(ord); + if (reverse) data = data.reverse(); + } + + lt.update_data(); + }, + + update_viewport: function() { + var first = $(window).scrollTop() - $(elem).offset().top - options.row_h; + var last = first + $(window).height(); + + first = Math.floor(first / options.row_h); + last = Math.ceil (last / options.row_h); + + first = first < 0 ? 0 : first; + last = last >= data.length ? data.length - 1 : last; + + $.each(shown_rows, function(id) { + if (id < first || id > last) { + lt._remove(id); + } + }); + + for (var id = first; id <= last; id++) { + if (!shown_rows[id]) lt._insert(id); + } + }, + + update_data: function() { + $(elem).height((data.length + 1) * options.row_h); + + lt._clean(); + lt.update_viewport(); + }, + + get_data: function() { + return data; + }, + + destroy: function() { + }, + + // http://web.archive.org/web/20130826203933/http://my.opera.com/GreyWyvern/blog/show.dml/1671288 + sort_alphanum: function(a, b) { + function chunkify(t) { + var tz = [], x = 0, y = -1, n = 0, i, j; + + while (i = (j = t.charAt(x++)).charCodeAt(0)) { + var m = (/* dot: i == 46 || */(i >=48 && i <= 57)); + if (m !== n) { + tz[++y] = ""; + n = m; + } + tz[y] += j; + } + return tz; + } + + var aa = chunkify((""+a).toLowerCase()); + var bb = chunkify((""+b).toLowerCase()); + + for (x = 0; aa[x] && bb[x]; x++) { + if (aa[x] !== bb[x]) { + var c = Number(aa[x]), d = Number(bb[x]); + if (c == aa[x] && d == bb[x]) { + return c - d; + } else return (aa[x] > bb[x]) ? 1 : -1; + } + } + return aa.length - bb.length; + } + // End of foreign code + }; + + + + lt._gen_tr().appendTo(elem); + lt.update_data(); + + $(window).on("scroll resize", lt.update_viewport); + + return lt; +}; diff --git a/stylesheets/longtable/longtable.css b/stylesheets/longtable/longtable.css new file mode 100644 index 00000000..09d9a0ab --- /dev/null +++ b/stylesheets/longtable/longtable.css @@ -0,0 +1,31 @@ +.longtable { + display: block; + position: relative; + box-sizing: border-box; +} +.longtable > tbody { + display: block; + box-sizing: border-box; +} +.longtable > tbody > tr { + display: block; + box-sizing: border-box; + clear: left; + width: 100%; +} +.longtable > tbody > tr > td { + display: block; + box-sizing: border-box; + float: left; + padding: 0; +} +.longtable > tbody > tr > th { + display: block; + box-sizing: border-box; + float: left; + padding: 0; +} +.longtable > tbody > tr > th.sortable { + cursor: pointer; +} +