diff options
24 files changed, 2317 insertions, 1394 deletions
diff --git a/wqflask/wqflask/interval_mapping/interval_mapping.py b/wqflask/wqflask/interval_mapping/interval_mapping.py index 672a9401..108bc747 100755 --- a/wqflask/wqflask/interval_mapping/interval_mapping.py +++ b/wqflask/wqflask/interval_mapping/interval_mapping.py @@ -53,6 +53,9 @@ class IntervalMapping(object): self.set_options(start_vars) + self.score_type = "LRS" + self.cutoff = 3 + self.json_data = {} self.json_data['lodnames'] = ['lod.hk'] self.gen_reaper_results(tempdata) @@ -65,22 +68,17 @@ class IntervalMapping(object): chromosome_mb_lengths[key] = self.species.chromosomes.chromosomes[key].mb_length - #print("self.qtl_results:", self.qtl_results) - print("JSON DATA:", self.json_data) - #os.chdir(webqtlConfig.TMPDIR) json_filename = webqtlUtil.genRandStr(prefix="intmap_") json.dumps(self.json_data, webqtlConfig.TMPDIR + json_filename) - + self.js_data = dict( - result_score_type = "LRS", + result_score_type = self.score_type, manhattan_plot = self.manhattan_plot, - additive = self.additive, chromosomes = chromosome_mb_lengths, qtl_results = self.qtl_results, json_data = self.json_data - #lrs_lod = self.lrs_lod, ) def set_options(self, start_vars): @@ -158,7 +156,6 @@ class IntervalMapping(object): self.json_data['chr'] = [] self.json_data['pos'] = [] self.json_data['lod.hk'] = [] - self.json_data['additive'] = [] self.json_data['markernames'] = [] for qtl in reaper_results: reaper_locus = qtl.locus @@ -166,6 +163,7 @@ class IntervalMapping(object): self.json_data['lod.hk'].append(qtl.lrs) self.json_data['markernames'].append(reaper_locus.name) if self.additive: + self.json_data['additive'] = [] self.json_data['additive'].append(qtl.additive) locus = {"name":reaper_locus.name, "chr":reaper_locus.chr, "cM":reaper_locus.cM, "Mb":reaper_locus.Mb} qtl = {"lrs": qtl.lrs, "locus": locus, "additive": qtl.additive} @@ -206,8 +204,9 @@ class IntervalMapping(object): self.json_data['chr'] = [] self.json_data['pos'] = [] self.json_data['lod.hk'] = [] - self.json_data['additive'] = [] self.json_data['markernames'] = [] + if self.additive: + self.json_data['additive'] = [] #Need to convert the QTL objects that qtl reaper returns into a json serializable dictionary self.qtl_results = [] @@ -221,39 +220,8 @@ class IntervalMapping(object): self.json_data['additive'].append(qtl.additive) locus = {"name":reaper_locus.name, "chr":reaper_locus.chr, "cM":reaper_locus.cM, "Mb":reaper_locus.Mb} qtl = {"lrs_value": qtl.lrs, "chr":reaper_locus.chr, "Mb":reaper_locus.Mb, - "cM":reaper_locus.cM, "name":reaper_locus.name, "additive":qtl.additive} + "cM":reaper_locus.cM, "name":reaper_locus.name, "additive":qtl.additive, "dominance":qtl.dominance} self.qtl_results.append(qtl) - - - def gen_qtl_results_2(self, tempdata): - """Generates qtl results for plotting interval map""" - - self.dataset.group.get_markers() - self.dataset.read_genotype_file() - - pheno_vector = np.array([val == "x" and np.nan or float(val) for val in self.vals]) - - #if self.dataset.group.species == "human": - # p_values, t_stats = self.gen_human_results(pheno_vector, tempdata) - #else: - genotype_data = [marker['genotypes'] for marker in self.dataset.group.markers.markers] - - no_val_samples = self.identify_empty_samples() - trimmed_genotype_data = self.trim_genotypes(genotype_data, no_val_samples) - - genotype_matrix = np.array(trimmed_genotype_data).T - - t_stats, p_values = lmm.run( - pheno_vector, - genotype_matrix, - restricted_max_likelihood=True, - refit=False, - temp_data=tempdata - ) - - self.dataset.group.markers.add_pvalues(p_values) - - self.qtl_results = self.dataset.group.markers.markers def identify_empty_samples(self): diff --git a/wqflask/wqflask/marker_regression/marker_regression.py b/wqflask/wqflask/marker_regression/marker_regression.py index c003f5e8..850dfc7f 100755 --- a/wqflask/wqflask/marker_regression/marker_regression.py +++ b/wqflask/wqflask/marker_regression/marker_regression.py @@ -79,9 +79,9 @@ class MarkerRegression(object): included_markers, p_values = gemma_mapping.run_gemma(self.dataset, self.samples, self.vals) self.dataset.group.get_specified_markers(markers = included_markers) self.dataset.group.markers.add_pvalues(p_values) - qtl_results = self.dataset.group.markers.markers + results = self.dataset.group.markers.markers elif self.mapping_method == "rqtl_plink": - qtl_results = self.run_rqtl_plink() + results = self.run_rqtl_plink() elif self.mapping_method == "rqtl_geno": if start_vars['num_perm'] == "": self.num_perm = 0 @@ -95,32 +95,32 @@ class MarkerRegression(object): if start_vars['pair_scan'] == "true": self.pair_scan = True - qtl_results = self.run_rqtl_geno() - print("qtl_results:", qtl_results) + results = self.run_rqtl_geno() + print("qtl_results:", results) elif self.mapping_method == "plink": - qtl_results = self.run_plink() - #print("qtl_results:", pf(qtl_results)) + results = self.run_plink() + #print("qtl_results:", pf(results)) elif self.mapping_method == "pylmm": print("RUNNING PYLMM") self.num_perm = start_vars['num_perm'] if self.num_perm != "": if int(self.num_perm) > 0: self.run_permutations(str(temp_uuid)) - qtl_results = self.gen_data(str(temp_uuid)) + results = self.gen_data(str(temp_uuid)) else: print("RUNNING NOTHING") if self.pair_scan == True: - self.filtered_markers = [] + self.qtl_results = [] highest_chr = 1 #This is needed in order to convert the highest chr to X/Y - for marker in qtl_results: + for marker in results: if marker['chr1'] > 0 or marker['chr1'] == "X" or marker['chr1'] == "X/Y": if marker['chr1'] > highest_chr or marker['chr1'] == "X" or marker['chr1'] == "X/Y": highest_chr = marker['chr1'] if 'lod_score' in marker: - self.filtered_markers.append(marker) + self.qtl_results.append(marker) - for qtl in enumerate(self.filtered_markers): + for qtl in enumerate(self.qtl_results): self.json_data['chr1'].append(str(qtl['chr1'])) self.json_data['chr2'].append(str(qtl['chr2'])) self.json_data['Mb'].append(qtl['Mb']) @@ -132,19 +132,20 @@ class MarkerRegression(object): data_set = self.dataset.name, maf = self.maf, manhattan_plot = self.manhattan_plot, - qtl_results = self.filtered_markers, + qtl_results = self.qtl_results, ) else: - self.lod_cutoff = 2 - self.filtered_markers = [] + self.score_type = "LRS" + self.cutoff = 2 + self.qtl_results = [] highest_chr = 1 #This is needed in order to convert the highest chr to X/Y - for marker in qtl_results: + for marker in results: if marker['chr'] > 0 or marker['chr'] == "X" or marker['chr'] == "X/Y": if marker['chr'] > highest_chr or marker['chr'] == "X" or marker['chr'] == "X/Y": highest_chr = marker['chr'] if 'lod_score' in marker: - self.filtered_markers.append(marker) + self.qtl_results.append(marker) self.json_data['chr'] = [] self.json_data['pos'] = [] @@ -155,8 +156,7 @@ class MarkerRegression(object): self.json_data['significant'] = self.significant #Need to convert the QTL objects that qtl reaper returns into a json serializable dictionary - self.qtl_results = [] - for index, qtl in enumerate(self.filtered_markers): + for index, qtl in enumerate(self.qtl_results): if index<40: print("lod score is:", qtl['lod_score']) if qtl['chr'] == highest_chr and highest_chr != "X" and highest_chr != "X/Y": @@ -179,14 +179,14 @@ class MarkerRegression(object): self.js_data = dict( - result_score_type = "LOD", + result_score_type = self.score_type, json_data = self.json_data, this_trait = self.this_trait.name, data_set = self.dataset.name, maf = self.maf, manhattan_plot = self.manhattan_plot, chromosomes = chromosome_mb_lengths, - qtl_results = self.filtered_markers, + qtl_results = self.qtl_results, ) diff --git a/wqflask/wqflask/static/new/javascript/create_lodchart.js b/wqflask/wqflask/static/new/javascript/create_lodchart.js index 2537e9e2..b8fcf1f8 100644 --- a/wqflask/wqflask/static/new/javascript/create_lodchart.js +++ b/wqflask/wqflask/static/new/javascript/create_lodchart.js @@ -3,7 +3,7 @@ var create_lod_chart; create_lod_chart = function() { - var additive, chrrect, data, h, halfh, margin, mychart, totalh, totalw, w; + var chrrect, data, h, halfh, margin, mychart, totalh, totalw, w; h = 500; w = 1200; margin = { @@ -16,12 +16,7 @@ halfh = h + margin.top + margin.bottom; totalh = halfh * 2; totalw = w + margin.left + margin.right; - if ('additive' in js_data) { - additive = js_data.additive; - } else { - additive = false; - } - console.log("js_data:", js_data); + //console.log("js_data:", js_data); mychart = lodchart().lodvarname("lod.hk").height(h).width(w).margin(margin).ylab(js_data.result_score_type + " score").manhattanPlot(js_data.manhattan_plot); data = js_data.json_data; d3.select("div#topchart").datum(data).call(mychart); diff --git a/wqflask/wqflask/static/new/javascript/lod_chart.js b/wqflask/wqflask/static/new/javascript/lod_chart.js index 631d8632..2ea3a3e8 100644 --- a/wqflask/wqflask/static/new/javascript/lod_chart.js +++ b/wqflask/wqflask/static/new/javascript/lod_chart.js @@ -20,7 +20,6 @@ lodchart = function() { }; titlepos = 20; manhattanPlot = false; - additive = false; ylim = null; additive_ylim = null; nyticks = 5; @@ -30,7 +29,8 @@ lodchart = function() { darkrect = "#F1F1F9"; lightrect = "#FBFBFF"; lodlinecolor = "darkslateblue"; - additivelinecolor = "red"; + additivelinecolor_plus = "red"; + additivelinecolor_negative = "green"; linewidth = 2; suggestivecolor = "gainsboro"; significantcolor = "#EBC7C7"; @@ -70,7 +70,8 @@ lodchart = function() { return results; })(); ylim = ylim != null ? ylim : [0, d3.max(data[lodvarname])]; - if (additive) { + + if ('additive' in data) { data['additive'] = (function() { var j, len, ref, results; ref = data['additive']; @@ -91,7 +92,7 @@ lodchart = function() { g.append("rect").attr("x", margin.left).attr("y", margin.top).attr("height", height).attr("width", width).attr("fill", darkrect).attr("stroke", "none"); yscale.domain(ylim).range([height + margin.top, margin.top + margin.inner]); yticks = yticks != null ? yticks : yscale.ticks(nyticks); - if (additive) { + if ('additive' in data) { additive_yscale.domain(additive_ylim).range([height + margin.top, margin.top + margin.inner + height / 2]); additive_yticks = additive_yticks != null ? additive_yticks : additive_yscale.ticks(nyticks); } @@ -147,7 +148,7 @@ lodchart = function() { return formatAxis(yticks)(d); }); yaxis.append("text").attr("class", "title").attr("y", margin.top + height / 2).attr("x", margin.left - axispos.ytitle).text(ylab).attr("transform", rotate_ylab ? "rotate(270," + (margin.left - axispos.ytitle) + "," + (margin.top + height / 2) + ")" : "").attr("text-anchor", "middle").attr("fill", "slateblue"); - if (additive) { + if ('additive' in data) { rotate_additive_ylab = rotate_additive_ylab != null ? rotate_additive_ylab : additive_ylab.length > 1; additive_yaxis = g.append("g").attr("class", "y axis"); additive_yaxis.selectAll("empty").data(additive_yticks).enter().append("line").attr("y1", function(d) { @@ -186,12 +187,12 @@ lodchart = function() { return yscale(data.lodByChr[chr][i][lodcolumn]); }); }; - if (additive) { + if ('additive' in data) { additivecurve = function(chr, lodcolumn) { return d3.svg.line().x(function(d) { return xscale[chr](d); }).y(function(d, i) { - return additive_yscale(data.additiveByChr[chr][i][lodcolumn]); + return additive_yscale(data.additiveByChr[chr][i]); }); }; } @@ -203,12 +204,18 @@ lodchart = function() { curves.append("path").datum(data.posByChr[chr[0]]).attr("d", lodcurve(chr[0], lodvarnum)).attr("stroke", lodlinecolor).attr("fill", "none").attr("stroke-width", linewidth).style("pointer-events", "none"); } } - if (additive) { + if ('additive' in data) { ref1 = data.chrnames; for (k = 0, len1 = ref1.length; k < len1; k++) { chr = ref1[k]; if (chr.indexOf(data['chr'])) { - curves.append("path").datum(data.posByChr[chr[0]]).attr("d", additivecurve(chr[0], lodvarnum)).attr("stroke", additivelinecolor).attr("fill", "none").attr("stroke-width", 1).style("pointer-events", "none"); + if (additivecurve(chr[0], lodvarnum).y < 0) { + additivecurve(chr[0], lodvarnum).y = Math.abs(additivecurve(chr[0], lodvarnum).y) + curves.append("path").datum(data.posByChr[chr[0]]).attr("d", additivecurve(chr[0], lodvarnum)).attr("stroke", additivelinecolor_negative).attr("fill", "none").attr("stroke-width", 1).style("pointer-events", "none"); + } + else { + curves.append("path").datum(data.posByChr[chr[0]]).attr("d", additivecurve(chr[0], lodvarnum)).attr("stroke", additivelinecolor_plus).attr("fill", "none").attr("stroke-width", 1).style("pointer-events", "none"); + } } } } @@ -430,9 +437,6 @@ lodchart = function() { chart.yscale = function() { return yscale; }; - chart.additive = function() { - return additive; - }; chart.additive_yscale = function() { return additive_yscale; }; diff --git a/wqflask/wqflask/static/new/javascript/panelutil.js b/wqflask/wqflask/static/new/javascript/panelutil.js index 7c14f4de..113512b4 100644 --- a/wqflask/wqflask/static/new/javascript/panelutil.js +++ b/wqflask/wqflask/static/new/javascript/panelutil.js @@ -47,12 +47,19 @@ reorgLodData = function(data, lodvarname) { } data.posByChr = {}; data.lodByChr = {}; + if ('additive' in data){ + data.additiveByChr = {}; + } _ref = data.chrnames; for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { chr = _ref[i]; data.posByChr[chr[0]] = []; data.lodByChr[chr[0]] = []; + if ('additive' in data){ + data.additiveByChr[chr[0]] = []; + } _ref1 = data.pos; + for (j = _j = 0, _len1 = _ref1.length; _j < _len1; j = ++_j) { pos = _ref1[j]; if (data.chr[j].toString() === chr[0]) { @@ -71,6 +78,12 @@ reorgLodData = function(data, lodvarname) { return _results; })(); data.lodByChr[chr[0]].push(lodval); + + if ('additive' in data){ + addval = data['additive'][j] + data.additiveByChr[chr[0]].push(addval); + } + } } } diff --git a/wqflask/wqflask/static/new/javascript/search_results.coffee b/wqflask/wqflask/static/new/javascript/search_results.coffee index c4e6b1a2..e0cfc61a 100755 --- a/wqflask/wqflask/static/new/javascript/search_results.coffee +++ b/wqflask/wqflask/static/new/javascript/search_results.coffee @@ -15,8 +15,7 @@ $ -> $(".trait_checkbox").trigger('click') add = -> - traits = $("#trait_table input:checked").map(-> - return $(this).val()).get() + traits = $("#trait_table input:checked").map(-> return $(this).val()).get() console.log("checked length is:", traits.length) console.log("checked is:", traits) $.colorbox({href:"/collections/add?traits=#{traits}"}) diff --git a/wqflask/wqflask/static/new/javascript/search_results.js b/wqflask/wqflask/static/new/javascript/search_results.js index ba2ebb4f..7064b6ff 100755 --- a/wqflask/wqflask/static/new/javascript/search_results.js +++ b/wqflask/wqflask/static/new/javascript/search_results.js @@ -1,17 +1,82 @@ -// Generated by CoffeeScript 1.8.0 $(function() { var add, change_buttons, checked_traits, deselect_all, invert, remove, removed_traits, select_all; + checked_traits = null; select_all = function() { console.log("selected_all"); - return $(".trait_checkbox").prop('checked', true); + $(".trait_checkbox").each(function() { + $(this).prop('checked', true); + if (!$(this).closest('tr').hasClass('selected')) { + $(this).closest('tr').addClass('selected') + } + }); }; + deselect_all = function() { - return $(".trait_checkbox").prop('checked', false); + $(".trait_checkbox").each(function() { + $(this).prop('checked', false); + if ($(this).closest('tr').hasClass('selected')) { + $(this).closest('tr').removeClass('selected') + } + }); }; + invert = function() { - return $(".trait_checkbox").trigger('click'); + $(".trait_checkbox").each(function() { + if ($(this).prop('checked') == true) { + $(this).prop('checked', false) + } + else { + $(this).prop('checked', true) + } + + if ($(this).closest('tr').hasClass('selected')) { + $(this).closest('tr').removeClass('selected') + } + else { + $(this).closest('tr').addClass('selected') + } + }); }; + + $('#searchbox').keyup(function(){ + $('#trait_table').DataTable().search($(this).val()).draw(); + }); + + $('#select_top').keyup(function(){ + num_rows = $(this).val() + if (num_rows = parseInt(num_rows)){ + i = 0 + $('#trait_table > tbody > tr').each(function(){ + if (i < num_rows) { + $(this).find('.trait_checkbox').prop("checked", true) + if (!$(this).closest('tr').hasClass('selected')) { + $(this).closest('tr').addClass('selected') + } + } + i += 1 + }); + } + change_buttons(); + }); + + $('.trait_checkbox:checkbox').change(function() { + console.log("CHANGED") + change_buttons() + + if ($(this).is(":checked")) { + if (!$(this).closest('tr').hasClass('selected')) { + $(this).closest('tr').addClass('selected') + } + } + else { + if ($(this).closest('tr').hasClass('selected')) { + $(this).closest('tr').removeClass('selected') + } + } + + }); + add = function() { var traits; traits = $("#trait_table input:checked").map(function() { @@ -28,7 +93,7 @@ $(function() { return checked_traits.closest("tr").fadeOut(); }; change_buttons = function() { - var button, buttons, item, num_checked, text, _i, _j, _k, _l, _len, _len1, _len2, _len3, _results, _results1; + var button, buttons, item, num_checked, text, _i, _j, _k, _l, _len, _len2, _len3, _len4, _results, _results2; buttons = ["#add", "#remove"]; num_checked = $('.trait_checkbox:checked').length; console.log("num_checked is:", num_checked); @@ -38,31 +103,13 @@ $(function() { $(button).prop("disabled", true); } } else { - for (_j = 0, _len1 = buttons.length; _j < _len1; _j++) { + for (_j = 0, _len2 = buttons.length; _j < _len2; _j++) { button = buttons[_j]; $(button).prop("disabled", false); } } - if (num_checked > 1) { - console.log("in loop"); - _results = []; - for (_k = 0, _len2 = buttons.length; _k < _len2; _k++) { - item = buttons[_k]; - console.log(" processing item:", item); - _results.push(text = $(item).html()); - } - return _results; - } else { - console.log("in loop"); - _results1 = []; - for (_l = 0, _len3 = buttons.length; _l < _len3; _l++) { - item = buttons[_l]; - console.log(" processing item:", item); - _results1.push(text = $(item).html()); - } - return _results1; - } }; + remove = function() { var traits, uc_id; checked_traits = $("#trait_table input:checked"); @@ -88,6 +135,5 @@ $(function() { $("#invert").click(invert); $("#add").click(add); $("#remove").click(remove); - $('.trait_checkbox').click(change_buttons); - return $('.btn').click(change_buttons); -}); + $('.trait_checkbox, .btn').click(change_buttons); +});
\ No newline at end of file diff --git a/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.coffee b/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.coffee index 16ca1886..d14fb98c 100755 --- a/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.coffee +++ b/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.coffee @@ -112,6 +112,11 @@ open_mapping_results = (data) -> form.submit() ) +outlier_text = "One or more outliers exist in this data set. Please review values before mapping. \ + Including outliers when mapping may lead to misleading results. \ + We recommend <A HREF=\"http://en.wikipedia.org/wiki/Winsorising\">winsorising</A> the outliers \ + or simply deleting them." + showalert = (message,alerttype) -> $('#alert_placeholder').append('<div id="alertdiv" class="alert ' + alerttype + '"><a class="close" data-dismiss="alert">×</a><span>'+message+'</span></div>') @@ -126,6 +131,11 @@ $('input[name=display_all]').change(() => $('#suggestive').hide() ) +$("#pylmm_mapping_compute").on("mouseover", => + if ( $(".outlier").length and $(".outlier-alert").length < 1 ) + showalert(outlier_text, "alert-success outlier-alert") +) + $("#pylmm_compute").on("click", => $("#progress_bar_container").modal() url = "/marker_regression" @@ -140,8 +150,7 @@ $("#pylmm_compute").on("click", => # block_outliers() do_ajax_post(url, form_data) ) - - + $("#rqtl_geno_compute").on("click", => $("#progress_bar_container").modal() @@ -187,11 +196,12 @@ $("#gemma_compute").on("click", => do_ajax_post(url, form_data) ) +$("#interval_mapping_compute").on("mouseover", => + if ( $(".outlier").length and $(".outlier-alert").length < 1 ) + showalert(outlier_text, "alert-success outlier-alert") +) + $("#interval_mapping_compute").on("click", => - showalert("One or more outliers exist in this data set. Please review values before mapping. \ - Including outliers when mapping may lead to misleading results. \ - We recommend <A HREF=\"http://en.wikipedia.org/wiki/Winsorising\">winsorising</A> the outliers \ - or simply deleting them.", "alert-success") console.log("In interval mapping") $("#progress_bar_container").modal() url = "/interval_mapping" diff --git a/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.js b/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.js index d6f4ba89..3be40a57 100755 --- a/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.js +++ b/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.js @@ -1,249 +1,269 @@ -// Generated by CoffeeScript 1.9.2 -var block_outliers, composite_mapping_fields, do_ajax_post, get_progress, mapping_method_fields, open_mapping_results, showalert, submit_special, toggle_enable_disable, update_time_remaining; - -submit_special = function() { - var url; - console.log("In submit_special"); - console.log("this is:", this); - console.log("$(this) is:", $(this)); - url = $(this).data("url"); - console.log("url is:", url); - $("#trait_data_form").attr("action", url); - return $("#trait_data_form").submit(); -}; - -update_time_remaining = function(percent_complete) { - var minutes_remaining, now, period, total_seconds_remaining; - now = new Date(); - period = now.getTime() - root.start_time; - console.log("period is:", period); - if (period > 8000) { - total_seconds_remaining = (period / percent_complete * (100 - percent_complete)) / 1000; - minutes_remaining = Math.round(total_seconds_remaining / 60); - if (minutes_remaining < 3) { - return $('#time_remaining').text(Math.round(total_seconds_remaining) + " seconds remaining"); - } else { - return $('#time_remaining').text(minutes_remaining + " minutes remaining"); +// Generated by CoffeeScript 1.8.0 +(function() { + var block_outliers, composite_mapping_fields, do_ajax_post, get_progress, mapping_method_fields, open_mapping_results, outlier_text, showalert, submit_special, toggle_enable_disable, update_time_remaining; + + submit_special = function() { + var url; + console.log("In submit_special"); + console.log("this is:", this); + console.log("$(this) is:", $(this)); + url = $(this).data("url"); + console.log("url is:", url); + $("#trait_data_form").attr("action", url); + return $("#trait_data_form").submit(); + }; + + update_time_remaining = function(percent_complete) { + var minutes_remaining, now, period, total_seconds_remaining; + now = new Date(); + period = now.getTime() - root.start_time; + console.log("period is:", period); + if (period > 8000) { + total_seconds_remaining = (period / percent_complete * (100 - percent_complete)) / 1000; + minutes_remaining = Math.round(total_seconds_remaining / 60); + if (minutes_remaining < 3) { + return $('#time_remaining').text(Math.round(total_seconds_remaining) + " seconds remaining"); + } else { + return $('#time_remaining').text(minutes_remaining + " minutes remaining"); + } } - } -}; - -get_progress = function() { - var params, params_str, temp_uuid, url; - console.log("temp_uuid:", $("#temp_uuid").val()); - temp_uuid = $("#temp_uuid").val(); - params = { - key: temp_uuid }; - params_str = $.param(params); - url = "/get_temp_data?" + params_str; - console.log("url:", url); - $.ajax({ - type: "GET", - url: url, - success: (function(_this) { - return function(progress_data) { - var percent_complete; - percent_complete = progress_data['percent_complete']; - console.log("in get_progress data:", progress_data); - $('#marker_regression_progress').css("width", percent_complete + "%"); - if (root.start_time) { - if (!isNaN(percent_complete)) { - return update_time_remaining(percent_complete); - } - } else { - return root.start_time = new Date().getTime(); - } - }; - })(this) - }); - return false; -}; -block_outliers = function() { - return $('.outlier').each((function(_this) { - return function(_index, element) { - return $(element).find('.trait_value_input').val('x'); + get_progress = function() { + var params, params_str, temp_uuid, url; + console.log("temp_uuid:", $("#temp_uuid").val()); + temp_uuid = $("#temp_uuid").val(); + params = { + key: temp_uuid }; - })(this)); -}; - -do_ajax_post = function(url, form_data) { - $.ajax({ - type: "POST", - url: url, - data: form_data, - error: (function(_this) { - return function(xhr, ajaxOptions, thrownError) { - alert("Sorry, an error occurred"); - console.log(xhr); - clearInterval(_this.my_timer); - $('#progress_bar_container').modal('hide'); - $('#static_progress_bar_container').modal('hide'); - return $("body").html("We got an error."); - }; - })(this), - success: (function(_this) { - return function(data) { - clearInterval(_this.my_timer); - $('#progress_bar_container').modal('hide'); - $('#static_progress_bar_container').modal('hide'); - return open_mapping_results(data); - }; - })(this) - }); - console.log("settingInterval"); - this.my_timer = setInterval(get_progress, 1000); - return false; -}; - -open_mapping_results = function(data) { - return $.colorbox({ - html: data, - href: "#mapping_results_holder", - height: "90%", - width: "90%", - onComplete: (function(_this) { - return function() { - var filename, getSvgXml; - root.create_lod_chart(); - filename = "lod_chart_" + js_data.this_trait; - getSvgXml = function() { - var svg; - svg = $("#topchart").find("svg")[0]; - return (new XMLSerializer).serializeToString(svg); + params_str = $.param(params); + url = "/get_temp_data?" + params_str; + console.log("url:", url); + $.ajax({ + type: "GET", + url: url, + success: (function(_this) { + return function(progress_data) { + var percent_complete; + percent_complete = progress_data['percent_complete']; + console.log("in get_progress data:", progress_data); + $('#marker_regression_progress').css("width", percent_complete + "%"); + if (root.start_time) { + if (!isNaN(percent_complete)) { + return update_time_remaining(percent_complete); + } + } else { + return root.start_time = new Date().getTime(); + } }; - $("#exportform > #export").click(function() { - var form, svg_xml; - svg_xml = getSvgXml(); - form = $("#exportform"); - form.find("#data").val(svg_xml); - form.find("#filename").val(filename); - return form.submit(); - }); - return $("#exportpdfform > #export_pdf").click(function() { - var form, svg_xml; - svg_xml = getSvgXml(); - form = $("#exportpdfform"); - form.find("#data").val(svg_xml); - form.find("#filename").val(filename); - return form.submit(); - }); - }; - })(this) - }); -}; - -showalert = function(message, alerttype) { - return $('#alert_placeholder').append('<div id="alertdiv" class="alert ' + alerttype + '"><a class="close" data-dismiss="alert">�</a><span>' + message + '</span></div>'); -}; - -$('#suggestive').hide(); - -$('input[name=display_all]').change((function(_this) { - return function() { - console.log("check"); - if ($('input[name=display_all]:checked').val() === "False") { - return $('#suggestive').show(); - } else { - return $('#suggestive').hide(); - } + })(this) + }); + return false; }; -})(this)); - -$("#pylmm_compute").on("click", (function(_this) { - return function() { - var form_data, url; - $("#progress_bar_container").modal(); - url = "/marker_regression"; - $('input[name=method]').val("pylmm"); - $('input[name=num_perm]').val($('input[name=num_perm_pylmm]').val()); - $('input[name=manhattan_plot]').val($('input[name=manhattan_plot_pylmm]:checked').val()); - form_data = $('#trait_data_form').serialize(); - console.log("form_data is:", form_data); - return do_ajax_post(url, form_data); + + block_outliers = function() { + return $('.outlier').each((function(_this) { + return function(_index, element) { + return $(element).find('.trait_value_input').val('x'); + }; + })(this)); }; -})(this)); - -$("#rqtl_geno_compute").on("click", (function(_this) { - return function() { - var form_data, url; - $("#progress_bar_container").modal(); - url = "/marker_regression"; - $('input[name=method]').val("rqtl_geno"); - $('input[name=num_perm]').val($('input[name=num_perm_rqtl_geno]').val()); - $('input[name=manhattan_plot]').val($('input[name=manhattan_plot_rqtl]:checked').val()); - $('input[name=control_marker]').val($('input[name=control_rqtl_geno]').val()); - form_data = $('#trait_data_form').serialize(); - console.log("form_data is:", form_data); - return do_ajax_post(url, form_data); + + do_ajax_post = function(url, form_data) { + $.ajax({ + type: "POST", + url: url, + data: form_data, + error: (function(_this) { + return function(xhr, ajaxOptions, thrownError) { + alert("Sorry, an error occurred"); + console.log(xhr); + clearInterval(_this.my_timer); + $('#progress_bar_container').modal('hide'); + $('#static_progress_bar_container').modal('hide'); + return $("body").html("We got an error."); + }; + })(this), + success: (function(_this) { + return function(data) { + clearInterval(_this.my_timer); + $('#progress_bar_container').modal('hide'); + $('#static_progress_bar_container').modal('hide'); + return open_mapping_results(data); + }; + })(this) + }); + console.log("settingInterval"); + this.my_timer = setInterval(get_progress, 1000); + return false; }; -})(this)); - -$("#plink_compute").on("click", (function(_this) { - return function() { - var form_data, url; - $("#static_progress_bar_container").modal(); - url = "/marker_regression"; - $('input[name=method]').val("plink"); - $('input[name=maf]').val($('input[name=maf_plink]').val()); - form_data = $('#trait_data_form').serialize(); - console.log("form_data is:", form_data); - return do_ajax_post(url, form_data); + + open_mapping_results = function(data) { + return $.colorbox({ + html: data, + href: "#mapping_results_holder", + height: "90%", + width: "90%", + onComplete: (function(_this) { + return function() { + var filename, getSvgXml; + root.create_lod_chart(); + filename = "lod_chart_" + js_data.this_trait; + getSvgXml = function() { + var svg; + svg = $("#topchart").find("svg")[0]; + return (new XMLSerializer).serializeToString(svg); + }; + $("#exportform > #export").click(function() { + var form, svg_xml; + svg_xml = getSvgXml(); + form = $("#exportform"); + form.find("#data").val(svg_xml); + form.find("#filename").val(filename); + return form.submit(); + }); + return $("#exportpdfform > #export_pdf").click(function() { + var form, svg_xml; + svg_xml = getSvgXml(); + form = $("#exportpdfform"); + form.find("#data").val(svg_xml); + form.find("#filename").val(filename); + return form.submit(); + }); + }; + })(this) + }); }; -})(this)); - -$("#gemma_compute").on("click", (function(_this) { - return function() { - var form_data, url; - console.log("RUNNING GEMMA"); - $("#static_progress_bar_container").modal(); - url = "/marker_regression"; - $('input[name=method]').val("gemma"); - $('input[name=maf]').val($('input[name=maf_gemma]').val()); - form_data = $('#trait_data_form').serialize(); - console.log("form_data is:", form_data); - return do_ajax_post(url, form_data); + + outlier_text = "One or more outliers exist in this data set. Please review values before mapping. Including outliers when mapping may lead to misleading results. We recommend <A HREF=\"http://en.wikipedia.org/wiki/Winsorising\">winsorising</A> the outliers or simply deleting them."; + + showalert = function(message, alerttype) { + return $('#alert_placeholder').append('<div id="alertdiv" class="alert ' + alerttype + '"><a class="close" data-dismiss="alert">�</a><span>' + message + '</span></div>'); }; -})(this)); - -$("#interval_mapping_compute").on("click", (function(_this) { - return function() { - var form_data, url; - showalert("One or more outliers exist in this data set. Please review values before mapping. Including outliers when mapping may lead to misleading results. We recommend <A HREF=\"http://en.wikipedia.org/wiki/Winsorising\">winsorising</A> the outliers or simply deleting them.", "alert-success"); - console.log("In interval mapping"); - $("#progress_bar_container").modal(); - url = "/interval_mapping"; - $('input[name=method]').val("reaper"); - $('input[name=manhattan_plot]').val($('input[name=manhattan_plot_reaper]:checked').val()); - $('input[name=mapping_display_all]').val($('input[name=display_all_reaper]')); - $('input[name=suggestive]').val($('input[name=suggestive_reaper]')); - form_data = $('#trait_data_form').serialize(); - console.log("form_data is:", form_data); - return do_ajax_post(url, form_data); + + $('#suggestive').hide(); + + $('input[name=display_all]').change((function(_this) { + return function() { + console.log("check"); + if ($('input[name=display_all]:checked').val() === "False") { + return $('#suggestive').show(); + } else { + return $('#suggestive').hide(); + } + }; + })(this)); + + $("#pylmm_mapping_compute").on("mouseover", (function(_this) { + return function() { + if ($(".outlier").length && $(".outlier-alert").length < 1) { + return showalert(outlier_text, "alert-success outlier-alert"); + } + }; + })(this)); + + $("#pylmm_compute").on("click", (function(_this) { + return function() { + var form_data, url; + $("#progress_bar_container").modal(); + url = "/marker_regression"; + $('input[name=method]').val("pylmm"); + $('input[name=num_perm]').val($('input[name=num_perm_pylmm]').val()); + $('input[name=manhattan_plot]').val($('input[name=manhattan_plot_pylmm]:checked').val()); + form_data = $('#trait_data_form').serialize(); + console.log("form_data is:", form_data); + return do_ajax_post(url, form_data); + }; + })(this)); + + $("#rqtl_geno_compute").on("click", (function(_this) { + return function() { + var form_data, url; + $("#progress_bar_container").modal(); + url = "/marker_regression"; + $('input[name=method]').val("rqtl_geno"); + $('input[name=num_perm]').val($('input[name=num_perm_rqtl_geno]').val()); + $('input[name=manhattan_plot]').val($('input[name=manhattan_plot_rqtl]:checked').val()); + $('input[name=control_marker]').val($('input[name=control_rqtl_geno]').val()); + form_data = $('#trait_data_form').serialize(); + console.log("form_data is:", form_data); + return do_ajax_post(url, form_data); + }; + })(this)); + + $("#plink_compute").on("click", (function(_this) { + return function() { + var form_data, url; + $("#static_progress_bar_container").modal(); + url = "/marker_regression"; + $('input[name=method]').val("plink"); + $('input[name=maf]').val($('input[name=maf_plink]').val()); + form_data = $('#trait_data_form').serialize(); + console.log("form_data is:", form_data); + return do_ajax_post(url, form_data); + }; + })(this)); + + $("#gemma_compute").on("click", (function(_this) { + return function() { + var form_data, url; + console.log("RUNNING GEMMA"); + $("#static_progress_bar_container").modal(); + url = "/marker_regression"; + $('input[name=method]').val("gemma"); + $('input[name=maf]').val($('input[name=maf_gemma]').val()); + form_data = $('#trait_data_form').serialize(); + console.log("form_data is:", form_data); + return do_ajax_post(url, form_data); + }; + })(this)); + + $("#interval_mapping_compute").on("mouseover", (function(_this) { + return function() { + if ($(".outlier").length && $(".outlier-alert").length < 1) { + return showalert(outlier_text, "alert-success outlier-alert"); + } + }; + })(this)); + + $("#interval_mapping_compute").on("click", (function(_this) { + return function() { + var form_data, url; + console.log("In interval mapping"); + $("#progress_bar_container").modal(); + url = "/interval_mapping"; + $('input[name=method]').val("reaper"); + $('input[name=manhattan_plot]').val($('input[name=manhattan_plot_reaper]:checked').val()); + $('input[name=mapping_display_all]').val($('input[name=display_all_reaper]')); + $('input[name=suggestive]').val($('input[name=suggestive_reaper]')); + form_data = $('#trait_data_form').serialize(); + console.log("form_data is:", form_data); + return do_ajax_post(url, form_data); + }; + })(this)); + + composite_mapping_fields = function() { + return $(".composite_fields").toggle(); }; -})(this)); -composite_mapping_fields = function() { - return $(".composite_fields").toggle(); -}; + mapping_method_fields = function() { + return $(".mapping_method_fields").toggle(); + }; -mapping_method_fields = function() { - return $(".mapping_method_fields").toggle(); -}; + $("#use_composite_choice").change(composite_mapping_fields); -$("#use_composite_choice").change(composite_mapping_fields); + $("#mapping_method_choice").change(mapping_method_fields); -$("#mapping_method_choice").change(mapping_method_fields); + toggle_enable_disable = function(elem) { + return $(elem).prop("disabled", !$(elem).prop("disabled")); + }; -toggle_enable_disable = function(elem) { - return $(elem).prop("disabled", !$(elem).prop("disabled")); -}; + $("#choose_closet_control").change(function() { + return toggle_enable_disable("#control_locus"); + }); -$("#choose_closet_control").change(function() { - return toggle_enable_disable("#control_locus"); -}); + $("#display_all_lrs").change(function() { + return toggle_enable_disable("#suggestive_lrs"); + }); -$("#display_all_lrs").change(function() { - return toggle_enable_disable("#suggestive_lrs"); -}); +}).call(this); diff --git a/wqflask/wqflask/static/new/packages/DataTables/css/jquery.dataTables.css b/wqflask/wqflask/static/new/packages/DataTables/css/jquery.dataTables.css index eec02ef5..c8303de2 100755 --- a/wqflask/wqflask/static/new/packages/DataTables/css/jquery.dataTables.css +++ b/wqflask/wqflask/static/new/packages/DataTables/css/jquery.dataTables.css @@ -65,7 +65,7 @@ table.dataTable tbody tr { background-color: #ffffff; } table.dataTable tbody tr.selected { - background-color: #B0BED9; + background-color: #ffff99; } table.dataTable tbody th, table.dataTable tbody td { diff --git a/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.colResize.js b/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.colResize.js index 6ef9907a..2712750a 100644 --- a/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.colResize.js +++ b/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.colResize.js @@ -1,943 +1,846 @@ -var dt; -(function (dt) { - var ColResize = (function () { - function ColResize($, api, settings) { - this.$ = $; - this.tableSize = -1; - this.initialized = false; - this.dt = {}; - this.dom = { - fixedLayout: false, - fixedHeader: null, - winResizeTimer: null, - mouse: { - startX: -1, - startWidth: null - }, - table: { - prevWidth: null - }, - origState: true, - resize: false, - scrollHead: null, - scrollHeadTable: null, - scrollFoot: null, - scrollFootTable: null, - scrollFootInner: null, - scrollBody: null, - scrollBodyTable: null, - scrollX: false, - scrollY: false - }; - this.settings = this.$.extend(true, {}, dt.ColResize.defaultSettings, settings); - this.dt.settings = api.settings()[0]; - this.dt.api = api; - this.dt.settings.colResize = this; - this.registerCallbacks(); - } - ColResize.prototype.initialize = function () { - var _this = this; - this.$.each(this.dt.settings.aoColumns, function (i, col) { - return _this.setupColumn(col); - }); - - //Initialize fixedHeader if specified - if (this.settings.fixedHeader) - this.setupFixedHeader(); - - //Save scroll head and body if found - this.dom.scrollHead = this.$('div.' + this.dt.settings.oClasses.sScrollHead, this.dt.settings.nTableWrapper); - this.dom.scrollHeadInner = this.$('div.' + this.dt.settings.oClasses.sScrollHeadInner, this.dom.scrollHead); - this.dom.scrollHeadTable = this.$('div.' + this.dt.settings.oClasses.sScrollHeadInner + ' > table', this.dom.scrollHead); - - this.dom.scrollFoot = this.$('div.' + this.dt.settings.oClasses.sScrollFoot, this.dt.settings.nTableWrapper); - this.dom.scrollFootInner = this.$('div.' + this.dt.settings.oClasses.sScrollFootInner, this.dom.scrollFoot); - this.dom.scrollFootTable = this.$('div.' + this.dt.settings.oClasses.sScrollFootInner + ' > table', this.dom.scrollFoot); - - this.dom.scrollBody = this.$('div.' + this.dt.settings.oClasses.sScrollBody, this.dt.settings.nTableWrapper); - this.dom.scrollBodyTable = this.$('> table', this.dom.scrollBody); - this.dt.api.on('draw.dt', this.onDraw.bind(this)); - if (this.dom.scrollFootTable) { - this.dt.api.on('colPinFcDraw.dt', function (e, colPin, data) { - if (data.leftClone.header) - _this.$('tfoot', data.leftClone.header).remove(); - if (data.leftClone.footer) - _this.$('thead', data.leftClone.footer).remove(); - if (data.rightClone.header) - _this.$('tfoot', data.rightClone.header).remove(); - if (data.rightClone.footer) - _this.$('thead', data.rightClone.footer).remove(); - }); - } - - this.dom.scrollX = this.dt.settings.oInit.sScrollX === undefined ? false : true; - this.dom.scrollY = this.dt.settings.oInit.sScrollY === undefined ? false : true; - - //SaveTableWidth - this.dt.settings.sTableWidthOrig = this.$(this.dt.settings.nTable).width(); - this.updateTableSize(); - - this.dt.settings.oFeatures.bAutoWidthOrig = this.dt.settings.oFeatures.bAutoWidth; - this.dt.settings.oFeatures.bAutoWidth = false; - - if (this.dt.settings.oInit.bStateSave && this.dt.settings.oLoadedState) { - this.loadState(this.dt.settings.oLoadedState); +/*! ColResize 0.0.10 + */ + +/** + * @summary ColResize + * @description Provide the ability to resize columns in a DataTable + * @version 0.0.10 + * @file dataTables.colResize.js + * @author Silvacom Ltd. + * + * For details please refer to: http://www.datatables.net + * + * Special thank to everyone who has contributed to this plug in + * - dykstrad + * - tdillan (for 0.0.3 and 0.0.5 bug fixes) + * - kylealonius (for 0.0.8 bug fix) + * - the86freak (for 0.0.9 bug fix) + */ + +(function (window, document, undefined) { + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * DataTables plug-in API functions test + * + * This are required by ColResize in order to perform the tasks required, and also keep this + * code portable, to be used for other column resize projects with DataTables, if needed. + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + var factory = function ($, DataTable) { + "use strict"; + + /** + * Plug-in for DataTables which will resize the columns depending on the handle clicked + * @method $.fn.dataTableExt.oApi.fnColResize + * @param object oSettings DataTables settings object - automatically added by DataTables! + * @param int iCol Take the column to be resized + * @returns void + */ + $.fn.dataTableExt.oApi.fnColResize = function (oSettings, iCol) { + var v110 = $.fn.dataTable.Api ? true : false; + + /* + * Update DataTables' event handlers + */ + + /* Fire an event so other plug-ins can update */ + $(oSettings.oInstance).trigger('column-resize', [ oSettings, { + "iCol": iCol + } ]); + }; + + /** + * ColResize provides column resize control for DataTables + * @class ColResize + * @constructor + * @param {object} dt DataTables settings object + * @param {object} opts ColResize options + */ + var ColResize = function (dt, opts) { + var oDTSettings; + + if ($.fn.dataTable.Api) { + oDTSettings = new $.fn.dataTable.Api(dt).settings()[0]; + } + // 1.9 compatibility + else if (dt.fnSettings) { + // DataTables object, convert to the settings object + oDTSettings = dt.fnSettings(); + } + else if (typeof dt === 'string') { + // jQuery selector + if ($.fn.dataTable.fnIsDataTable($(dt)[0])) { + oDTSettings = $(dt).eq(0).dataTable().fnSettings(); + } } - - this.onDraw(); - this.dom.table.preWidth = parseFloat(this.dom.scrollBodyTable.css('width')); - - if (!this.dom.scrollX && this.dom.scrollY && this.settings.fixedLayout && this.dt.settings._reszEvt) { - //We have to manually resize columns on window resize - var eventName = 'resize.DT-' + this.dt.settings.sInstance; - this.$(window).off(eventName); - this.$(window).on(eventName, function () { - _this.proportionallyColumnSizing(); - //api._fnAdjustColumnSizing(this.dt.settings); - }); + else if (dt.nodeName && dt.nodeName.toLowerCase() === 'table') { + // Table node + if ($.fn.dataTable.fnIsDataTable(dt.nodeName)) { + oDTSettings = $(dt.nodeName).dataTable().fnSettings(); + } } - - if (this.dom.scrollX || this.dom.scrollY) { - this.dt.api.on('column-sizing.dt', this.fixFootAndHeadTables.bind(this)); - this.dt.api.on('column-visibility.dt', this.fixFootAndHeadTables.bind(this)); + else if (dt instanceof jQuery) { + // jQuery object + if ($.fn.dataTable.fnIsDataTable(dt[0])) { + oDTSettings = dt.eq(0).dataTable().fnSettings(); + } } + else { + // DataTables settings object + oDTSettings = dt; + } + + // Convert from camelCase to Hungarian, just as DataTables does + if ($.fn.dataTable.camelToHungarian) { + $.fn.dataTable.camelToHungarian(ColResize.defaults, opts || {}); + } + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Public class variables + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + /** + * @namespace Settings object which contains customizable information for ColResize instance + */ + this.s = { + /** + * DataTables settings object + * @property dt + * @type Object + * @default null + */ + "dt": null, + + /** + * Initialisation object used for this instance + * @property init + * @type object + * @default {} + */ + "init": $.extend(true, {}, ColResize.defaults, opts), + + /** + * @namespace Information used for the mouse drag + */ + "mouse": { + "startX": -1, + "startY": -1, + "targetIndex": -1, + "targetColumn": -1, + "neighbourIndex": -1, + "neighbourColumn": -1 + }, - this.initialized = true; - this.dt.settings.oApi._fnCallbackFire(this.dt.settings, 'colResizeInitCompleted', 'colResizeInitCompleted', [this]); - }; - - ColResize.prototype.setupColumn = function (col) { - var _this = this; - var $th = this.$(col.nTh); - if (col.resizable === false) - return; - - // listen to mousemove event for resize - $th.on('mousemove.ColResize', function (e) { - if (_this.dom.resize || col.resizable === false) - return; - - /* Store information about the mouse position */ - var $thTarget = e.target.nodeName.toUpperCase() == 'TH' ? _this.$(e.target) : _this.$(e.target).closest('TH'); - var offset = $thTarget.offset(); - var nLength = $thTarget.innerWidth(); - - /* are we on the col border (if so, resize col) */ - if (Math.abs(e.pageX - Math.round(offset.left + nLength)) <= 5) { - $thTarget.css({ 'cursor': 'col-resize' }); - } else - $thTarget.css({ 'cursor': 'pointer' }); - }); - - //Save the original width - col._ColResize_sWidthOrig = col.sWidthOrig; - col.initWidth = $th.width(); - col.minWidthOrig = col.minWidth; - - $th.on('dblclick.ColResize', function (e) { - _this.onDblClick(e, $th, col); - }); - - $th.off('mousedown.ColReorder'); - - // listen to mousedown event - $th.on('mousedown.ColResize', function (e) { - return _this.onMouseDown(e, col); - }); - }; - - ColResize.prototype.setupFixedHeader = function () { - var fhSettings = this.settings.fixedHeader === true ? undefined : this.settings.fixedHeader; - - //If left or right option was set to true disable resizing for the first or last column - if (this.$.isPlainObject(fhSettings)) { - var columns = this.dt.settings.aoColumns; - if (fhSettings.left === true) - columns[0].resizable = false; - if (fhSettings.right === true) - columns[columns.length - 1].resizable = false; - } + /** + * Status variable keeping track of mouse down status + * @property isMousedown + * @type boolean + * @default false + */ + "isMousedown": false + }; - this.dom.fixedHeader = new this.$.fn.dataTable.FixedHeader(this.dt.api, fhSettings); - var origUpdateClones = this.dom.fixedHeader._fnUpdateClones; - var that = this; - //FixeHeader doesn't have any callback after updating the clones so we have to wrap the orig function - this.dom.fixedHeader._fnUpdateClones = function () { - origUpdateClones.apply(this, arguments); - that.memorizeFixedHeaderNodes(); + /** + * @namespace Common and useful DOM elements for the class instance + */ + this.dom = { + /** + * Resizing element (the one the mouse is resizing) + * @property resize + * @type element + * @default null + */ + "resizeCol": null, + + /** + * Resizing element neighbour (the column next to the one the mouse is resizing) + * This is for fixed table resizing. + * @property resize + * @type element + * @default null + */ + "resizeColNeighbour": null, + + /** + * Array of events to be restored, used for overriding existing events from other plugins for a time. + * @property restoreEvents + * @type array + * @default [] + */ + "restoreEvents": [] }; - //As we missed the first call of _fnUpdateClones we have to call memorizeFixedHeaderNodes function manually - this.memorizeFixedHeaderNodes(); - }; - ColResize.prototype.memorizeFixedHeaderNodes = function () { - var _this = this; - var fhSettings = this.dom.fixedHeader.fnGetSettings(); - var fhCache = fhSettings.aoCache; - var i, col; - for (i = 0; i < fhCache.length; i++) { - var type = fhCache[i].sType; - var propName; - var selector; - switch (type) { - case 'fixedHeader': - propName = 'fhTh'; - selector = 'thead>tr>th'; - this.dt.settings.fhTHead = fhCache[i].nNode; - break; - case 'fixedFooter': - propName = 'fhTf'; - selector = 'thead>tr>th'; - - //prepend a cloned thead to the floating footer table so that resizing will work correctly - var tfoot = this.$(fhCache[i].nNode); - var thead = this.$(this.dt.settings.nTHead).clone().css({ height: 0, visibility: 'hidden' }); - this.$('tr', thead).css('height', 0); - this.$('tr>th', thead).css({ - 'height': 0, - 'padding-bottom': 0, - 'padding-top': 0, - 'border-bottom-width': 0, - 'border-top-width': 0, - 'line-height': 0 - }); - tfoot.prepend(thead); - this.$('tfoot>tr>th', tfoot).css('width', ''); - this.dt.settings.fhTFoot = fhCache[i].nNode; - break; - default: - continue; + /* Constructor logic */ + this.s.dt = oDTSettings.oInstance.fnSettings(); + this.s.dt._colResize = this; + this._fnConstruct(); + + /* Add destroy callback */ + oDTSettings.oApi._fnCallbackReg(oDTSettings, 'aoDestroyCallback', $.proxy(this._fnDestroy, this), 'ColResize'); + + return this; + }; + + + ColResize.prototype = { + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Public methods + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + /** + * Reset the column widths to the original widths that was detected on + * start up. + * @return {this} Returns `this` for chaining. + * + * @example + * // DataTables initialisation with ColResize + * var table = $('#example').dataTable( { + * "sDom": 'Zlfrtip' + * } ); + * + * // Add click event to a button to reset the ordering + * $('#resetOrdering').click( function (e) { + * e.preventDefault(); + * $.fn.dataTable.ColResize( table ).fnReset(); + * } ); + */ + "fnReset": function () { + var a = []; + for (var i = 0, iLen = this.s.dt.aoColumns.length; i < iLen; i++) { + this.s.dt.aoColumns[i].width = this.s.dt.aoColumns[i]._ColResize_iOrigWidth; } - this.$(selector, fhCache[i].nNode).each(function (j, th) { - col = _this.getVisibleColumn(j); - col[propName] = th; - }); - } - }; + this.s.dt.adjust().draw(); - //zero based index - ColResize.prototype.getVisibleColumn = function (idx) { - var columns = this.dt.settings.aoColumns; - var currVisColIdx = -1; - for (var i = 0; i < columns.length; i++) { - if (!columns[i].bVisible) - continue; - currVisColIdx++; - if (currVisColIdx == idx) - return columns[i]; - } - return null; - }; - - ColResize.prototype.updateTableSize = function () { - if (this.dom.scrollX && this.dom.scrollHeadTable.length) - this.tableSize = this.dom.scrollHeadTable.width(); - else - this.tableSize = -1; - }; + return this; + }, - ColResize.prototype.proportionallyColumnSizing = function () { - var _this = this; - var prevWidths = [], newWidths = [], prevWidth, newWidth, newTableWidth, prevTableWidth, moveLength, multiplier, cWidth, i, j, delay = 500, prevTotalColWidths = 0, currTotalColWidths, columnRestWidths = [], columns = this.dt.settings.aoColumns, bodyTableColumns = this.$('thead th', this.dom.scrollBodyTable), headTableColumns = this.$('thead th', this.dom.scrollHeadTable), footTableColumns = this.dom.scrollFootTable.length ? this.$('thead th', this.dom.scrollFootTable) : [], visColumns = []; - for (i = 0; i < columns.length; i++) { - if (!columns[i].bVisible) - continue; - visColumns.push(columns[i]); - columnRestWidths.push(0); //set default value - } + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Private methods (they are of course public in JS, but recommended as private) + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - for (i = 0; i < bodyTableColumns.length; i++) { - cWidth = parseFloat(bodyTableColumns[i].style.width); - prevTotalColWidths += cWidth; - prevWidths.push(cWidth); - } - - for (i = 0; i < bodyTableColumns.length; i++) { - bodyTableColumns[i].style.width = ''; - } + /** + * Constructor logic + * @method _fnConstruct + * @returns void + * @private + */ + "_fnConstruct": function () { + var that = this; + var iLen = that.s.dt.aoColumns.length; + var i; - //Get the new table width calculated by the browser - newTableWidth = parseFloat(this.dom.scrollBodyTable.css('width')); + that._fnSetupMouseListeners(); - //Get the old table width - prevTableWidth = this.dom.table.preWidth; - moveLength = newTableWidth - prevTableWidth; - if (moveLength == 0) { - for (i = 0; i < bodyTableColumns.length; i++) { - bodyTableColumns[i].style.width = prevWidths[i] + 'px'; + /* Add event handlers for the resize handles */ + for (i = 0; i < iLen; i++) { + /* Mark the original column width for later reference */ + this.s.dt.aoColumns[i]._ColResize_iOrigWidth = this.s.dt.aoColumns[i].width; } - return; - } - //var tot = 0; - currTotalColWidths = prevTotalColWidths; - for (i = 0; i < visColumns.length; i++) { - //For each column calculate the new width - prevWidth = prevWidths[i]; - multiplier = (+(prevWidth / prevTotalColWidths).toFixed(2)); - - //tot += multiplier; - newWidth = prevWidth + (moveLength * multiplier) + columnRestWidths[i]; - currTotalColWidths -= prevWidth; - - //Check whether the column can be resized to the new calculated value - //if not, set it to the min or max width depends on the moveLength value - if (!this.canResizeColumn(visColumns[i], newWidth)) { - cWidth = moveLength > 0 ? this.getColumnMaxWidth(visColumns[i]) : this.getColumnMinWidth(visColumns[i]); - var rest = newWidth - cWidth; - newWidth = cWidth; - - for (j = (i + 1); j < visColumns.length; j++) { - columnRestWidths[j] += rest * (+(visColumns[j] / currTotalColWidths).toFixed(2)); + this._fnSetColumnIndexes(); + + /* State saving */ + this.s.dt.oApi._fnCallbackReg( this.s.dt, 'aoStateSaveParams', function (oS, oData) { + that._fnStateSave.call(that, oData); + }, "ColResize_State" ); + + // State loading + this._fnStateLoad(); + }, + + /** + * @method _fnStateSave + * @param object oState DataTables state + * @private + */ + "_fnStateSave": function (oState) { + this.s.dt.aoColumns.forEach(function(col, index) { + oState.columns[index].width = col.sWidthOrig; + }); + }, + + /** + * If state has been loaded, apply the saved widths to the columns + * @method _fnStateLoad + * @private + */ + "_fnStateLoad": function() { + var that = this, + loadedState = this.s.dt.oLoadedState; + if (loadedState && loadedState.columns) { + var colStates = loadedState.columns, + currCols = this.s.dt.aoColumns; + // Only apply the saved widths if the number of columns is the same. + // Otherwise, we don't know if we're applying the width to the correct column. + if (colStates.length > 0 && colStates.length === currCols.length) { + colStates.forEach(function(state, index) { + var col = that.s.dt.aoColumns[index]; + if (state.width) { + col.sWidthOrig = col.sWidth = state.width; + } + }); } } - newWidths.push(newWidth); - } - - //Apply the calculated column widths to the headers cells - var tablesWidth = this.dom.scrollBodyTable.outerWidth() + 'px'; - for (i = 0; i < headTableColumns.length; i++) { - headTableColumns[i].style.width = newWidths[i] + 'px'; - } - this.dom.scrollHeadTable.css('width', tablesWidth); - this.dom.scrollHeadInner.css('width', tablesWidth); - - for (i = 0; i < bodyTableColumns.length; i++) { - bodyTableColumns[i].style.width = newWidths[i] + 'px'; - } - - if (this.dom.scrollFootTable.length) { - for (i = 0; i < footTableColumns.length; i++) { - footTableColumns[i].style.width = newWidths[i] + 'px'; + }, + + /** + * Remove events of type from obj add it to restoreEvents array to be restored at a later time + * @param until string flag when to restore the event + * @param obj Object to remove events from + * @param type type of event to remove + * @param namespace namespace of the event being removed + */ + "_fnDelayEvents": function (until, obj, type, namespace) { + var that = this; + //Get the events for the object + var events = $._data($(obj).get(0), 'events'); + $.each(events, function (i, o) { + //If the event type matches + if (i == type) { + //Loop through the possible many events with that type + $.each(o, function (k, v) { + //Somehow it is possible for the event to be undefined make sure it is defined first + if (v) { + if (namespace) { + //Add the event to the array of events to be restored later + that.dom.restoreEvents.push({"until": until, "obj": obj, "type": v.type, "namespace": v.namespace, "handler": v.handler}); + //If the namespace matches + if (v.namespace == namespace) { + //Turn off/unbind the event + $(obj).off(type + "." + namespace); + } + } else { + //Add the event to the array of events to be restored later + that.dom.restoreEvents.push({"until": until, "obj": obj, "type": v.type, "namespace": null, "handler": v.handler}); + //Turn off/unbind the event + $(obj).off(type); + } + } + }); + } + }); + }, + + /** + * Loop through restoreEvents array and restore the events on the elements provided + */ + "_fnRestoreEvents": function (until) { + var that = this; + //Loop through the events to be restored + var i; + for (i = that.dom.restoreEvents.length; i--;) { + if (that.dom.restoreEvents[i].until == undefined || that.dom.restoreEvents[i].until == null || that.dom.restoreEvents[i].until == until) { + if (that.dom.restoreEvents[i].namespace) { + //Turn on the event for the object provided + $(that.dom.restoreEvents[i].obj).off(that.dom.restoreEvents[i].type + "." + that.dom.restoreEvents[i].namespace).on(that.dom.restoreEvents[i].type + "." + that.dom.restoreEvents[i].namespace, that.dom.restoreEvents[i].handler); + that.dom.restoreEvents.splice(i, 1); + } else { + //Turn on the event for the object provided + $(that.dom.restoreEvents[i].obj).off(that.dom.restoreEvents[i].type).on(that.dom.restoreEvents[i].type, that.dom.restoreEvents[i].handler); + that.dom.restoreEvents.splice(i, 1); + } + } } - this.dom.scrollFootTable[0].style.width = tablesWidth; - this.dom.scrollFootInner[0].style.width = tablesWidth; - } + }, - //console.log('moveLength: ' + moveLength + ' multiplier: ' + tot); - //console.log(newWidths); - this.dom.table.preWidth = newTableWidth; - - //Call afterResizing function after the window stops resizing - if (this.dom.winResizeTimer) - clearTimeout(this.dom.winResizeTimer); - this.dom.winResizeTimer = setTimeout(function () { - _this.afterResizing(); - _this.dom.winResizeTimer = null; - }, delay); - }; + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mouse drop and drag + */ - ColResize.prototype.getColumnIndex = function (col) { - //Get the current column position - var colIdx = -1; - for (var i = 0; i < this.dt.settings.aoColumns.length; i++) { - if (this.dt.settings.aoColumns[i] === col) { - colIdx = i; - break; + "_fnSetupMouseListeners":function() { + var that = this; + $(that.s.dt.nTableWrapper).off("mouseenter.ColResize").on("mouseenter.ColResize","th",function(e) { + e.preventDefault(); + that._fnMouseEnter.call(that, e, this); + }); + $(that.s.dt.nTableWrapper).off("mouseleave.ColResize").on("mouseleave.ColResize","th",function(e) { + e.preventDefault(); + that._fnMouseLeave.call(that, e, this); + }); + }, + + /** + * Add mouse listeners to the resize handle on TH element + * @method _fnMouseListener + * @param i Column index + * @param nTh TH resize handle element clicked on + * @returns void + * @private + */ + "_fnMouseListener": function (i, nTh) { + var that = this; + $(nTh).off('mouseenter.ColResize').on('mouseenter.ColResize', function (e) { + e.preventDefault(); + that._fnMouseEnter.call(that, e, nTh); + }); + $(nTh).off('mouseleave.ColResize').on('mouseleave.ColResize', function (e) { + e.preventDefault(); + that._fnMouseLeave.call(that, e, nTh); + }); + }, + + /** + * + * @param e Mouse event + * @param nTh TH element that the mouse is over + */ + "_fnMouseEnter": function (e, nTh) { + var that = this; + if(!that.s.isMousedown) { + //Once the mouse has entered the cell add mouse move event to see if the mouse is over resize handle + $(nTh).off('mousemove.ColResizeHandle').on('mousemove.ColResizeHandle', function (e) { + e.preventDefault(); + that._fnResizeHandleCheck.call(that, e, nTh); + }); } - } - return colIdx; - }; + }, + + /** + * Clear mouse events when the mouse has left the th + * @param e Mouse event + * @param nTh TH element that the mouse has just left + */ + "_fnMouseLeave": function (e, nTh) { + //Once the mouse has left the TH make suure to remove the mouse move listener + $(nTh).off('mousemove.ColResizeHandle'); + }, + + /** + * Mouse down on a TH element in the table header + * @method _fnMouseDown + * @param event e Mouse event + * @param element nTh TH element to be resized + * @returns void + * @private + */ + "_fnMouseDown": function (e, nTh) { + var that = this; + + that.s.isMousedown = true; - ColResize.prototype.getColumnEvent = function (th, type, ns) { - var event; - var thEvents = this.$._data(th, "events"); - this.$.each(thEvents[type] || [], function (idx, handler) { - if (handler.namespace === ns) - event = handler; - }); - return event; - }; - - ColResize.prototype.loadState = function (data) { - var _this = this; - var i, col; - - var onInit = function () { - if (_this.settings.fixedLayout) { - _this.setTablesLayout('fixed'); + /* Store information about the mouse position */ + var target = $(e.target).closest('th, td'); + var offset = target.offset(); + + /* Store information about the mouse position for resize calculations in mouse move function */ + this.s.mouse.startX = e.pageX; + this.s.mouse.startY = e.pageY; + + //Store the indexes of the columns the mouse is down on + var idx = that.dom.resizeCol[0].cellIndex; + + // the last column has no 'right-side' neighbour + // with fixed this can make the table smaller + if (that.dom.resizeColNeighbour[0] === undefined){ + var idxNeighbour = 0; } else { - _this.setTablesLayout('auto'); + var idxNeighbour = that.dom.resizeColNeighbour[0].cellIndex; } - if (!data.colResize) { - if (_this.dt.settings.oFeatures.bAutoWidthOrig) - _this.dt.settings.oFeatures.bAutoWidth = true; - else if (_this.dt.settings.sTableWidthOrig) - _this.$(_this.dt.settings.nTable).width(_this.dt.settings.sTableWidthOrig); - - for (i = 0; i < _this.dt.settings.aoColumns.length; i++) { - col = _this.dt.settings.aoColumns[i]; - if (col._ColResize_sWidthOrig) { - col.sWidthOrig = col._ColResize_sWidthOrig; - } - } - _this.dom.origState = true; - } else { - var columns = data.colResize.columns || []; - var wMap = {}; + + - if (_this.dt.settings.oFeatures.bAutoWidth) { - _this.dt.settings.oFeatures.bAutoWidth = false; - } + if (idx === undefined) { + return; + } - if (_this.dom.scrollX && data.colResize.tableSize > 0) { - _this.dom.scrollHeadTable.width(data.colResize.tableSize); - _this.dom.scrollHeadInner.width(data.colResize.tableSize); - _this.dom.scrollBodyTable.width(data.colResize.tableSize); - _this.dom.scrollFootTable.width(data.colResize.tableSize); + this.s.mouse.targetIndex = idx; + this.s.mouse.targetColumn = this.s.dt.aoColumns[ idx ]; + + this.s.mouse.neighbourIndex = idxNeighbour; + this.s.mouse.neighbourColumn = this.s.dt.aoColumns[ idxNeighbour ]; + + /* Add event handlers to the document */ + $(document) + .off('mousemove.ColResize').on('mousemove.ColResize', function (e) { + that._fnMouseMove.call(that, e); + }) + .off('mouseup.ColResize').on('mouseup.ColResize', function (e) { + that._fnMouseUp.call(that, e); + }); + }, + + /** + * Deal with a mouse move event while dragging to resize a column + * @method _fnMouseMove + * @param e Mouse event + * @returns void + * @private + */ + "_fnMouseMove": function (e) { + var that = this; + + var offset = $(that.s.mouse.targetColumn.nTh).offset(); + var relativeX = (e.pageX - offset.left); + var distFromLeft = relativeX; + var distFromRight = $(that.s.mouse.targetColumn.nTh).outerWidth() - relativeX - 1; + + //Change in mouse x position + var dx = e.pageX - that.s.mouse.startX; + //Get the minimum width of the column (default minimum 10px) + var minColumnWidth = Math.max(parseInt($(that.s.mouse.targetColumn.nTh).css('min-width')), 10); + //Store the previous width of the column + var prevWidth = $(that.s.mouse.targetColumn.nTh).width(); + //As long as the cursor is past the handle, resize the columns + if ((dx > 0 && distFromRight <= 0) || (dx < 0 && distFromRight >= 0)) { + if (!that.s.init.tableWidthFixed) { + //As long as the width is larger than the minimum + var newColWidth = Math.max(minColumnWidth, prevWidth + dx); + //Get the width difference (take into account the columns minimum width) + var widthDiff = newColWidth - prevWidth; + var colResizeIdx = parseInt(that.dom.resizeCol.attr("data-column-index")); + //Set datatable column widths + that.s.mouse.targetColumn.sWidthOrig = that.s.mouse.targetColumn.sWidth = that.s.mouse.targetColumn.width = newColWidth + "px"; + var domCols = $(that.s.dt.nTableWrapper).find("th[data-column-index='"+colResizeIdx+"']"); + //For each table expand the width by the same amount as the column + //This accounts for other datatable plugins like FixedColumns + domCols.parents("table").each(function() { + if(!$(this).parent().hasClass("DTFC_LeftBodyLiner")) { + var newWidth = $(this).width() + widthDiff; + $(this).width(newWidth); + } else { + var newWidth =$(that.s.dt.nTableWrapper).find(".DTFC_LeftHeadWrapper").children("table").width(); + $(this).parents(".DTFC_LeftWrapper").width(newWidth); + $(this).parent().width(newWidth+15); + $(this).width(newWidth); + } + }); + //Apply the new width to the columns after the table has been resized + domCols.width(that.s.mouse.targetColumn.width); + } else { + //A neighbour column must exist in order to resize a column in a table with a fixed width + if (that.s.mouse.neighbourColumn) { + //Get the minimum width of the neighbor column (default minimum 10px) + var minColumnNeighbourWidth = Math.max(parseInt($(that.s.mouse.neighbourColumn.nTh).css('min-width')), 10); + //Store the previous width of the neighbour column + var prevNeighbourWidth = $(that.s.mouse.neighbourColumn.nTh).width(); + //As long as the width is larger than the minimum + var newColWidth = Math.max(minColumnWidth, prevWidth + dx); + var newColNeighbourWidth = Math.max(minColumnNeighbourWidth, prevNeighbourWidth - dx); + //Get the width difference (take into account the columns minimum width) + var widthDiff = newColWidth - prevWidth; + var widthDiffNeighbour = newColNeighbourWidth - prevNeighbourWidth; + //Get the column index for the column being changed + var colResizeIdx = parseInt(that.dom.resizeCol.attr("data-column-index")); + var neighbourColResizeIdx = parseInt(that.dom.resizeColNeighbour.attr("data-column-index")); + //Set datatable column widths + that.s.mouse.neighbourColumn.sWidthOrig = that.s.mouse.neighbourColumn.sWidth = that.s.mouse.neighbourColumn.width = newColNeighbourWidth + "px"; + that.s.mouse.targetColumn.sWidthOrig = that.s.mouse.targetColumn.sWidth = that.s.mouse.targetColumn.width = newColWidth + "px"; + //Get list of columns based on column index in all affected tables tables. This accounts for other plugins like FixedColumns + var domNeighbourCols = $(that.s.dt.nTableWrapper).find("th[data-column-index='" + neighbourColResizeIdx + "']"); + var domCols = $(that.s.dt.nTableWrapper).find("th[data-column-index='" + colResizeIdx + "']"); + //If dx if positive (the width is getting larger) shrink the neighbour columns first + if(dx>0) { + domNeighbourCols.width(that.s.mouse.neighbourColumn.width); + domCols.width(that.s.mouse.targetColumn.width); + } else { + //Apply the new width to the columns then to the neighbour columns + domCols.width(that.s.mouse.targetColumn.width); + domNeighbourCols.width(that.s.mouse.neighbourColumn.width); + } + } } + } + that.s.mouse.startX = e.pageX; + }, + + /** + * Check to see if the mouse is over the resize handle area + * @param e + * @param nTh + */ + "_fnResizeHandleCheck": function (e, nTh) { + var that = this; + + var offset = $(nTh).offset(); + var relativeX = (e.pageX - offset.left); + var relativeY = (e.pageY - offset.top); + var distFromLeft = relativeX; + var distFromRight = $(nTh).outerWidth() - relativeX - 1; + + var handleBuffer = this.s.init.handleWidth / 2; + var leftHandleOn = distFromLeft < handleBuffer; + var rightHandleOn = distFromRight < handleBuffer; + + //If this is the first table cell + if ($(nTh).prev("th").length == 0) { + if(this.s.init.rtl) + rightHandleOn = false; + else + leftHandleOn = false; + } + //If this is the last cell and the table is fixed width don't let them expand the last cell directly + if ($(nTh).next("th").length == 0 && this.s.init.tableWidthFixed) { + if(this.s.init.rtl) + leftHandleOn = false; + else + rightHandleOn = false; + } - for (i = 0; i < columns.length; i++) { - wMap[i] = columns[i]; + var resizeAvailable = leftHandleOn||rightHandleOn; + + //If table is in right to left mode flip which TH is being resized + if (that.s.init.rtl) { + //Handle is to the left + if (leftHandleOn) { + that.dom.resizeCol = $(nTh); + that.dom.resizeColNeighbour = $(nTh).next(); + } else if (rightHandleOn) { + that.dom.resizeCol = $(nTh).prev(); + that.dom.resizeColNeighbour = $(nTh); } - for (i = 0; i < _this.dt.settings.aoColumns.length; i++) { - col = _this.dt.settings.aoColumns[i]; - var idx = col._ColReorder_iOrigCol != null ? col._ColReorder_iOrigCol : i; - col.sWidth = wMap[idx]; - col.sWidthOrig = wMap[idx]; - col.nTh.style.width = columns[i]; - - //Check for FixedHeader - if (col.fhTh) - col.fhTh.style.width = columns[i]; - if (col.fhTf) - col.fhTf.style.width = columns[i]; + } else { + //Handle is to the right + if (rightHandleOn) { + that.dom.resizeCol = $(nTh); + that.dom.resizeColNeighbour = $(nTh).next(); + } else if (leftHandleOn) { + that.dom.resizeCol = $(nTh).prev(); + that.dom.resizeColNeighbour = $(nTh); } - _this.dom.origState = false; } - _this.dt.api.columns.adjust(); - if (_this.dom.scrollX || _this.dom.scrollY) - _this.dt.api.draw(false); - }; - - if (this.initialized) { - onInit(); - return; - } - this.dt.settings.oApi._fnCallbackReg(this.dt.settings, 'colResizeInitCompleted', function () { - onInit(); - }, "ColResize_Init"); - }; - - ColResize.prototype.saveState = function (data) { - if (!this.dt.settings._bInitComplete) { - var oData = this.dt.settings.fnStateLoadCallback.call(this.dt.settings.oInstance, this.dt.settings); - if (oData && oData.colResize) - data.colResize = oData.colResize; - return; - } - this.updateTableSize(); - data.colResize = { - columns: [], - tableSize: this.tableSize - }; - - data.colResize.columns.length = this.dt.settings.aoColumns.length; - for (var i = 0; i < this.dt.settings.aoColumns.length; i++) { - var col = this.dt.settings.aoColumns[i]; - var idx = col._ColReorder_iOrigCol != null ? col._ColReorder_iOrigCol : i; - data.colResize.columns[idx] = col.sWidth; - } - }; - - ColResize.prototype.registerCallbacks = function () { - var _this = this; - /* State saving */ - this.dt.settings.oApi._fnCallbackReg(this.dt.settings, 'aoStateSaveParams', function (oS, oData) { - _this.saveState(oData); - }, "ColResize_StateSave"); - - /* State loading */ - this.dt.settings.oApi._fnCallbackReg(this.dt.settings, 'aoStateLoaded', function (oS, oData) { - _this.loadState(oData); - }, "ColResize_StateLoad"); - - if (this.$.fn.DataTable.models.oSettings.remoteStateInitCompleted !== undefined) { - //Integrate with remote state - this.dt.settings.oApi._fnCallbackReg(this.dt.settings, 'remoteStateLoadedParams', function (s, data) { - _this.loadState(data); - }, "ColResize_StateLoad"); - this.dt.settings.oApi._fnCallbackReg(this.dt.settings, 'remoteStateSaveParams', function (s, data) { - _this.saveState(data); - }, "ColResize_StateSave"); - } - }; - - ColResize.prototype.setTablesLayout = function (value) { - if (this.dom.scrollX || this.dom.scrollY) { - this.dom.scrollHeadTable.css('table-layout', value); - this.dom.scrollBodyTable.css('table-layout', value); - this.dom.scrollFootTable.css('table-layout', value); - } else { - this.$(this.dt.settings.nTable).css('table-layout', value); - } - this.dom.fixedLayout = value == 'fixed'; - }; - - //only when scrollX or scrollY are enabled - ColResize.prototype.fixFootAndHeadTables = function (e) { - var _this = this; - if (e != null && e.target !== this.dt.settings.nTable) - return; - - if (this.dom.scrollFootTable.length) { - this.$('thead', this.dom.scrollFootTable).remove(); - this.dom.scrollFootTable.prepend(this.$('thead', this.dom.scrollBodyTable).clone()); - } - this.$('tfoot', this.dom.scrollHeadTable).remove(); - this.dom.scrollHeadTable.append(this.$('tfoot', this.dom.scrollBodyTable).clone()); - var removeFooterWidth = function (table) { - _this.$('tfoot>tr>th', table).each(function (i, th) { - _this.$(th).css('width', ''); - }); - }; - - //Remove all tfoot headers widths - removeFooterWidth(this.dom.scrollFootTable); - removeFooterWidth(this.dom.scrollBodyTable); - removeFooterWidth(this.dom.scrollHeadTable); - }; - - ColResize.prototype.onDraw = function (e) { - if (e != null && e.target !== this.dt.settings.nTable) - return; - if (this.dom.scrollX || this.dom.scrollY) { - this.fixFootAndHeadTables(); - - //Fix the header table padding - if (this.dt.settings._bInitComplete) { - var borderWidth = this.dom.scrollHeadTable.outerWidth() - this.dom.scrollHeadTable.innerWidth(); - var paddingType = this.dt.settings.oBrowser.bScrollbarLeft ? 'padding-left' : 'padding-right'; - var paddingVal = parseFloat(this.dom.scrollHeadInner.css(paddingType)); - this.dom.scrollHeadInner.css(paddingType, (paddingVal + borderWidth) + 'px'); - } - } - - var autoWidthTypes = []; - if (this.settings.dblClick == 'autoMinFit' || !this.settings.fixedLayout) - autoWidthTypes.push('autoMinWidth'); - if (this.settings.dblClick == 'autoFit') - autoWidthTypes.push('autoWidth'); - - //Call this only once so that the table will be cloned only one time - if (autoWidthTypes.length) - this.updateColumnsAutoWidth(autoWidthTypes); - - if (!this.settings.fixedLayout) { - var columns = this.dt.settings.aoColumns; - var i; - for (i = 0; i < columns.length; i++) { - if (!columns[i].bVisible) - continue; - columns[i].minWidth = Math.max((columns[i].minWidthOrig || 0), columns[i].autoMinWidth); - - //We have to resize if the current column width if is less that the column minWidth - if (this.$(columns[i].nTh).width() < columns[i].minWidth) - this.resize(columns[i], columns[i].minWidth); + //If table width is fixed make sure both columns are resizable else just check the one. + if(this.s.init.tableWidthFixed) + resizeAvailable &= this.s.init.exclude.indexOf(parseInt($(that.dom.resizeCol).attr("data-column-index"))) == -1 && this.s.init.exclude.indexOf(parseInt($(that.dom.resizeColNeighbour).attr("data-column-index"))) == -1; + else + resizeAvailable &= this.s.init.exclude.indexOf(parseInt($(that.dom.resizeCol).attr("data-column-index"))) == -1; + + $(nTh).off('mousedown.ColResize'); + if (resizeAvailable) { + $(nTh).css("cursor", "ew-resize"); + + //Delay other mousedown events from the Reorder plugin + that._fnDelayEvents(null, nTh, "mousedown", "ColReorder"); + that._fnDelayEvents("click", nTh, "click", "DT"); + + $(nTh).off('mousedown.ColResize').on('mousedown.ColResize', function (e) { + e.preventDefault(); + that._fnMouseDown.call(that, e, nTh); + }) + .off('click.ColResize').on('click.ColResize', function (e) { + that._fnClick.call(that, e); + }); + } else { + $(nTh).css("cursor", "pointer"); + $(nTh).off('mousedown.ColResize click.ColResize'); + //Restore any events that were removed + that._fnRestoreEvents(); + //This is to restore column sorting on click functionality + if (!that.s.isMousedown) + //Restore click event if mouse is not down + this._fnRestoreEvents("click"); } - } else { - if (!this.dom.fixedLayout) { - this.setTablesLayout('fixed'); - this.afterResizing(); + }, + + "_fnClick": function (e) { + var that = this; + that.s.isMousedown = false; + e.stopImmediatePropagation(); + }, + + /** + * Finish off the mouse drag + * @method _fnMouseUp + * @param e Mouse event + * @returns void + * @private + */ + "_fnMouseUp": function (e) { + var that = this; + that.s.isMousedown = false; + + //Fix width of column to be the size the dom is limited to (for when user sets min-width on a column) + that.s.mouse.targetColumn.width = that.dom.resizeCol.width(); + + $(document).off('mousemove.ColResize mouseup.ColResize'); + this.s.dt.oInstance.fnAdjustColumnSizing(); + //Table width fix, prevents extra gaps between tables + var LeftWrapper = $(that.s.dt.nTableWrapper).find(".DTFC_LeftWrapper"); + var DTFC_LeftWidth = LeftWrapper.width(); + LeftWrapper.children(".DTFC_LeftHeadWrapper").children("table").width(DTFC_LeftWidth); + + if (that.s.init.resizeCallback) { + that.s.init.resizeCallback.call(that, that.s.mouse.targetColumn); } - } - }; - - ColResize.prototype.getTableAutoColWidths = function (table, types) { - var widths = {}, i, colIdx; - var $table = this.$(table); - for (i = 0; i < types.length; i++) { - widths[types[i]] = []; - } - if (!types.length || !$table.length) - return widths; - - var clnTable = $table.clone().removeAttr('id').css('table-layout', 'auto'); - - // Remove any assigned widths from the footer (from scrolling) - clnTable.find('thead th, tfoot th, tfoot td').css('width', ''); - var container = this.$('<div />').css({ - 'position': 'absolute', - 'width': '9999px', - 'height': '9999px' - }); - container.append(clnTable); - this.$(this.dt.settings.nTableWrapper).append(container); - - var headerCols = this.$('thead>tr>th', clnTable); - - for (i = 0; i < types.length; i++) { - var type = types[i]; - var fn = ''; - switch (type) { - case 'autoMinWidth': - clnTable.css('width', '1px'); - fn = 'width'; + }, + + /** + * Clean up ColResize memory references and event handlers + * @method _fnDestroy + * @returns void + * @private + */ + "_fnDestroy": function () { + var i, iLen; + + for (i = 0, iLen = this.s.dt.aoDrawCallback.length; i < iLen; i++) { + if (this.s.dt.aoDrawCallback[i].sName === 'ColResize_Pre') { + this.s.dt.aoDrawCallback.splice(i, 1); break; - case 'autoWidth': - clnTable.css('width', 'auto'); - fn = 'outerWidth'; - break; - default: - throw 'Invalid widthType ' + type; - } - for (colIdx = 0; colIdx < headerCols.length; colIdx++) { - widths[type].push(this.$(headerCols[colIdx])[fn]()); - } - } - - container.remove(); - return widths; - }; - - ColResize.prototype.updateColumnsAutoWidth = function (types) { - var columns = this.dt.settings.aoColumns; - var i, j, colLen, type, visColIdx = 0; - var widths = {}; - if (this.dom.scrollX || this.dom.scrollY) { - var headWidths = this.getTableAutoColWidths(this.dom.scrollHeadTable, types); - var bodyWidths = this.getTableAutoColWidths(this.dom.scrollBodyTable, types); - var footWidths = this.getTableAutoColWidths(this.dom.scrollFootTable, types); - - for (i = 0; i < types.length; i++) { - type = types[i]; - widths[type] = []; - footWidths[type].length = headWidths[type].length; - colLen = headWidths[type].length; - for (j = 0; j < colLen; j++) { - widths[type].push(Math.max(headWidths[type][j], bodyWidths[type][j], (footWidths[type][j] || 0))); } } - } else { - widths = this.getTableAutoColWidths(this.dt.settings.nTable, types); - } - - for (i = 0; i < columns.length; i++) { - if (!columns[i].bVisible) - continue; - for (j = 0; j < types.length; j++) { - type = types[j]; - columns[i][type] = widths[type][visColIdx]; - } - visColIdx++; - } - }; - ColResize.prototype.overrideClickHander = function (col, $th) { - var dtClickEvent = this.getColumnEvent($th.get(0), 'click', 'DT'); + $(this.s.dt.nTHead).find('*').off('.ColResize'); - //Remove the DataTables event so that ordering will not occur - if (dtClickEvent) { - $th.off('click.DT'); - this.$(document).one('click.ColResize', function (e) { - $th.on('click.DT', dtClickEvent.handler); + $.each(this.s.dt.aoColumns, function (i, column) { + $(column.nTh).removeAttr('data-column-index'); }); - } - }; - - ColResize.prototype.onDblClick = function (e, $th, col) { - if (e.target !== $th.get(0)) - return; - if ($th.css('cursor') != 'col-resize') - return; - - var width; - switch (this.settings.dblClick) { - case 'autoMinFit': - width = col.autoMinWidth; - break; - case 'autoFit': - width = col.autoWidth; - break; - default: - width = col.initWidth; - } - this.resize(col, width); - }; - - ColResize.prototype.onMouseDown = function (e, col) { - var _this = this; - if (e.target !== col.nTh && e.target !== col.fhTh) - return true; - - var $th = e.target === col.nTh ? this.$(col.nTh) : this.$(col.fhTh); - - if ($th.css('cursor') != 'col-resize' || col.resizable === false) { - var colReorder = this.dt.settings._colReorder; - if (colReorder) { - colReorder._fnMouseDown.call(colReorder, e, e.target); //Here we fix the e.preventDefault() in ColReorder so that we can have working inputs in header - } - return true; - } - this.dom.mouse.startX = e.pageX; - this.dom.mouse.prevX = e.pageX; - this.dom.mouse.startWidth = $th.width(); - this.dom.resize = true; - this.beforeResizing(col); + this.s.dt._colResize = null; + this.s = null; + }, - /* Add event handlers to the document */ - this.$(document).on('mousemove.ColResize', function (event) { - _this.onMouseMove(event, col); - }); - this.overrideClickHander(col, $th); - this.$(document).one('mouseup.ColResize', function (event) { - _this.onMouseUp(event, col); - }); - - return false; - }; - - ColResize.prototype.resize = function (col, width) { - var colWidth = this.$(col.nTh).width(); - var moveLength = width - this.$(col.nTh).width(); - this.beforeResizing(col); - var resized = this.resizeColumn(col, colWidth, moveLength, moveLength); - this.afterResizing(); - return resized; - }; - - ColResize.prototype.beforeResizing = function (col) { - //if (this.settings.fixedLayout && !this.dom.fixedLayout) - // this.setTablesLayout('fixed'); - }; - - ColResize.prototype.afterResizing = function () { - var i; - var columns = this.dt.settings.aoColumns; - for (i = 0; i < columns.length; i++) { - if (!columns[i].bVisible) - continue; - columns[i].sWidth = this.$(columns[i].nTh).css('width'); - } - - //Update the internal storage of the table's width (in case we changed it because the user resized some column and scrollX was enabled - this.updateTableSize(); - - //Save the state - this.dt.settings.oInstance.oApi._fnSaveState(this.dt.settings); - this.dom.origState = false; - }; - ColResize.prototype.onMouseUp = function (e, col) { - this.$(document).off('mousemove.ColResize'); - if (!this.dom.resize) - return; - this.dom.resize = false; - this.afterResizing(); - }; - - ColResize.prototype.canResizeColumn = function (col, newWidth) { - return (col.resizable === undefined || col.resizable) && this.settings.minWidth <= newWidth && (!col.minWidth || col.minWidth <= newWidth) && (!this.settings.maxWidth || this.settings.maxWidth >= newWidth) && (!col.maxWidth || col.maxWidth >= newWidth); - }; - - ColResize.prototype.getColumnMaxWidth = function (col) { - return col.maxWidth ? col.maxWidth : this.settings.maxWidth; - }; - - ColResize.prototype.getColumnMinWidth = function (col) { - return col.minWidth ? col.minWidth : this.settings.minWidth; - }; - - ColResize.prototype.getPrevResizableColumnIdx = function (col, moveLength) { - var columns = this.dt.settings.aoColumns; - var colIdx = ColResizeHelper.indexOf(columns, col); - for (var i = colIdx; i >= 0; i--) { - if (!columns[i].bVisible) - continue; - var newWidth = this.$(columns[i].nTh).width() + moveLength; - if (this.canResizeColumn(columns[i], newWidth)) - return i; - } - return -1; - }; - - ColResize.prototype.getNextResizableColumnIdx = function (col, moveLength) { - var columns = this.dt.settings.aoColumns; - var colIdx = ColResizeHelper.indexOf(columns, col); - for (var i = (colIdx + 1); i < columns.length; i++) { - if (!columns[i].bVisible) - continue; - var newWidth = this.$(columns[i].nTh).width() - moveLength; - if (this.canResizeColumn(columns[i], newWidth)) - return i; + /** + * Add a data attribute to the column headers, so we know the index of + * the row to be reordered. This allows fast detection of the index, and + * for this plug-in to work with FixedHeader which clones the nodes. + * @private + */ + "_fnSetColumnIndexes": function () { + $.each(this.s.dt.aoColumns, function (i, column) { + $(column.nTh).attr('data-column-index', i); + }); } - return -1; }; - ColResize.prototype.resizeColumn = function (col, startWidth, moveLength, lastMoveLength) { - if (moveLength == 0 || lastMoveLength == 0 || col.resizable === false) - return false; - var i; - var columns = this.dt.settings.aoColumns; - var headCol = this.$(col.nTh); - var headColNext = headCol.next(); - var colIdx = this.getColumnIndex(col); - var thWidth = startWidth + moveLength; - var thNextWidth; - var nextColIdx; - - if (!this.dom.scrollX) { - if (lastMoveLength < 0) { - thWidth = headColNext.width() - lastMoveLength; - nextColIdx = this.getPrevResizableColumnIdx(col, lastMoveLength); - if (nextColIdx < 0) - return false; - headCol = headColNext; - colIdx = colIdx + 1; - headColNext = this.$(columns[nextColIdx].nTh); - thNextWidth = headColNext.width() + lastMoveLength; - } else { - thWidth = headCol.width() + lastMoveLength; - nextColIdx = this.getNextResizableColumnIdx(col, lastMoveLength); - - //If there is no columns that can be shrinked dont resize anymore - if (nextColIdx < 0) - return false; - headColNext = this.$(columns[nextColIdx].nTh); - thNextWidth = headColNext.width() - lastMoveLength; - if ((this.settings.maxWidth && this.settings.maxWidth < thWidth) || col.maxWidth && col.maxWidth < thWidth) - return false; - } - if (!this.canResizeColumn(columns[nextColIdx], thNextWidth) || !this.canResizeColumn(columns[colIdx], thWidth)) - return false; - headColNext.width(thNextWidth); - - //If fixed header is present we have to resize the cloned column too - if (this.dom.fixedHeader) { - this.$(columns[nextColIdx].fhTh).width(thNextWidth); - this.$(columns[colIdx].fhTh).width(thWidth); - - //If fixedfooter was enabled resize that too - if (columns[nextColIdx].fhTf) { - this.$(columns[nextColIdx].fhTf).width(thNextWidth); - this.$(columns[colIdx].fhTf).width(thWidth); + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Static parameters + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + + /** + * ColResize default settings for initialisation + * @namespace + * @static + */ + ColResize.defaults = { + /** + * Callback function that is fired when columns are resized + * @type function():void + * @default null + * @static + */ + "resizeCallback": null, + + /** + * Exclude array for columns that are not resizable + * @property exclude + * @type array of indexes that are excluded from resizing + * @default [] + */ + "exclude": [], + + /** + * Check to see if user is using a fixed table width or dynamic + * if true: + * -Columns will resize themselves and their neighbour + * -If neighbour is excluded resize will not occur + * if false: + * -Columns will resize themselves and increase or decrease the width of the table accordingly + */ + "tableWidthFixed": true, + + /** + * Width of the resize handle in pixels + * @property handleWidth + * @type int (pixels) + * @default 10 + */ + "handleWidth": 10, + + /** + * Right to left support, when true flips which column they are resizing on mouse down + * @property rtl + * @type bool + * @default false + */ + "rtl": false + }; + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Constants + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + /** + * ColResize version + * @constant version + * @type String + * @default As code + */ + ColResize.version = "0.0.10"; + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * DataTables interfaces + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + // Expose + $.fn.dataTable.ColResize = ColResize; + $.fn.DataTable.ColResize = ColResize; + + + // Register a new feature with DataTables + if (typeof $.fn.dataTable == "function" && + typeof $.fn.dataTableExt.fnVersionCheck == "function" && + $.fn.dataTableExt.fnVersionCheck('1.9.3')) { + $.fn.dataTableExt.aoFeatures.push({ + "fnInit": function (settings) { + var table = settings.oInstance; + + if (!settings._colResize) { + var dtInit = settings.oInit; + var opts = dtInit.colResize || dtInit.oColResize || {}; + + new ColResize(settings, opts); + } + else { + table.oApi._fnLog(settings, 1, "ColResize attempted to initialise twice. Ignoring second"); } - } - } else { - if (!this.canResizeColumn(col, thWidth)) - return false; - var tSize = this.tableSize + moveLength + 'px'; - this.dom.scrollHeadInner.css('width', tSize); - this.dom.scrollHeadTable.css('width', tSize); - this.dom.scrollBodyTable.css('width', tSize); - this.dom.scrollFootTable.css('width', tSize); - } - headCol.width(thWidth); - - //scrollX or scrollY enabled - if (this.dom.scrollBody.length) { - var colDomIdx = 0; - for (i = 0; i < this.dt.settings.aoColumns.length && i != colIdx; i++) { - if (this.dt.settings.aoColumns[i].bVisible) - colDomIdx++; - } - //Get the table - var bodyCol = this.$('thead>tr>th:nth(' + colDomIdx + ')', this.dom.scrollBodyTable); - var footCol = this.$('thead>tr>th:nth(' + colDomIdx + ')', this.dom.scrollFootTable); + return null; + /* No node for DataTables to insert */ + }, + "cFeature": "Z", + "sFeature": "ColResize" + }); + } else { + alert("Warning: ColResize requires DataTables 1.9.3 or greater - www.datatables.net/download"); + } - //This will happen only when scrollY is used without scrollX - if (!this.dom.scrollX) { - var nextColDomIdx = 0; - for (i = 0; i < this.dt.settings.aoColumns.length && i != nextColIdx; i++) { - if (this.dt.settings.aoColumns[i].bVisible) - nextColDomIdx++; - } - var bodyColNext = this.$('thead>tr>th:nth(' + nextColDomIdx + ')', this.dom.scrollBodyTable); - var footColNext = this.$('thead>tr>th:nth(' + nextColDomIdx + ')', this.dom.scrollFootTable); - bodyColNext.width(thNextWidth); - if (thWidth > 0) - bodyCol.width(thWidth); +// API augmentation + if ($.fn.dataTable.Api) { + $.fn.dataTable.Api.register('colResize.reset()', function () { + return this.iterator('table', function (ctx) { + ctx._colResize.fnReset(); + }); + }); + } - footColNext.width(thNextWidth); - if (thWidth > 0) - footCol.width(thWidth); - } + return ColResize; + }; // /factory - //Resize the table and the column - if (this.dom.scrollX && thWidth > 0) { - bodyCol.width(thWidth); - footCol.width(thWidth); - } - } - return true; - }; - ColResize.prototype.onMouseMove = function (e, col) { - var moveLength = e.pageX - this.dom.mouse.startX; - var lastMoveLength = e.pageX - this.dom.mouse.prevX; - this.resizeColumn(col, this.dom.mouse.startWidth, moveLength, lastMoveLength); - this.dom.mouse.prevX = e.pageX; - }; +// Define as an AMD module if possible +if ( typeof define === 'function' && define.amd ) { + define( ['jquery', 'datatables'], factory ); +} +else if ( typeof exports === 'object' ) { + // Node/CommonJS + factory( require('jquery'), require('datatables') ); +} +else if (jQuery && !jQuery.fn.dataTable.ColResize) { + // Otherwise simply initialise as normal, stopping multiple evaluation + factory(jQuery, jQuery.fn.dataTable); +} - ColResize.prototype.destroy = function () { - }; - ColResize.defaultSettings = { - minWidth: 1, - maxWidth: null, - fixedLayout: true, - fixedHeader: null, - dblClick: 'initWidth' - }; - return ColResize; - })(); - dt.ColResize = ColResize; - var ColResizeHelper = (function () { - function ColResizeHelper() { - } - ColResizeHelper.indexOf = function (arr, item, equalFun) { - if (typeof equalFun === "undefined") { equalFun = null; } - for (var i = 0; i < arr.length; i++) { - if (equalFun) { - if (equalFun(arr[i], item)) - return i; - } else if (arr[i] === item) - return i; - } - return -1; - }; - return ColResizeHelper; - })(); - dt.ColResizeHelper = ColResizeHelper; -})(dt || (dt = {})); - -(function ($, window, document, undefined) { - //Register events - $.fn.DataTable.models.oSettings.colResizeInitCompleted = []; - - //Register api function - $.fn.DataTable.Api.register('colResize.init()', function (settings) { - var colResize = new dt.ColResize($, this, settings); - if (this.settings()[0]._bInitComplete) - colResize.initialize(); - else - this.one('init.dt', function () { - colResize.initialize(); - }); - return null; - }); - - $.fn.DataTable.Api.register('column().resize()', function (width) { - var oSettings = this.settings()[0]; - var colResize = oSettings.colResize; - return colResize.resize(oSettings.aoColumns[this[0][0]], width); - }); - - //Add as feature - $.fn.dataTable.ext.feature.push({ - "fnInit": function (oSettings) { - return oSettings.oInstance.api().colResize.init(oSettings.oInit.colResize); - }, - "cFeature": "J", - "sFeature": "ColResize" - }); -}(jQuery, window, document, undefined));
\ No newline at end of file +})(window, document);
\ No newline at end of file diff --git a/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.colResize2.js b/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.colResize2.js new file mode 100644 index 00000000..6ef9907a --- /dev/null +++ b/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.colResize2.js @@ -0,0 +1,943 @@ +var dt; +(function (dt) { + var ColResize = (function () { + function ColResize($, api, settings) { + this.$ = $; + this.tableSize = -1; + this.initialized = false; + this.dt = {}; + this.dom = { + fixedLayout: false, + fixedHeader: null, + winResizeTimer: null, + mouse: { + startX: -1, + startWidth: null + }, + table: { + prevWidth: null + }, + origState: true, + resize: false, + scrollHead: null, + scrollHeadTable: null, + scrollFoot: null, + scrollFootTable: null, + scrollFootInner: null, + scrollBody: null, + scrollBodyTable: null, + scrollX: false, + scrollY: false + }; + this.settings = this.$.extend(true, {}, dt.ColResize.defaultSettings, settings); + this.dt.settings = api.settings()[0]; + this.dt.api = api; + this.dt.settings.colResize = this; + this.registerCallbacks(); + } + ColResize.prototype.initialize = function () { + var _this = this; + this.$.each(this.dt.settings.aoColumns, function (i, col) { + return _this.setupColumn(col); + }); + + //Initialize fixedHeader if specified + if (this.settings.fixedHeader) + this.setupFixedHeader(); + + //Save scroll head and body if found + this.dom.scrollHead = this.$('div.' + this.dt.settings.oClasses.sScrollHead, this.dt.settings.nTableWrapper); + this.dom.scrollHeadInner = this.$('div.' + this.dt.settings.oClasses.sScrollHeadInner, this.dom.scrollHead); + this.dom.scrollHeadTable = this.$('div.' + this.dt.settings.oClasses.sScrollHeadInner + ' > table', this.dom.scrollHead); + + this.dom.scrollFoot = this.$('div.' + this.dt.settings.oClasses.sScrollFoot, this.dt.settings.nTableWrapper); + this.dom.scrollFootInner = this.$('div.' + this.dt.settings.oClasses.sScrollFootInner, this.dom.scrollFoot); + this.dom.scrollFootTable = this.$('div.' + this.dt.settings.oClasses.sScrollFootInner + ' > table', this.dom.scrollFoot); + + this.dom.scrollBody = this.$('div.' + this.dt.settings.oClasses.sScrollBody, this.dt.settings.nTableWrapper); + this.dom.scrollBodyTable = this.$('> table', this.dom.scrollBody); + this.dt.api.on('draw.dt', this.onDraw.bind(this)); + if (this.dom.scrollFootTable) { + this.dt.api.on('colPinFcDraw.dt', function (e, colPin, data) { + if (data.leftClone.header) + _this.$('tfoot', data.leftClone.header).remove(); + if (data.leftClone.footer) + _this.$('thead', data.leftClone.footer).remove(); + if (data.rightClone.header) + _this.$('tfoot', data.rightClone.header).remove(); + if (data.rightClone.footer) + _this.$('thead', data.rightClone.footer).remove(); + }); + } + + this.dom.scrollX = this.dt.settings.oInit.sScrollX === undefined ? false : true; + this.dom.scrollY = this.dt.settings.oInit.sScrollY === undefined ? false : true; + + //SaveTableWidth + this.dt.settings.sTableWidthOrig = this.$(this.dt.settings.nTable).width(); + this.updateTableSize(); + + this.dt.settings.oFeatures.bAutoWidthOrig = this.dt.settings.oFeatures.bAutoWidth; + this.dt.settings.oFeatures.bAutoWidth = false; + + if (this.dt.settings.oInit.bStateSave && this.dt.settings.oLoadedState) { + this.loadState(this.dt.settings.oLoadedState); + } + + this.onDraw(); + this.dom.table.preWidth = parseFloat(this.dom.scrollBodyTable.css('width')); + + if (!this.dom.scrollX && this.dom.scrollY && this.settings.fixedLayout && this.dt.settings._reszEvt) { + //We have to manually resize columns on window resize + var eventName = 'resize.DT-' + this.dt.settings.sInstance; + this.$(window).off(eventName); + this.$(window).on(eventName, function () { + _this.proportionallyColumnSizing(); + //api._fnAdjustColumnSizing(this.dt.settings); + }); + } + + if (this.dom.scrollX || this.dom.scrollY) { + this.dt.api.on('column-sizing.dt', this.fixFootAndHeadTables.bind(this)); + this.dt.api.on('column-visibility.dt', this.fixFootAndHeadTables.bind(this)); + } + + this.initialized = true; + this.dt.settings.oApi._fnCallbackFire(this.dt.settings, 'colResizeInitCompleted', 'colResizeInitCompleted', [this]); + }; + + ColResize.prototype.setupColumn = function (col) { + var _this = this; + var $th = this.$(col.nTh); + if (col.resizable === false) + return; + + // listen to mousemove event for resize + $th.on('mousemove.ColResize', function (e) { + if (_this.dom.resize || col.resizable === false) + return; + + /* Store information about the mouse position */ + var $thTarget = e.target.nodeName.toUpperCase() == 'TH' ? _this.$(e.target) : _this.$(e.target).closest('TH'); + var offset = $thTarget.offset(); + var nLength = $thTarget.innerWidth(); + + /* are we on the col border (if so, resize col) */ + if (Math.abs(e.pageX - Math.round(offset.left + nLength)) <= 5) { + $thTarget.css({ 'cursor': 'col-resize' }); + } else + $thTarget.css({ 'cursor': 'pointer' }); + }); + + //Save the original width + col._ColResize_sWidthOrig = col.sWidthOrig; + col.initWidth = $th.width(); + col.minWidthOrig = col.minWidth; + + $th.on('dblclick.ColResize', function (e) { + _this.onDblClick(e, $th, col); + }); + + $th.off('mousedown.ColReorder'); + + // listen to mousedown event + $th.on('mousedown.ColResize', function (e) { + return _this.onMouseDown(e, col); + }); + }; + + ColResize.prototype.setupFixedHeader = function () { + var fhSettings = this.settings.fixedHeader === true ? undefined : this.settings.fixedHeader; + + //If left or right option was set to true disable resizing for the first or last column + if (this.$.isPlainObject(fhSettings)) { + var columns = this.dt.settings.aoColumns; + if (fhSettings.left === true) + columns[0].resizable = false; + if (fhSettings.right === true) + columns[columns.length - 1].resizable = false; + } + + this.dom.fixedHeader = new this.$.fn.dataTable.FixedHeader(this.dt.api, fhSettings); + var origUpdateClones = this.dom.fixedHeader._fnUpdateClones; + var that = this; + + //FixeHeader doesn't have any callback after updating the clones so we have to wrap the orig function + this.dom.fixedHeader._fnUpdateClones = function () { + origUpdateClones.apply(this, arguments); + that.memorizeFixedHeaderNodes(); + }; + + //As we missed the first call of _fnUpdateClones we have to call memorizeFixedHeaderNodes function manually + this.memorizeFixedHeaderNodes(); + }; + + ColResize.prototype.memorizeFixedHeaderNodes = function () { + var _this = this; + var fhSettings = this.dom.fixedHeader.fnGetSettings(); + var fhCache = fhSettings.aoCache; + var i, col; + for (i = 0; i < fhCache.length; i++) { + var type = fhCache[i].sType; + var propName; + var selector; + switch (type) { + case 'fixedHeader': + propName = 'fhTh'; + selector = 'thead>tr>th'; + this.dt.settings.fhTHead = fhCache[i].nNode; + break; + case 'fixedFooter': + propName = 'fhTf'; + selector = 'thead>tr>th'; + + //prepend a cloned thead to the floating footer table so that resizing will work correctly + var tfoot = this.$(fhCache[i].nNode); + var thead = this.$(this.dt.settings.nTHead).clone().css({ height: 0, visibility: 'hidden' }); + this.$('tr', thead).css('height', 0); + this.$('tr>th', thead).css({ + 'height': 0, + 'padding-bottom': 0, + 'padding-top': 0, + 'border-bottom-width': 0, + 'border-top-width': 0, + 'line-height': 0 + }); + tfoot.prepend(thead); + this.$('tfoot>tr>th', tfoot).css('width', ''); + this.dt.settings.fhTFoot = fhCache[i].nNode; + break; + default: + continue; + } + + this.$(selector, fhCache[i].nNode).each(function (j, th) { + col = _this.getVisibleColumn(j); + col[propName] = th; + }); + } + }; + + //zero based index + ColResize.prototype.getVisibleColumn = function (idx) { + var columns = this.dt.settings.aoColumns; + var currVisColIdx = -1; + for (var i = 0; i < columns.length; i++) { + if (!columns[i].bVisible) + continue; + currVisColIdx++; + if (currVisColIdx == idx) + return columns[i]; + } + return null; + }; + + ColResize.prototype.updateTableSize = function () { + if (this.dom.scrollX && this.dom.scrollHeadTable.length) + this.tableSize = this.dom.scrollHeadTable.width(); + else + this.tableSize = -1; + }; + + ColResize.prototype.proportionallyColumnSizing = function () { + var _this = this; + var prevWidths = [], newWidths = [], prevWidth, newWidth, newTableWidth, prevTableWidth, moveLength, multiplier, cWidth, i, j, delay = 500, prevTotalColWidths = 0, currTotalColWidths, columnRestWidths = [], columns = this.dt.settings.aoColumns, bodyTableColumns = this.$('thead th', this.dom.scrollBodyTable), headTableColumns = this.$('thead th', this.dom.scrollHeadTable), footTableColumns = this.dom.scrollFootTable.length ? this.$('thead th', this.dom.scrollFootTable) : [], visColumns = []; + + for (i = 0; i < columns.length; i++) { + if (!columns[i].bVisible) + continue; + visColumns.push(columns[i]); + columnRestWidths.push(0); //set default value + } + + for (i = 0; i < bodyTableColumns.length; i++) { + cWidth = parseFloat(bodyTableColumns[i].style.width); + prevTotalColWidths += cWidth; + prevWidths.push(cWidth); + } + + for (i = 0; i < bodyTableColumns.length; i++) { + bodyTableColumns[i].style.width = ''; + } + + //Get the new table width calculated by the browser + newTableWidth = parseFloat(this.dom.scrollBodyTable.css('width')); + + //Get the old table width + prevTableWidth = this.dom.table.preWidth; + moveLength = newTableWidth - prevTableWidth; + if (moveLength == 0) { + for (i = 0; i < bodyTableColumns.length; i++) { + bodyTableColumns[i].style.width = prevWidths[i] + 'px'; + } + return; + } + + //var tot = 0; + currTotalColWidths = prevTotalColWidths; + for (i = 0; i < visColumns.length; i++) { + //For each column calculate the new width + prevWidth = prevWidths[i]; + multiplier = (+(prevWidth / prevTotalColWidths).toFixed(2)); + + //tot += multiplier; + newWidth = prevWidth + (moveLength * multiplier) + columnRestWidths[i]; + currTotalColWidths -= prevWidth; + + //Check whether the column can be resized to the new calculated value + //if not, set it to the min or max width depends on the moveLength value + if (!this.canResizeColumn(visColumns[i], newWidth)) { + cWidth = moveLength > 0 ? this.getColumnMaxWidth(visColumns[i]) : this.getColumnMinWidth(visColumns[i]); + var rest = newWidth - cWidth; + newWidth = cWidth; + + for (j = (i + 1); j < visColumns.length; j++) { + columnRestWidths[j] += rest * (+(visColumns[j] / currTotalColWidths).toFixed(2)); + } + } + newWidths.push(newWidth); + } + + //Apply the calculated column widths to the headers cells + var tablesWidth = this.dom.scrollBodyTable.outerWidth() + 'px'; + for (i = 0; i < headTableColumns.length; i++) { + headTableColumns[i].style.width = newWidths[i] + 'px'; + } + this.dom.scrollHeadTable.css('width', tablesWidth); + this.dom.scrollHeadInner.css('width', tablesWidth); + + for (i = 0; i < bodyTableColumns.length; i++) { + bodyTableColumns[i].style.width = newWidths[i] + 'px'; + } + + if (this.dom.scrollFootTable.length) { + for (i = 0; i < footTableColumns.length; i++) { + footTableColumns[i].style.width = newWidths[i] + 'px'; + } + this.dom.scrollFootTable[0].style.width = tablesWidth; + this.dom.scrollFootInner[0].style.width = tablesWidth; + } + + //console.log('moveLength: ' + moveLength + ' multiplier: ' + tot); + //console.log(newWidths); + this.dom.table.preWidth = newTableWidth; + + //Call afterResizing function after the window stops resizing + if (this.dom.winResizeTimer) + clearTimeout(this.dom.winResizeTimer); + this.dom.winResizeTimer = setTimeout(function () { + _this.afterResizing(); + _this.dom.winResizeTimer = null; + }, delay); + }; + + ColResize.prototype.getColumnIndex = function (col) { + //Get the current column position + var colIdx = -1; + for (var i = 0; i < this.dt.settings.aoColumns.length; i++) { + if (this.dt.settings.aoColumns[i] === col) { + colIdx = i; + break; + } + } + return colIdx; + }; + + ColResize.prototype.getColumnEvent = function (th, type, ns) { + var event; + var thEvents = this.$._data(th, "events"); + this.$.each(thEvents[type] || [], function (idx, handler) { + if (handler.namespace === ns) + event = handler; + }); + return event; + }; + + ColResize.prototype.loadState = function (data) { + var _this = this; + var i, col; + + var onInit = function () { + if (_this.settings.fixedLayout) { + _this.setTablesLayout('fixed'); + } else { + _this.setTablesLayout('auto'); + } + if (!data.colResize) { + if (_this.dt.settings.oFeatures.bAutoWidthOrig) + _this.dt.settings.oFeatures.bAutoWidth = true; + else if (_this.dt.settings.sTableWidthOrig) + _this.$(_this.dt.settings.nTable).width(_this.dt.settings.sTableWidthOrig); + + for (i = 0; i < _this.dt.settings.aoColumns.length; i++) { + col = _this.dt.settings.aoColumns[i]; + if (col._ColResize_sWidthOrig) { + col.sWidthOrig = col._ColResize_sWidthOrig; + } + } + _this.dom.origState = true; + } else { + var columns = data.colResize.columns || []; + var wMap = {}; + + if (_this.dt.settings.oFeatures.bAutoWidth) { + _this.dt.settings.oFeatures.bAutoWidth = false; + } + + if (_this.dom.scrollX && data.colResize.tableSize > 0) { + _this.dom.scrollHeadTable.width(data.colResize.tableSize); + _this.dom.scrollHeadInner.width(data.colResize.tableSize); + _this.dom.scrollBodyTable.width(data.colResize.tableSize); + _this.dom.scrollFootTable.width(data.colResize.tableSize); + } + + for (i = 0; i < columns.length; i++) { + wMap[i] = columns[i]; + } + for (i = 0; i < _this.dt.settings.aoColumns.length; i++) { + col = _this.dt.settings.aoColumns[i]; + var idx = col._ColReorder_iOrigCol != null ? col._ColReorder_iOrigCol : i; + col.sWidth = wMap[idx]; + col.sWidthOrig = wMap[idx]; + col.nTh.style.width = columns[i]; + + //Check for FixedHeader + if (col.fhTh) + col.fhTh.style.width = columns[i]; + if (col.fhTf) + col.fhTf.style.width = columns[i]; + } + _this.dom.origState = false; + } + + _this.dt.api.columns.adjust(); + if (_this.dom.scrollX || _this.dom.scrollY) + _this.dt.api.draw(false); + }; + + if (this.initialized) { + onInit(); + return; + } + this.dt.settings.oApi._fnCallbackReg(this.dt.settings, 'colResizeInitCompleted', function () { + onInit(); + }, "ColResize_Init"); + }; + + ColResize.prototype.saveState = function (data) { + if (!this.dt.settings._bInitComplete) { + var oData = this.dt.settings.fnStateLoadCallback.call(this.dt.settings.oInstance, this.dt.settings); + if (oData && oData.colResize) + data.colResize = oData.colResize; + return; + } + this.updateTableSize(); + data.colResize = { + columns: [], + tableSize: this.tableSize + }; + + data.colResize.columns.length = this.dt.settings.aoColumns.length; + for (var i = 0; i < this.dt.settings.aoColumns.length; i++) { + var col = this.dt.settings.aoColumns[i]; + var idx = col._ColReorder_iOrigCol != null ? col._ColReorder_iOrigCol : i; + data.colResize.columns[idx] = col.sWidth; + } + }; + + ColResize.prototype.registerCallbacks = function () { + var _this = this; + /* State saving */ + this.dt.settings.oApi._fnCallbackReg(this.dt.settings, 'aoStateSaveParams', function (oS, oData) { + _this.saveState(oData); + }, "ColResize_StateSave"); + + /* State loading */ + this.dt.settings.oApi._fnCallbackReg(this.dt.settings, 'aoStateLoaded', function (oS, oData) { + _this.loadState(oData); + }, "ColResize_StateLoad"); + + if (this.$.fn.DataTable.models.oSettings.remoteStateInitCompleted !== undefined) { + //Integrate with remote state + this.dt.settings.oApi._fnCallbackReg(this.dt.settings, 'remoteStateLoadedParams', function (s, data) { + _this.loadState(data); + }, "ColResize_StateLoad"); + this.dt.settings.oApi._fnCallbackReg(this.dt.settings, 'remoteStateSaveParams', function (s, data) { + _this.saveState(data); + }, "ColResize_StateSave"); + } + }; + + ColResize.prototype.setTablesLayout = function (value) { + if (this.dom.scrollX || this.dom.scrollY) { + this.dom.scrollHeadTable.css('table-layout', value); + this.dom.scrollBodyTable.css('table-layout', value); + this.dom.scrollFootTable.css('table-layout', value); + } else { + this.$(this.dt.settings.nTable).css('table-layout', value); + } + this.dom.fixedLayout = value == 'fixed'; + }; + + //only when scrollX or scrollY are enabled + ColResize.prototype.fixFootAndHeadTables = function (e) { + var _this = this; + if (e != null && e.target !== this.dt.settings.nTable) + return; + + if (this.dom.scrollFootTable.length) { + this.$('thead', this.dom.scrollFootTable).remove(); + this.dom.scrollFootTable.prepend(this.$('thead', this.dom.scrollBodyTable).clone()); + } + this.$('tfoot', this.dom.scrollHeadTable).remove(); + this.dom.scrollHeadTable.append(this.$('tfoot', this.dom.scrollBodyTable).clone()); + var removeFooterWidth = function (table) { + _this.$('tfoot>tr>th', table).each(function (i, th) { + _this.$(th).css('width', ''); + }); + }; + + //Remove all tfoot headers widths + removeFooterWidth(this.dom.scrollFootTable); + removeFooterWidth(this.dom.scrollBodyTable); + removeFooterWidth(this.dom.scrollHeadTable); + }; + + ColResize.prototype.onDraw = function (e) { + if (e != null && e.target !== this.dt.settings.nTable) + return; + if (this.dom.scrollX || this.dom.scrollY) { + this.fixFootAndHeadTables(); + + //Fix the header table padding + if (this.dt.settings._bInitComplete) { + var borderWidth = this.dom.scrollHeadTable.outerWidth() - this.dom.scrollHeadTable.innerWidth(); + var paddingType = this.dt.settings.oBrowser.bScrollbarLeft ? 'padding-left' : 'padding-right'; + var paddingVal = parseFloat(this.dom.scrollHeadInner.css(paddingType)); + this.dom.scrollHeadInner.css(paddingType, (paddingVal + borderWidth) + 'px'); + } + } + + var autoWidthTypes = []; + if (this.settings.dblClick == 'autoMinFit' || !this.settings.fixedLayout) + autoWidthTypes.push('autoMinWidth'); + if (this.settings.dblClick == 'autoFit') + autoWidthTypes.push('autoWidth'); + + //Call this only once so that the table will be cloned only one time + if (autoWidthTypes.length) + this.updateColumnsAutoWidth(autoWidthTypes); + + if (!this.settings.fixedLayout) { + var columns = this.dt.settings.aoColumns; + var i; + for (i = 0; i < columns.length; i++) { + if (!columns[i].bVisible) + continue; + columns[i].minWidth = Math.max((columns[i].minWidthOrig || 0), columns[i].autoMinWidth); + + //We have to resize if the current column width if is less that the column minWidth + if (this.$(columns[i].nTh).width() < columns[i].minWidth) + this.resize(columns[i], columns[i].minWidth); + } + } else { + if (!this.dom.fixedLayout) { + this.setTablesLayout('fixed'); + this.afterResizing(); + } + } + }; + + ColResize.prototype.getTableAutoColWidths = function (table, types) { + var widths = {}, i, colIdx; + var $table = this.$(table); + for (i = 0; i < types.length; i++) { + widths[types[i]] = []; + } + if (!types.length || !$table.length) + return widths; + + var clnTable = $table.clone().removeAttr('id').css('table-layout', 'auto'); + + // Remove any assigned widths from the footer (from scrolling) + clnTable.find('thead th, tfoot th, tfoot td').css('width', ''); + var container = this.$('<div />').css({ + 'position': 'absolute', + 'width': '9999px', + 'height': '9999px' + }); + container.append(clnTable); + this.$(this.dt.settings.nTableWrapper).append(container); + + var headerCols = this.$('thead>tr>th', clnTable); + + for (i = 0; i < types.length; i++) { + var type = types[i]; + var fn = ''; + switch (type) { + case 'autoMinWidth': + clnTable.css('width', '1px'); + fn = 'width'; + break; + case 'autoWidth': + clnTable.css('width', 'auto'); + fn = 'outerWidth'; + break; + default: + throw 'Invalid widthType ' + type; + } + for (colIdx = 0; colIdx < headerCols.length; colIdx++) { + widths[type].push(this.$(headerCols[colIdx])[fn]()); + } + } + + container.remove(); + return widths; + }; + + ColResize.prototype.updateColumnsAutoWidth = function (types) { + var columns = this.dt.settings.aoColumns; + var i, j, colLen, type, visColIdx = 0; + var widths = {}; + if (this.dom.scrollX || this.dom.scrollY) { + var headWidths = this.getTableAutoColWidths(this.dom.scrollHeadTable, types); + var bodyWidths = this.getTableAutoColWidths(this.dom.scrollBodyTable, types); + var footWidths = this.getTableAutoColWidths(this.dom.scrollFootTable, types); + + for (i = 0; i < types.length; i++) { + type = types[i]; + widths[type] = []; + footWidths[type].length = headWidths[type].length; + colLen = headWidths[type].length; + for (j = 0; j < colLen; j++) { + widths[type].push(Math.max(headWidths[type][j], bodyWidths[type][j], (footWidths[type][j] || 0))); + } + } + } else { + widths = this.getTableAutoColWidths(this.dt.settings.nTable, types); + } + + for (i = 0; i < columns.length; i++) { + if (!columns[i].bVisible) + continue; + for (j = 0; j < types.length; j++) { + type = types[j]; + columns[i][type] = widths[type][visColIdx]; + } + visColIdx++; + } + }; + + ColResize.prototype.overrideClickHander = function (col, $th) { + var dtClickEvent = this.getColumnEvent($th.get(0), 'click', 'DT'); + + //Remove the DataTables event so that ordering will not occur + if (dtClickEvent) { + $th.off('click.DT'); + this.$(document).one('click.ColResize', function (e) { + $th.on('click.DT', dtClickEvent.handler); + }); + } + }; + + ColResize.prototype.onDblClick = function (e, $th, col) { + if (e.target !== $th.get(0)) + return; + if ($th.css('cursor') != 'col-resize') + return; + + var width; + switch (this.settings.dblClick) { + case 'autoMinFit': + width = col.autoMinWidth; + break; + case 'autoFit': + width = col.autoWidth; + break; + default: + width = col.initWidth; + } + this.resize(col, width); + }; + + ColResize.prototype.onMouseDown = function (e, col) { + var _this = this; + if (e.target !== col.nTh && e.target !== col.fhTh) + return true; + + var $th = e.target === col.nTh ? this.$(col.nTh) : this.$(col.fhTh); + + if ($th.css('cursor') != 'col-resize' || col.resizable === false) { + var colReorder = this.dt.settings._colReorder; + if (colReorder) { + colReorder._fnMouseDown.call(colReorder, e, e.target); //Here we fix the e.preventDefault() in ColReorder so that we can have working inputs in header + } + return true; + } + this.dom.mouse.startX = e.pageX; + this.dom.mouse.prevX = e.pageX; + this.dom.mouse.startWidth = $th.width(); + this.dom.resize = true; + + this.beforeResizing(col); + + /* Add event handlers to the document */ + this.$(document).on('mousemove.ColResize', function (event) { + _this.onMouseMove(event, col); + }); + this.overrideClickHander(col, $th); + this.$(document).one('mouseup.ColResize', function (event) { + _this.onMouseUp(event, col); + }); + + return false; + }; + + ColResize.prototype.resize = function (col, width) { + var colWidth = this.$(col.nTh).width(); + var moveLength = width - this.$(col.nTh).width(); + this.beforeResizing(col); + var resized = this.resizeColumn(col, colWidth, moveLength, moveLength); + this.afterResizing(); + return resized; + }; + + ColResize.prototype.beforeResizing = function (col) { + //if (this.settings.fixedLayout && !this.dom.fixedLayout) + // this.setTablesLayout('fixed'); + }; + + ColResize.prototype.afterResizing = function () { + var i; + var columns = this.dt.settings.aoColumns; + for (i = 0; i < columns.length; i++) { + if (!columns[i].bVisible) + continue; + columns[i].sWidth = this.$(columns[i].nTh).css('width'); + } + + //Update the internal storage of the table's width (in case we changed it because the user resized some column and scrollX was enabled + this.updateTableSize(); + + //Save the state + this.dt.settings.oInstance.oApi._fnSaveState(this.dt.settings); + this.dom.origState = false; + }; + + ColResize.prototype.onMouseUp = function (e, col) { + this.$(document).off('mousemove.ColResize'); + if (!this.dom.resize) + return; + this.dom.resize = false; + this.afterResizing(); + }; + + ColResize.prototype.canResizeColumn = function (col, newWidth) { + return (col.resizable === undefined || col.resizable) && this.settings.minWidth <= newWidth && (!col.minWidth || col.minWidth <= newWidth) && (!this.settings.maxWidth || this.settings.maxWidth >= newWidth) && (!col.maxWidth || col.maxWidth >= newWidth); + }; + + ColResize.prototype.getColumnMaxWidth = function (col) { + return col.maxWidth ? col.maxWidth : this.settings.maxWidth; + }; + + ColResize.prototype.getColumnMinWidth = function (col) { + return col.minWidth ? col.minWidth : this.settings.minWidth; + }; + + ColResize.prototype.getPrevResizableColumnIdx = function (col, moveLength) { + var columns = this.dt.settings.aoColumns; + var colIdx = ColResizeHelper.indexOf(columns, col); + for (var i = colIdx; i >= 0; i--) { + if (!columns[i].bVisible) + continue; + var newWidth = this.$(columns[i].nTh).width() + moveLength; + if (this.canResizeColumn(columns[i], newWidth)) + return i; + } + return -1; + }; + + ColResize.prototype.getNextResizableColumnIdx = function (col, moveLength) { + var columns = this.dt.settings.aoColumns; + var colIdx = ColResizeHelper.indexOf(columns, col); + for (var i = (colIdx + 1); i < columns.length; i++) { + if (!columns[i].bVisible) + continue; + var newWidth = this.$(columns[i].nTh).width() - moveLength; + if (this.canResizeColumn(columns[i], newWidth)) + return i; + } + return -1; + }; + + ColResize.prototype.resizeColumn = function (col, startWidth, moveLength, lastMoveLength) { + if (moveLength == 0 || lastMoveLength == 0 || col.resizable === false) + return false; + var i; + var columns = this.dt.settings.aoColumns; + var headCol = this.$(col.nTh); + var headColNext = headCol.next(); + var colIdx = this.getColumnIndex(col); + var thWidth = startWidth + moveLength; + var thNextWidth; + var nextColIdx; + + if (!this.dom.scrollX) { + if (lastMoveLength < 0) { + thWidth = headColNext.width() - lastMoveLength; + nextColIdx = this.getPrevResizableColumnIdx(col, lastMoveLength); + if (nextColIdx < 0) + return false; + headCol = headColNext; + colIdx = colIdx + 1; + headColNext = this.$(columns[nextColIdx].nTh); + thNextWidth = headColNext.width() + lastMoveLength; + } else { + thWidth = headCol.width() + lastMoveLength; + nextColIdx = this.getNextResizableColumnIdx(col, lastMoveLength); + + //If there is no columns that can be shrinked dont resize anymore + if (nextColIdx < 0) + return false; + headColNext = this.$(columns[nextColIdx].nTh); + thNextWidth = headColNext.width() - lastMoveLength; + + if ((this.settings.maxWidth && this.settings.maxWidth < thWidth) || col.maxWidth && col.maxWidth < thWidth) + return false; + } + if (!this.canResizeColumn(columns[nextColIdx], thNextWidth) || !this.canResizeColumn(columns[colIdx], thWidth)) + return false; + headColNext.width(thNextWidth); + + //If fixed header is present we have to resize the cloned column too + if (this.dom.fixedHeader) { + this.$(columns[nextColIdx].fhTh).width(thNextWidth); + this.$(columns[colIdx].fhTh).width(thWidth); + + //If fixedfooter was enabled resize that too + if (columns[nextColIdx].fhTf) { + this.$(columns[nextColIdx].fhTf).width(thNextWidth); + this.$(columns[colIdx].fhTf).width(thWidth); + } + } + } else { + if (!this.canResizeColumn(col, thWidth)) + return false; + var tSize = this.tableSize + moveLength + 'px'; + this.dom.scrollHeadInner.css('width', tSize); + this.dom.scrollHeadTable.css('width', tSize); + this.dom.scrollBodyTable.css('width', tSize); + this.dom.scrollFootTable.css('width', tSize); + } + headCol.width(thWidth); + + //scrollX or scrollY enabled + if (this.dom.scrollBody.length) { + var colDomIdx = 0; + for (i = 0; i < this.dt.settings.aoColumns.length && i != colIdx; i++) { + if (this.dt.settings.aoColumns[i].bVisible) + colDomIdx++; + } + + //Get the table + var bodyCol = this.$('thead>tr>th:nth(' + colDomIdx + ')', this.dom.scrollBodyTable); + var footCol = this.$('thead>tr>th:nth(' + colDomIdx + ')', this.dom.scrollFootTable); + + //This will happen only when scrollY is used without scrollX + if (!this.dom.scrollX) { + var nextColDomIdx = 0; + for (i = 0; i < this.dt.settings.aoColumns.length && i != nextColIdx; i++) { + if (this.dt.settings.aoColumns[i].bVisible) + nextColDomIdx++; + } + var bodyColNext = this.$('thead>tr>th:nth(' + nextColDomIdx + ')', this.dom.scrollBodyTable); + var footColNext = this.$('thead>tr>th:nth(' + nextColDomIdx + ')', this.dom.scrollFootTable); + + bodyColNext.width(thNextWidth); + if (thWidth > 0) + bodyCol.width(thWidth); + + footColNext.width(thNextWidth); + if (thWidth > 0) + footCol.width(thWidth); + } + + //Resize the table and the column + if (this.dom.scrollX && thWidth > 0) { + bodyCol.width(thWidth); + footCol.width(thWidth); + } + } + return true; + }; + + ColResize.prototype.onMouseMove = function (e, col) { + var moveLength = e.pageX - this.dom.mouse.startX; + var lastMoveLength = e.pageX - this.dom.mouse.prevX; + this.resizeColumn(col, this.dom.mouse.startWidth, moveLength, lastMoveLength); + this.dom.mouse.prevX = e.pageX; + }; + + ColResize.prototype.destroy = function () { + }; + ColResize.defaultSettings = { + minWidth: 1, + maxWidth: null, + fixedLayout: true, + fixedHeader: null, + dblClick: 'initWidth' + }; + return ColResize; + })(); + dt.ColResize = ColResize; + + var ColResizeHelper = (function () { + function ColResizeHelper() { + } + ColResizeHelper.indexOf = function (arr, item, equalFun) { + if (typeof equalFun === "undefined") { equalFun = null; } + for (var i = 0; i < arr.length; i++) { + if (equalFun) { + if (equalFun(arr[i], item)) + return i; + } else if (arr[i] === item) + return i; + } + return -1; + }; + return ColResizeHelper; + })(); + dt.ColResizeHelper = ColResizeHelper; +})(dt || (dt = {})); + +(function ($, window, document, undefined) { + //Register events + $.fn.DataTable.models.oSettings.colResizeInitCompleted = []; + + //Register api function + $.fn.DataTable.Api.register('colResize.init()', function (settings) { + var colResize = new dt.ColResize($, this, settings); + if (this.settings()[0]._bInitComplete) + colResize.initialize(); + else + this.one('init.dt', function () { + colResize.initialize(); + }); + return null; + }); + + $.fn.DataTable.Api.register('column().resize()', function (width) { + var oSettings = this.settings()[0]; + var colResize = oSettings.colResize; + return colResize.resize(oSettings.aoColumns[this[0][0]], width); + }); + + //Add as feature + $.fn.dataTable.ext.feature.push({ + "fnInit": function (oSettings) { + return oSettings.oInstance.api().colResize.init(oSettings.oInit.colResize); + }, + "cFeature": "J", + "sFeature": "ColResize" + }); +}(jQuery, window, document, undefined));
\ No newline at end of file diff --git a/wqflask/wqflask/static/new/packages/DataTables/js/jquery.dataTables.js b/wqflask/wqflask/static/new/packages/DataTables/js/jquery.dataTables.js index 2a9bdb36..1364bafc 100755 --- a/wqflask/wqflask/static/new/packages/DataTables/js/jquery.dataTables.js +++ b/wqflask/wqflask/static/new/packages/DataTables/js/jquery.dataTables.js @@ -640,7 +640,7 @@ oCol.sWidthOrig = th.attr('width') || null; // Style attribute - var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/); + var t = (th.attr('style') || '').match(/width:\s*(\d+[px|em|%]+)/); if ( t ) { oCol.sWidthOrig = t[1]; } diff --git a/wqflask/wqflask/templates/collections/list.html b/wqflask/wqflask/templates/collections/list.html index a00878a0..c05b694b 100755 --- a/wqflask/wqflask/templates/collections/list.html +++ b/wqflask/wqflask/templates/collections/list.html @@ -4,8 +4,6 @@ <link rel="stylesheet" type="text/css" href="/static/new/packages/DataTables/css/jquery.dataTables.css" /> <link rel="stylesheet" type="text/css" href="/static/packages/DT_bootstrap/DT_bootstrap.css" /> <link rel="stylesheet" type="text/css" href="/static/packages/TableTools/media/css/TableTools.css" /> - <link rel="stylesheet" type="text/css" href="//cdn.datatables.net/fixedheader/2.1.2/css/dataTables.fixedHeader.css" > - <link rel="stylesheet" type="text/css" href="//cdn.datatables.net/fixedcolumns/3.0.4/css/dataTables.fixedColumns.css"> {% endblock %} {% block content %} <!-- Start of body --> @@ -59,30 +57,20 @@ <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/jquery.dataTables.min.js"></script> <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/dataTables.naturalSort.js"></script> <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.colResize.js"></script> + <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.colReorder.js"></script> <script language="javascript" type="text/javascript" src="/static/packages/DT_bootstrap/DT_bootstrap.js"></script> <script language="javascript" type="text/javascript" src="/static/packages/TableTools/media/js/TableTools.min.js"></script> - <script language="javascript" type="text/javascript" src="//cdn.datatables.net/fixedheader/2.1.2/js/dataTables.fixedHeader.min.js"></script> - <script language="javascript" type="text/javascript" src="//cdn.datatables.net/fixedcolumns/3.0.4/js/dataTables.fixedColumns.min.js"></script> <script> $('#trait_table').dataTable( { - "sDom": "Ztir", + "sDom": "RZtir", "iDisplayLength": -1, "autoWidth": true, - "bLengthChange": true, "bDeferRender": true, "bSortClasses": false, "scrollY": "600px", - "scrollX": true, "scrollCollapse": true, - "colResize": { - "tableWidthFixed": false - }, "paging": false } ); - var table = $('#trait_table').DataTable(); - //new $.fn.dataTable.FixedHeader( table ); - new $.fn.dataTable.FixedColumns( table ); - </script> {% endblock %} diff --git a/wqflask/wqflask/templates/collections/view.html b/wqflask/wqflask/templates/collections/view.html index 49df6af5..29c65058 100755 --- a/wqflask/wqflask/templates/collections/view.html +++ b/wqflask/wqflask/templates/collections/view.html @@ -4,8 +4,6 @@ <link rel="stylesheet" type="text/css" href="/static/new/packages/DataTables/css/jquery.dataTables.css" /> <link rel="stylesheet" type="text/css" href="/static/packages/DT_bootstrap/DT_bootstrap.css" /> <link rel="stylesheet" type="text/css" href="/static/packages/TableTools/media/css/TableTools.css" /> - <link rel="stylesheet" type="text/css" href="//cdn.datatables.net/fixedheader/2.1.2/css/dataTables.fixedHeader.css" > - <link rel="stylesheet" type="text/css" href="//cdn.datatables.net/fixedcolumns/3.0.4/css/dataTables.fixedColumns.css"> {% endblock %} {% block content %} <!-- Start of body --> @@ -121,10 +119,9 @@ <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/jquery.dataTables.min.js"></script> <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/dataTables.naturalSort.js"></script> <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.colResize.js"></script> + <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.colReorder.js"></script> <script language="javascript" type="text/javascript" src="/static/packages/DT_bootstrap/DT_bootstrap.js"></script> <script language="javascript" type="text/javascript" src="/static/packages/TableTools/media/js/TableTools.min.js"></script> - <script language="javascript" type="text/javascript" src="//cdn.datatables.net/fixedheader/2.1.2/js/dataTables.fixedHeader.min.js"></script> - <script language="javascript" type="text/javascript" src="//cdn.datatables.net/fixedcolumns/3.0.4/js/dataTables.fixedColumns.min.js"></script> <script language="javascript" type="text/javascript"> @@ -152,25 +149,17 @@ "width": "15%" }, { "type": "natural" } ], - "sDom": "Ztir", + "sDom": "ZRtir", "iDisplayLength": -1, "autoWidth": true, - "bLengthChange": true, "bDeferRender": true, "bSortClasses": false, "scrollY": "600px", - "scrollX": true, "scrollCollapse": true, - "colResize": { - "tableWidthFixed": false - }, "paging": false } ); console.timeEnd("Creating table"); - var table = $('#trait_table').DataTable(); - new $.fn.dataTable.FixedColumns( table ); - }); </script> diff --git a/wqflask/wqflask/templates/correlation_page.html b/wqflask/wqflask/templates/correlation_page.html index d53f930d..62407555 100755 --- a/wqflask/wqflask/templates/correlation_page.html +++ b/wqflask/wqflask/templates/correlation_page.html @@ -229,22 +229,26 @@ { "type": "natural" }, { "type": "natural" } ], - "sDom": "RJtir", + "sDom": "RZtir", "iDisplayLength": -1, "autoWidth": true, "bLengthChange": true, "bDeferRender": true, "bSortClasses": false, - "scrollY": "700px", - "scrollCollapse": false, + //"scrollY": "700px", + //"scrollCollapse": false, "colResize": { "tableWidthFixed": false }, "paging": false } ); + + var table = $('#corr_results').DataTable(); + new $.fn.dataTable.FixedHeader( table ); + {% elif target_dataset.type == "Publish" %} $('#corr_results').dataTable( { - "aoColumns": [ + "columns": [ { "type": "natural" }, { "type": "natural" }, { "type": "natural" }, @@ -257,7 +261,7 @@ { "type": "natural" }, { "type": "natural" } ], - "sDom": "RJtir", + "sDom": "RZtir", "iDisplayLength": -1, "autoWidth": true, "bLengthChange": true, @@ -280,7 +284,7 @@ { "type": "natural" }, { "type": "natural" } ], - "sDom": "RJtir", + "sDom": "RZtir", "iDisplayLength": -1, "autoWidth": true, "bLengthChange": true, diff --git a/wqflask/wqflask/templates/gsearch_gene.html b/wqflask/wqflask/templates/gsearch_gene.html index 6cf16c08..ba2276d4 100755 --- a/wqflask/wqflask/templates/gsearch_gene.html +++ b/wqflask/wqflask/templates/gsearch_gene.html @@ -19,48 +19,51 @@ <button class="btn btn-default" id="select_all"><span class="glyphicon glyphicon-ok"></span> Select All</button> <button class="btn btn-default" id="deselect_all"><span class="glyphicon glyphicon-remove"></span> Deselect All</button> <button class="btn btn-default" id="invert"><span class="glyphicon glyphicon-resize-vertical"></span> Invert</button> - <button class="btn btn-default" id="add"><span class="glyphicon glyphicon-plus-sign"></span> Add</button> + <button class="btn btn-default" id="add" disabled ><span class="glyphicon glyphicon-plus-sign"></span> Add</button> <button class="btn btn-primary pull-right"><span class="glyphicon glyphicon-download"></span> Download Table</button> + <input type="text" id="searchbox" class="form-control" style="width: 200px; display: inline;" placeholder="Search This Table For ..."> + <input type="text" id="select_top" class="form-control" style="width: 200px; display: inline;" placeholder="Select Top ..."> + <br /> <br /> <table class="table table-hover table-striped" id="trait_table"> - <thead> - <tr> - <th style="width: 30px;"></th> - <th>Index</th> - <th>Species</th> - <th>Group</th> - <th>Tissue</th> - <th>Dataset</th> - <th>Record</th> - <th>Symbol</th> - <th>Description</th> - <th>Location</th> - <th>Mean</th> - <th style="text-align: right;">Max <br>LRS<a href="http://genenetwork.org//glossary.html#L" target="_blank"><sup style="color:#f00"> ?</sup></a></th> - <th>Max LRS Location</th> - <th style="text-align: right;">Additive<br>Effect<a href="http://genenetwork.org//glossary.html#A" target="_blank"><sup style="color:#f00"> ?</sup></a></th> - </tr> - </thead> + <thead> + <tr> + <th style="width: 30px;"></th> + <th>Index</th> + <th>Species</th> + <th>Group</th> + <th>Tissue</th> + <th>Dataset</th> + <th>Record</th> + <th>Symbol</th> + <th>Description</th> + <th>Location</th> + <th>Mean</th> + <th style="text-align: right;">Max <br>LRS<a href="http://genenetwork.org//glossary.html#L" target="_blank"><sup style="color:#f00"> ?</sup></a></th> + <th>Max LRS Location</th> + <th style="text-align: right;">Additive<br>Effect<a href="http://genenetwork.org//glossary.html#A" target="_blank"><sup style="color:#f00"> ?</sup></a></th> + </tr> + </thead> <tbody> - {% for this_trait in trait_list %} - <TR id="trait:{{ this_trait.name }}:{{ this_trait.dataset.name }}"> - <TD><INPUT TYPE="checkbox" NAME="searchResult" class="checkbox trait_checkbox" style="transform: scale(1.5);" VALUE="{{ data_hmac('{}:{}'.format(this_trait.name, this_trait.dataset.name)) }}"></TD> - <TD>{{ loop.index }}</TD> - <TD>{{ this_trait.dataset.group.species }}</TD> - <TD>{{ this_trait.dataset.group.name }}</TD> - <TD>{{ this_trait.dataset.name }}</TD> - <TD>{{ this_trait.dataset.name }}</TD> - <TD><a href="{{ url_for('show_trait_page', trait_id = this_trait.name, dataset = this_trait.dataset.name)}}">{{ this_trait.name }}</a></TD> - <TD>{{ this_trait.symbol }}</TD> - <TD>{{ this_trait.description_display }}</TD> - <TD>{{ this_trait.location_repr }}</TD> - <TD align="right">{{ '%0.3f' % this_trait.mean|float }}</TD> - <TD align="right">{{ '%0.3f' % this_trait.LRS_score_repr|float }}</TD> - <TD>{{ this_trait.LRS_location_repr }}</TD> - <TD align="right">{{ '%0.3f' % this_trait.additive|float }}</TD> - </TR> - {% endfor %} + {% for this_trait in trait_list %} + <TR id="trait:{{ this_trait.name }}:{{ this_trait.dataset.name }}"> + <TD><INPUT TYPE="checkbox" NAME="searchResult" class="checkbox trait_checkbox" style="transform: scale(1.5);" VALUE="{{ data_hmac('{}:{}'.format(this_trait.name, this_trait.dataset.name)) }}"></TD> + <TD>{{ loop.index }}</TD> + <TD>{{ this_trait.dataset.group.species }}</TD> + <TD>{{ this_trait.dataset.group.name }}</TD> + <TD>{{ this_trait.dataset.name }}</TD> + <TD>{{ this_trait.dataset.name }}</TD> + <TD><a href="{{ url_for('show_trait_page', trait_id = this_trait.name, dataset = this_trait.dataset.name)}}">{{ this_trait.name }}</a></TD> + <TD>{{ this_trait.symbol }}</TD> + <TD>{{ this_trait.description_display }}</TD> + <TD>{{ this_trait.location_repr }}</TD> + <TD align="right">{{ '%0.3f' % this_trait.mean|float }}</TD> + <TD align="right">{{ '%0.3f' % this_trait.LRS_score_repr|float }}</TD> + <TD>{{ this_trait.LRS_location_repr }}</TD> + <TD align="right">{{ '%0.3f' % this_trait.additive|float }}</TD> + </TR> + {% endfor %} </tbody> </table> </div> @@ -71,12 +74,12 @@ {% endblock %} {% block js %} - <script type="text/javascript" src="/static/new/javascript/search_results.js"></script> + <script language="javascript" type="text/javascript" src="/static/new/javascript/search_results.js"></script> <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/jquery.dataTables.min.js"></script> <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/dataTables.naturalSort.js"></script> - <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.colResize.js"></script> <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.colReorder.js"></script> + <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.colResize.js"></script> <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.fixedHeader.js"></script> <script language="javascript" type="text/javascript" src="//cdn.datatables.net/fixedcolumns/3.0.4/js/dataTables.fixedColumns.min.js"></script> <script language="javascript" type="text/javascript" src="/static/packages/DT_bootstrap/DT_bootstrap.js"></script> @@ -112,13 +115,35 @@ return ((x < y) ? -1 : ((x > y) ? 1 : 0)); } }; + + jQuery.fn.dataTableExt.oSort['cust-txt-asc'] = function (a, b) { + var x = getValue(a); + var y = getValue(b); + if (x == 'N/A' || x == '') { + return 1; + } + else if (y == 'N/A' || y == '') { + return -1; + } + else { + return ((x < y) ? -1 : ((x > y) ? 1 : 0)); + } + }; + jQuery.fn.dataTableExt.oSort['cust-txt-desc'] = function (a, b) { var x = getValue(a); var y = getValue(b); return ((x < y) ? 1 : ((x > y) ? -1 : 0)); }; + $.fn.dataTable.ext.order['dom-checkbox'] = function ( settings, col ) + { + return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) { + return $('input', td).prop('checked') ? '1' : '0'; + } ); + } + $(document).ready( function () { $('#trait_table tr').click(function(event) { @@ -130,21 +155,23 @@ console.time("Creating table"); $('#trait_table').DataTable( { "columns": [ - { "bSortClasses": false }, { "type": "natural" }, { "type": "natural", "width": "35%" }, { "type": "natural", "width": "15%" }, { "type": "cust-txt" }, { "type": "natural", "width": "12%" }, - { "type": "natural", "width": "12%" }, - { "type": "natural", "width": "12%" }, - { "type": "natural", "width": "12%" }, - { "type": "natural", "width": "12%" }, + { "type": "natural", "width": "12%" }, + { "type": "natural", "width": "12%" }, + { "type": "natural", "width": "12%" }, + { "type": "natural", "width": "12%" }, { "type": "natural", "width": "15%" }, - { "type": "natural" }, - { "type": "natural" }, - { "type": "natural" } + { "type": "natural" }, + { "type": "natural" }, + { "type": "natural" }, + { "type": "cust-txt" } ], + "order": [[ 1, "asc" ]], + "sDom": "RZtir", "autoWidth": true, "bLengthChange": true, "bDeferRender": true, @@ -155,6 +182,7 @@ "paging": false } ); console.timeEnd("Creating table"); + }); </script> diff --git a/wqflask/wqflask/templates/gsearch_pheno.html b/wqflask/wqflask/templates/gsearch_pheno.html index c25b71a2..e1dcf76f 100755 --- a/wqflask/wqflask/templates/gsearch_pheno.html +++ b/wqflask/wqflask/templates/gsearch_pheno.html @@ -19,17 +19,19 @@ <button class="btn btn-default" id="select_all"><span class="glyphicon glyphicon-ok"></span> Select All</button> <button class="btn btn-default" id="deselect_all"><span class="glyphicon glyphicon-remove"></span> Deselect All</button> <button class="btn btn-default" id="invert"><span class="glyphicon glyphicon-resize-vertical"></span> Invert</button> - <button class="btn btn-default" id="add"><span class="glyphicon glyphicon-plus-sign"></span> Add</button> + <button class="btn btn-default" id="add" disabled ><span class="glyphicon glyphicon-plus-sign"></span> Add</button> <button class="btn btn-primary pull-right"><span class="glyphicon glyphicon-download"></span> Download Table</button> + <input type="text" id="searchbox" class="form-control" style="width: 200px; display: inline;" placeholder="Search This Table For ..."> + <input type="text" id="select_top" class="form-control" style="width: 200px; display: inline;" placeholder="Select Top ..."> <br /> <br /> <table class="table table-hover table-striped" id='trait_table' style="float: left;"> <thead> <tr> - <th style="width: 30px;"></th> + <th style="width: 30px;"></th> <th>Index</th> - <th>Species</th> - <th>Group</th> + <th>Species</th> + <th>Group</th> <th>Record</th> <th>Description</th> <th>Authors</th> @@ -43,16 +45,16 @@ {% for this_trait in trait_list %} <TR id="trait:{{ this_trait.name }}:{{ this_trait.dataset.name }}"> <TD><INPUT TYPE="checkbox" NAME="searchResult" class="checkbox trait_checkbox" style="transform: scale(1.5);" VALUE="{{ data_hmac('{}:{}'.format(this_trait.name, this_trait.dataset.name)) }}"></TD> - <TD>{{ loop.index }}</TD> + <TD>{{ loop.index }}</TD> <TD>{{ this_trait.dataset.group.species }}</TD> - <TD>{{ this_trait.dataset.group.name }}</TD> - <TD><a href="{{ url_for('show_trait_page', trait_id = this_trait.name, dataset = this_trait.dataset.name)}}">{{ this_trait.name }}</a></TD> + <TD>{{ this_trait.dataset.group.name }}</TD> + <TD><a href="{{ url_for('show_trait_page', trait_id = this_trait.name, dataset = this_trait.dataset.name)}}">{{ this_trait.name }}</a></TD> <TD>{{ this_trait.description_display }}</TD> - <TD>{{ this_trait.authors }}</TD> - <TD><a href="{{ this_trait.pubmed_link }}">{{ this_trait.pubmed_text }}</a></TD> - <TD>{{ this_trait.LRS_score_repr }}</TD> - <TD>{{ this_trait.LRS_location_repr }}</TD> - <TD>{{ '%0.3f' % this_trait.additive|float }}</TD> + <TD>{{ this_trait.authors }}</TD> + <TD><a href="{{ this_trait.pubmed_link }}">{{ this_trait.pubmed_text }}</a></TD> + <TD>{{ this_trait.LRS_score_repr }}</TD> + <TD>{{ this_trait.LRS_location_repr }}</TD> + <TD>{{ '%0.3f' % this_trait.additive|float }}</TD> </TR> {% endfor %} </tbody> @@ -65,11 +67,11 @@ {% endblock %} {% block js %} - <script type="text/javascript" src="/static/new/javascript/search_results.js"></script> + <script language="javascript" type="text/javascript" src="/static/new/javascript/search_results.js"></script> <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/jquery.dataTables.min.js"></script> <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/dataTables.naturalSort.js"></script> - <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.colResize.js"></script> + <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.colResize2.js"></script> <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.colReorder.js"></script> <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.fixedHeader.js"></script> <script language="javascript" type="text/javascript" src="//cdn.datatables.net/fixedcolumns/3.0.4/js/dataTables.fixedColumns.min.js"></script> @@ -124,19 +126,20 @@ console.time("Creating table"); $('#trait_table').DataTable( { "columns": [ - { "bSortClasses": false }, + { "bSortClasses": false }, { "type": "natural" }, { "type": "natural" }, { "type": "natural" }, { "type": "natural" }, { "type": "natural" }, - { "type": "natural" }, - { "type": "natural" }, - { "type": "natural" }, - { "type": "natural" }, - { "type": "natural" } + { "type": "natural" }, + { "type": "natural" }, + { "type": "natural" }, + { "type": "natural" }, + { "type": "natural" } ], - "sDom": "RJtir", + "order": [[ 1, "asc" ]], + "sDom": "RJtir", "iDisplayLength": -1, "autoWidth": true, "bLengthChange": true, diff --git a/wqflask/wqflask/templates/index_page.html b/wqflask/wqflask/templates/index_page.html index 49067e37..2bbfcd91 100755 --- a/wqflask/wqflask/templates/index_page.html +++ b/wqflask/wqflask/templates/index_page.html @@ -79,7 +79,7 @@ <label for="or_search" class="col-xs-1 control-label" style="padding-left: 0px; padding-right: 0px; width: 65px !important;">Get Any:</label> <div class="col-xs-10 controls"> <div class="col-xs-8"> - <textarea name="search_terms_or" rows="1" class="form-control search-query" style="max-width: 550px; width: 450px !important;" id="or_search"></textarea> + <textarea onkeydown="pressed(event)" name="search_terms_or" rows="1" class="form-control search-query" style="max-width: 550px; width: 450px !important;" id="or_search"></textarea> </div> </div> </div> @@ -100,7 +100,7 @@ <label for="and_search" class="col-xs-1 control-label" style="padding-left: 0px; padding-right: 0px; width: 65px !important;">Combined:</label> <div class="col-xs-10 controls"> <div class="col-xs-8"> - <textarea name="search_terms_and" rows="1" class="form-control search-query" style="max-width: 550px; width: 450px !important;" id="and_search"></textarea> + <textarea onkeydown="pressed(event)" name="search_terms_and" rows="1" class="form-control search-query" style="max-width: 550px; width: 450px !important;" id="and_search"></textarea> </div> </div> </div> @@ -265,4 +265,15 @@ {% block js %} <script src="/static/new/javascript/dataset_select_menu.js"></script> + + <script> + function pressed(e) { + // Has the enter key been pressed? + if ( (window.event ? event.keyCode : e.which) == 13) { + // If it has been so, manually submit the <form> + document.forms[0].submit(); + } + } + </script> + {% endblock %}
\ No newline at end of file diff --git a/wqflask/wqflask/templates/marker_regression.html b/wqflask/wqflask/templates/marker_regression.html index d8f64c20..91808fcf 100755 --- a/wqflask/wqflask/templates/marker_regression.html +++ b/wqflask/wqflask/templates/marker_regression.html @@ -26,26 +26,36 @@ </div> </div> - <div> + <div style="width:60%;"> <h2> Results </h2> - <table cellpadding="0" cellspacing="0" border="0" id="qtl_results" class="table table-hover table-striped table-bordered"> + <table id="qtl_results" class="table table-hover table-striped"> <thead> <tr> - <td>Index</td> - <td>LOD Score</td> - <td>Chr</td> - <td>Mb</td> - <td>Locus</td> + <th>Index</th> + <th>LOD Score</th> + <th>Chr</th> + <th>Mb</th> + <th>Locus</th> </tr> </thead> <tbody> - {% for marker in filtered_markers %} - {% if marker.lod_score > lod_cutoff %} + {% for marker in qtl_results %} + {% if (score_type == "LOD" and marker.lod_score > cutoff) or + (score_type == "LRS" and marker.lrs_value > cutoff) %} <tr> - <td>{{loop.index}}</td> + <td> + {{loop.index}} + <input type="checkbox" name="selectCheck" + class="checkbox edit_sample_checkbox" + value="{{ marker.name }}" checked="checked"> + </td> + {% if score_type == "LOD" %} <td>{{marker.lod_score}}</td> + {% else %} + <td>{{marker.lrs_value}}</td> + {% endif %} <td>{{marker.chr}}</td> <td>{{marker.Mb}}</td> <td>{{marker.name}}</td> @@ -70,26 +80,24 @@ $(document).ready( function () { console.time("Creating table"); $('#qtl_results').dataTable( { - //"sDom": "<<'span3'l><'span3'T><'span4'f>'row-fluid'r>t<'row-fluid'<'span6'i><'span6'p>>", - "sDom": "lTftipr", - "oTableTools": { - "aButtons": [ - "copy", - "print", - { - "sExtends": "collection", - "sButtonText": 'Save <span class="caret" />', - "aButtons": [ "csv", "xls", "pdf" ] - } + "columns": [ + { "type": "natural" }, + { "type": "natural" }, + { "type": "natural" }, + { "type": "natural" }, + { "type": "natural" } ], - "sSwfPath": "/static/packages/TableTools/media/swf/copy_csv_xls_pdf.swf" - }, - "iDisplayLength": 50, - "bLengthChange": true, + "sDom": "ZRtir", + "iDisplayLength": -1, + "autoWidth": true, "bDeferRender": true, - "bSortClasses": false + "bSortClasses": false, + "scrollY": "700px", + "scrollCollapse": true, + "paging": false } ); console.timeEnd("Creating table"); + }); </script> {% endblock %} diff --git a/wqflask/wqflask/templates/search_result_page.html b/wqflask/wqflask/templates/search_result_page.html index b9bb65fd..62dc4fb4 100755 --- a/wqflask/wqflask/templates/search_result_page.html +++ b/wqflask/wqflask/templates/search_result_page.html @@ -43,15 +43,18 @@ <button class="btn btn-default" id="select_all"><span class="glyphicon glyphicon-ok"></span> Select All</button> <button class="btn btn-default" id="deselect_all"><span class="glyphicon glyphicon-remove"></span> Deselect All</button> <button class="btn btn-default" id="invert"><span class="glyphicon glyphicon-resize-vertical"></span> Invert</button> - <button class="btn btn-default" id="add"><span class="glyphicon glyphicon-plus-sign"></span> Add</button> + <button class="btn btn-default" id="add" disabled><span class="glyphicon glyphicon-plus-sign"></span> Add</button> <button class="btn btn-default"><span class="glyphicon glyphicon-download"></span> Download Table</button> <button id="redraw" class="btn btn-default">Reset Columns</button> + <input type="text" id="searchbox" class="form-control" style="width: 200px; display: inline;" placeholder="Search This Table For ..."> + <input type="text" id="select_top" class="form-control" style="width: 200px; display: inline;" placeholder="Select Top ..."> <br /> <br /> <div id="table_container"> <table class="table table-hover table-striped" id='trait_table' {% if dataset.type == 'Geno' %}width="400px"{% endif %} style="float: left;"> <thead> <tr> + <th style="width: 30px;"></th> {% for header in header_fields %} {% if header == 'Max LRS' %} <th style="text-align: right;">Max <br>LRS<a href="http://genenetwork.org//glossary.html#L" target="_blank"><sup style="color:#f00"> ?</sup></a></th> @@ -67,10 +70,9 @@ <tbody> {% for this_trait in trait_list %} <TR id="trait:{{ this_trait.name }}:{{ this_trait.dataset.name }}"> - <TD>{{ loop.index }} - <INPUT TYPE="checkbox" NAME="searchResult" class="checkbox trait_checkbox" - VALUE="{{ data_hmac('{}:{}'.format(this_trait.name, this_trait.dataset.name)) }}"> + <TD><INPUT TYPE="checkbox" NAME="searchResult" class="checkbox trait_checkbox" style="transform: scale(1.5);" VALUE="{{ data_hmac('{}:{}'.format(this_trait.name, this_trait.dataset.name)) }}"> </TD> + <TD>{{ loop.index }}</TD> <TD> <a href="{{ url_for('show_trait_page', trait_id = this_trait.name, @@ -181,6 +183,7 @@ { "type": "natural" }, { "type": "natural" }, { "type": "natural" }, + { "type": "natural" }, { "type": "natural", "width": "30%" }, { "type": "natural", "width": "15%" }, { "type": "natural" }, @@ -188,19 +191,16 @@ { "type": "natural", "width": "15%" }, { "type": "natural" } ], - "sDom": "RJtir", + "sDom": "RZtir", "iDisplayLength": -1, "autoWidth": false, - "bLengthChange": true, "bDeferRender": true, "bSortClasses": false, "scrollY": "700px", "scrollCollapse": false, - "colResize": { - "tableWidthFixed": false, - }, "paging": false } ); + {% elif dataset.type == 'Publish' %} $('#trait_table').DataTable( { "columns": [ @@ -210,20 +210,17 @@ { "type": "natural" }, { "type": "natural" }, { "type": "natural" }, + { "type": "natural" }, { "type": "natural", "width": "15%"}, { "type": "natural" } ], - "sDom": "RJtir", + "sDom": "RZtir", "iDisplayLength": -1, "autoWidth": false, - "bLengthChange": true, "bDeferRender": true, "bSortClasses": false, "scrollY": "700px", "scrollCollapse": false, - "colResize": { - "tableWidthFixed": false, - }, "paging": false } ); {% elif dataset.type == 'Geno' %} @@ -231,19 +228,16 @@ "columns": [ { "type": "natural" }, { "type": "natural" }, + { "type": "natural" }, { "type": "natural", "width": "40%"} ], - "sDom": "RJtir", + "sDom": "RZtir", "iDisplayLength": -1, - "autoWidth": false, - "bLengthChange": true, + "autoWidth": true, "bDeferRender": true, "bSortClasses": false, "scrollY": "700px", "scrollCollapse": false, - "colResize": { - "tableWidthFixed": false, - }, "paging": false } ); {% endif %} diff --git a/wqflask/wqflask/templates/show_trait.html b/wqflask/wqflask/templates/show_trait.html index 40f6eafd..6199f931 100755 --- a/wqflask/wqflask/templates/show_trait.html +++ b/wqflask/wqflask/templates/show_trait.html @@ -13,8 +13,6 @@ <link rel="stylesheet" type="text/css" href="/static/new/packages/DataTables/css/jquery.dataTables.css" /> <link rel="stylesheet" type="text/css" href="/static/packages/DT_bootstrap/DT_bootstrap.css" /> <link rel="stylesheet" type="text/css" href="/static/packages/TableTools/media/css/TableTools.css" /> - <link rel="stylesheet" type="text/css" href="/static/new/packages/DataTables/extensions/dataTables.fixedHeader.css" > - <link rel="stylesheet" type="text/css" href="//cdn.datatables.net/fixedcolumns/3.0.4/css/dataTables.fixedColumns.css"> {% endblock %} {% block content %} <!-- Start of body --> @@ -82,6 +80,7 @@ <div class="panel-body"> {% include 'show_trait_mapping_tools.html' %} </div> + <div id="alert_placeholder"></div> </div> </div> <div class="panel panel-default"> @@ -150,8 +149,6 @@ <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/dataTables.naturalSort.js"></script> <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.colResize.js"></script> <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.colReorder.js"></script> - <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.fixedHeader.js"></script> - <script language="javascript" type="text/javascript" src="//cdn.datatables.net/fixedcolumns/3.0.4/js/dataTables.fixedColumns.min.js"></script> <script language="javascript" type="text/javascript" src="/static/packages/DT_bootstrap/DT_bootstrap.js"></script> <script language="javascript" type="text/javascript" src="/static/packages/TableTools/media/js/TableTools.min.js"></script> <script type="text/javascript" charset="utf-8"> @@ -212,7 +209,7 @@ { "bSortable": false }, { "type": "cust-txt" } ], - "sDom": "RJtir", + "sDom": "RZtir", "oTableTools": { "aButtons": [ "copy", @@ -248,7 +245,7 @@ null, { "type": "cust-txt" } ], - "sDom": "RJtir", + "sDom": "RZtir", "oTableTools": { "aButtons": [ "copy", diff --git a/wqflask/wqflask/templates/show_trait_edit_data.html b/wqflask/wqflask/templates/show_trait_edit_data.html index 5c7b0417..ca8e02de 100755 --- a/wqflask/wqflask/templates/show_trait_edit_data.html +++ b/wqflask/wqflask/templates/show_trait_edit_data.html @@ -81,12 +81,12 @@ <table class="table-hover table-striped" id="samples_{{ sample_type.sample_group_type }}" style="float: left;"> <thead> <tr> - <th>Index</td> - <th>Sample</td> - <th>Value</td> + <th>Index</th> + <th>Sample</th> + <th>Value</th> {% if sample_type.se_exists() %} - <th> </td> - <th>SE</td> + <th> </th> + <th>SE</th> {% endif %} {% for attribute in sample_type.attributes|sort() %} <th> diff --git a/wqflask/wqflask/templates/show_trait_mapping_tools.html b/wqflask/wqflask/templates/show_trait_mapping_tools.html index 6f69bcfa..eea9b295 100755 --- a/wqflask/wqflask/templates/show_trait_mapping_tools.html +++ b/wqflask/wqflask/templates/show_trait_mapping_tools.html @@ -35,7 +35,7 @@ <div class="mapping_method_fields form-group"> <label for="mapping_permutations" class="col-xs-2 control-label">Permutations</label> <div style="margin-left: 20px;" class="col-xs-4 controls"> - <input name="num_pylmm" value="2000" type="text" class="form-control"> + <input name="num_pylmm" value="" type="text" class="form-control"> </div> </div> <div id="permutations_alert" class="alert alert-error alert-warning" style="display:none;"> @@ -211,6 +211,7 @@ </button> </div> </div> + <!--<div id="alert_placeholder"></div>--> </div> </div> {% endif %} @@ -268,7 +269,6 @@ <dd>R/qtl is an extensible, interactive environment for mapping quantitative trait loci (QTL) in experimental crosses.</dd> </dl> </div> - <div id="alert_placeholder"></div> <div id="mapping_result_holder_wrapper" style="display:none;"> <div id="mapping_result_holder"></div> </div> |