diff options
author | zsloan | 2021-10-18 12:29:09 -0500 |
---|---|---|
committer | GitHub | 2021-10-18 12:29:09 -0500 |
commit | 04f3d13aceeaec2e52b94037d59f08ed6dc6a8bb (patch) | |
tree | 70745f7f26fda1b14be5904877f2b4439d52fff6 | |
parent | 631301a0888a16123283b382483e2b229a64e804 (diff) | |
parent | 35105c816726b58dc376b2c3925d48077aeca675 (diff) | |
download | genenetwork2-04f3d13aceeaec2e52b94037d59f08ed6dc6a8bb.tar.gz |
Merge pull request #562 from zsloan/feature/add_resizeable_columns
Add Resizeable Table Columns
-rw-r--r-- | wqflask/wqflask/search_results.py | 19 | ||||
-rw-r--r-- | wqflask/wqflask/static/new/css/show_trait.css | 1 | ||||
-rw-r--r-- | wqflask/wqflask/static/new/css/trait_list.css | 1 | ||||
-rw-r--r-- | wqflask/wqflask/static/new/javascript/initialize_show_trait_tables.js | 219 | ||||
-rw-r--r-- | wqflask/wqflask/static/new/javascript/table_functions.js | 88 | ||||
-rw-r--r-- | wqflask/wqflask/templates/base.html | 3 | ||||
-rw-r--r-- | wqflask/wqflask/templates/gsearch_gene.html | 349 | ||||
-rw-r--r-- | wqflask/wqflask/templates/gsearch_pheno.html | 427 | ||||
-rw-r--r-- | wqflask/wqflask/templates/search_result_page.html | 429 | ||||
-rw-r--r-- | wqflask/wqflask/templates/show_trait.html | 21 | ||||
-rw-r--r-- | wqflask/wqflask/templates/show_trait_edit_data.html | 6 |
11 files changed, 922 insertions, 641 deletions
diff --git a/wqflask/wqflask/search_results.py b/wqflask/wqflask/search_results.py index 3cbda3dd..78d30ba1 100644 --- a/wqflask/wqflask/search_results.py +++ b/wqflask/wqflask/search_results.py @@ -101,7 +101,6 @@ class SearchResultPage: self.dataset.group.name) # result_set represents the results for each search term; a search of # "shh grin2b" would have two sets of results, one for each term - logger.debug("self.results is:", pf(self.results)) for index, result in enumerate(self.results): if not result: @@ -169,6 +168,24 @@ class SearchResultPage: trait_dict[key] = trait_dict[key].decode('utf-8') trait_list.append(trait_dict) + if self.results: + self.max_widths = {} + for i, trait in enumerate(trait_list): + for key in trait.keys(): + if key == "authors": + authors_string = ",".join(str(trait[key]).split(",")[:6]) + ", et al." + self.max_widths[key] = max(len(authors_string), self.max_widths[key]) if key in self.max_widths else len(str(trait[key])) + else: + self.max_widths[key] = max(len(str(trait[key])), self.max_widths[key]) if key in self.max_widths else len(str(trait[key])) + + self.wide_columns_exist = False + if this_trait.dataset.type == "Publish": + if (self.max_widths['display_name'] > 25 or self.max_widths['description'] > 100 or self.max_widths['authors']> 80): + self.wide_columns_exist = True + if this_trait.dataset.type == "ProbeSet": + if (self.max_widths['display_name'] > 25 or self.max_widths['symbol'] > 25 or self.max_widths['description'] > 100): + self.wide_columns_exist = True + self.trait_list = trait_list if self.dataset.type == "ProbeSet": diff --git a/wqflask/wqflask/static/new/css/show_trait.css b/wqflask/wqflask/static/new/css/show_trait.css index b0514e01..f5e8c22a 100644 --- a/wqflask/wqflask/static/new/css/show_trait.css +++ b/wqflask/wqflask/static/new/css/show_trait.css @@ -250,7 +250,6 @@ div.export-code-container { table.sample-table { float: left; - width:100%; } input.trait-value-input { diff --git a/wqflask/wqflask/static/new/css/trait_list.css b/wqflask/wqflask/static/new/css/trait_list.css index c7249721..ce3075d4 100644 --- a/wqflask/wqflask/static/new/css/trait_list.css +++ b/wqflask/wqflask/static/new/css/trait_list.css @@ -51,4 +51,3 @@ div.dts div.dataTables_scrollBody table { div.dts div.dataTables_paginate,div.dts div.dataTables_length{ display:none } - diff --git a/wqflask/wqflask/static/new/javascript/initialize_show_trait_tables.js b/wqflask/wqflask/static/new/javascript/initialize_show_trait_tables.js index 0a060cdc..96ef7a04 100644 --- a/wqflask/wqflask/static/new/javascript/initialize_show_trait_tables.js +++ b/wqflask/wqflask/static/new/javascript/initialize_show_trait_tables.js @@ -15,6 +15,8 @@ build_columns = function() { 'data': null, 'orderDataType': "dom-checkbox", 'searchable' : false, + 'targets': 0, + 'width': "25px", 'render': function(data, type, row, meta) { return '<input type="checkbox" name="searchResult" class="checkbox edit_sample_checkbox" value="">' } @@ -23,12 +25,16 @@ build_columns = function() { 'title': "ID", 'type': "natural", 'searchable' : false, + 'targets': 1, + 'width': "35px", 'data': "this_id" }, { 'title': "Sample", 'type': "natural", 'data': null, + 'targets': 2, + 'width': "60px", 'render': function(data, type, row, meta) { return '<span class="edit_sample_sample_name">' + data.name + '</span>' } @@ -38,6 +44,8 @@ build_columns = function() { 'orderDataType': "dom-input", 'type': "cust-txt", 'data': null, + 'targets': 3, + 'width': "60px", 'render': function(data, type, row, meta) { if (data.value == null) { return '<input type="text" data-value="x" data-qnorm="x" data-zscore="x" name="value:' + data.name + '" style="text-align: right;" class="trait_value_input edit_sample_value" value="x" size=' + js_data.max_digits[0] + '>' @@ -48,13 +56,17 @@ build_columns = function() { } ]; + attr_start = 4 if (js_data.se_exists) { + attr_start += 2 column_list.push( { 'bSortable': false, 'type': "natural", 'data': null, + 'targets': 4, 'searchable' : false, + 'width': "25px", 'render': function(data, type, row, meta) { return '±' } @@ -64,6 +76,8 @@ build_columns = function() { 'orderDataType': "dom-input", 'type': "cust-txt", 'data': null, + 'targets': 5, + 'width': "60px", 'render': function(data, type, row, meta) { if (data.variance == null) { return '<input type="text" data-value="x" data-qnorm="x" data-zscore="x" name="value:' + data.name + '" class="trait_value_input edit_sample_se" value="x" size=6>' @@ -73,24 +87,49 @@ build_columns = function() { } } ); - } - if (js_data.has_num_cases === true) { - column_list.push( - { - 'title': "<div style='text-align: right;'>N</div>", - 'orderDataType': "dom-input", - 'type': "cust-txt", - 'data': null, - 'render': function(data, type, row, meta) { - if (data.num_cases == null || data.num_cases == undefined) { - return '<input type="text" data-value="x" data-qnorm="x" data-zscore="x" name="value:' + data.name + '" class="trait_value_input edit_sample_num_cases" value="x" size=4 maxlength=4>' - } else { - return '<input type="text" data-value="' + data.num_cases + '" data-qnorm="x" data-zscore="x" name="value:' + data.name + '" class="trait_value_input edit_sample_num_cases" value="' + data.num_cases + '" size=4 maxlength=4>' + if (js_data.has_num_cases === true) { + attr_start += 1 + column_list.push( + { + 'title': "<div style='text-align: right;'>N</div>", + 'orderDataType': "dom-input", + 'type': "cust-txt", + 'data': null, + 'targets': 6, + 'width': "60px", + 'render': function(data, type, row, meta) { + if (data.num_cases == null || data.num_cases == undefined) { + return '<input type="text" data-value="x" data-qnorm="x" data-zscore="x" name="value:' + data.name + '" class="trait_value_input edit_sample_num_cases" value="x" size=4 maxlength=4>' + } else { + return '<input type="text" data-value="' + data.num_cases + '" data-qnorm="x" data-zscore="x" name="value:' + data.name + '" class="trait_value_input edit_sample_num_cases" value="' + data.num_cases + '" size=4 maxlength=4>' + } } } - } - ); + ); + } + } + else { + if (js_data.has_num_cases === true) { + attr_start += 1 + column_list.push( + { + 'title': "<div style='text-align: right;'>N</div>", + 'orderDataType': "dom-input", + 'type': "cust-txt", + 'data': null, + 'targets': 4, + 'width': "60px", + 'render': function(data, type, row, meta) { + if (data.num_cases == null || data.num_cases == undefined) { + return '<input type="text" data-value="x" data-qnorm="x" data-zscore="x" name="value:' + data.name + '" class="trait_value_input edit_sample_num_cases" value="x" size=4 maxlength=4>' + } else { + return '<input type="text" data-value="' + data.num_cases + '" data-qnorm="x" data-zscore="x" name="value:' + data.name + '" class="trait_value_input edit_sample_num_cases" value="' + data.num_cases + '" size=4 maxlength=4>' + } + } + } + ); + } } attr_keys = Object.keys(js_data.attributes).sort((a, b) => (js_data.attributes[a].id > js_data.attributes[b].id) ? 1 : -1) @@ -100,6 +139,7 @@ build_columns = function() { 'title': "<div title='" + js_data.attributes[attr_keys[i]].description + "' style='text-align: " + js_data.attributes[attr_keys[i]].alignment + "'>" + js_data.attributes[attr_keys[i]].name + "</div>", 'type': "natural", 'data': null, + 'targets': attr_start + i, 'render': function(data, type, row, meta) { attr_name = Object.keys(data.extra_attributes).sort((a, b) => (parseInt(a) > parseInt(b)) ? 1 : -1)[meta.col - data.first_attr_col] @@ -119,14 +159,35 @@ build_columns = function() { return column_list } -var primary_table = $('#samples_primary').DataTable( { +columnDefs = build_columns() + +loadDataTable(first_run=true, table_id="samples_primary", table_data=js_data['sample_lists'][0]) +if (js_data.sample_lists.length > 1){ + loadDataTable(first_run=true, table_id="samples_other", table_data=js_data['sample_lists'][1]) +} + +function loadDataTable(first_run=false, table_id, table_data){ + + console.log("COL DEFS:", columnDefs) + + if (!first_run){ + setUserColumnsDefWidths(table_id); + } + + if (table_id == "samples_primary"){ + table_type = "Primary" + } else { + table_type = "Other" + } + + table_settings = { 'initComplete': function(settings, json) { $('.edit_sample_value').change(function() { edit_data_change(); }); }, 'createdRow': function ( row, data, index ) { - $(row).attr('id', "Primary_" + data.this_id) + $(row).attr('id', table_type + "_" + data.this_id) $(row).addClass("value_se"); if (data.outlier) { $(row).addClass("outlier"); @@ -155,76 +216,80 @@ var primary_table = $('#samples_primary').DataTable( { $('td', row).eq(attribute_start_pos + i + 1).attr("style", "text-align: " + js_data.attributes[attr_keys[i]].alignment + "; padding-top: 2px; padding-bottom: 0px;") } }, - 'data': js_data['sample_lists'][0], - 'columns': build_columns(), - 'order': [[1, "asc"]], - 'sDom': "Ztr", - 'autoWidth': true, - 'orderClasses': true, + 'data': table_data, + 'columns': columnDefs, + "order": [[1, "asc" ]], + "sDom": "iti", + "destroy": true, + "autoWidth": false, + "deferRender": true, + "bSortClasses": false, "scrollY": "100vh", - 'scroller': true, - 'scrollCollapse': true -} ); + "scrollCollapse": true, + "scroller": true, + "iDisplayLength": -1, + "initComplete": function (settings) { + //Add JQueryUI resizable functionality to each th in the ScrollHead table + $('#' + table_id + '_wrapper .dataTables_scrollHead thead th').resizable({ + handles: "e", + alsoResize: '#' + table_id + '_wrapper .dataTables_scrollHead table', //Not essential but makes the resizing smoother + resize: function( event, ui ) { + width_change = ui.size.width - ui.originalSize.width; + }, + stop: function () { + saveColumnSettings(table_id, the_table); + loadDataTable(first_run=false, table_id, table_data); + } + }); + } + } + + if (!first_run){ + $('#' + table_type.toLowerCase() + '_container').css("width", String($('#' + table_id).width() + width_change + 17) + "px"); //ZS : Change the container width by the change in width of the adjusted column, so the overall table size adjusts properly -primary_table.draw(); //ZS: This makes the table adjust its height properly on initial load + let checked_rows = get_checked_rows(table_id); + the_table = $('#' + table_id).DataTable(table_settings); + if (checked_rows.length > 0){ + recheck_rows(the_table, checked_rows); + } + } else { + the_table = $('#' + table_id).DataTable(table_settings); + the_table.draw(); + } -primary_table.on( 'order.dt search.dt draw.dt', function () { - primary_table.column(1, {search:'applied', order:'applied'}).nodes().each( function (cell, i) { + the_table.on( 'order.dt search.dt draw.dt', function () { + the_table.column(1, {search:'applied', order:'applied'}).nodes().each( function (cell, i) { cell.innerHTML = i+1; } ); -} ).draw(); + } ).draw(); -$('#primary_searchbox').on( 'keyup', function () { - primary_table.search($(this).val()).draw(); -} ); + if (first_run){ + $('#' + table_type.toLowerCase() + '_container').css("width", String($('#' + table_id).width() + 17) + "px"); + } -if (js_data.sample_lists.length > 1){ - var other_table = $('#samples_other').DataTable( { - 'initComplete': function(settings, json) { - $('.edit_sample_value').change(function() { - edit_data_change(); - }); - }, - 'createdRow': function ( row, data, index ) { - $(row).attr('id', "Primary_" + data.this_id) - $(row).addClass("value_se"); - if (data.outlier) { - $(row).addClass("outlier"); - $(row).attr("style", "background-color: orange;"); - } - $('td', row).eq(1).addClass("column_name-Index") - $('td', row).eq(2).addClass("column_name-Sample") - $('td', row).eq(3).addClass("column_name-Value") - if (js_data.se_exists) { - $('td', row).eq(5).addClass("column_name-SE") - if (js_data.has_num_cases === true) { - $('td', row).eq(6).addClass("column_name-num_cases") - } else { - if (js_data.has_num_cases === true) { - $('td', row).eq(4).addClass("column_name-num_cases") - } - } + $('#' + table_type.toLowerCase() + '_searchbox').on( 'keyup', function () { + the_table.search($(this).val()).draw(); + } ); + + $('.toggle-vis').on('click', function (e) { + e.preventDefault(); + + function toggle_column(column) { + //ZS: Toggle column visibility + column.visible( ! column.visible() ); + if (column.visible()){ + $(this).removeClass("active"); } else { - if (js_data.has_num_cases === true) { - $('td', row).eq(4).addClass("column_name-num_cases") - } + $(this).addClass("active"); } + } - for (i=0; i < attr_keys.length; i++) { - $('td', row).eq(attribute_start_pos + i + 1).addClass("column_name-" + js_data.attributes[attr_keys[i]].name) - $('td', row).eq(attribute_start_pos + i + 1).attr("style", "text-align: " + js_data.attributes[attr_keys[i]].alignment + "; padding-top: 2px; padding-bottom: 0px;") - } - }, - 'data': js_data['sample_lists'][1], - 'columns': build_columns(), - 'order': [[1, "asc"]], - 'sDom': "Ztr", - 'autoWidth': true, - 'orderClasses': true, - "scrollY": "100vh", - 'scroller': true, - 'scrollCollapse': true + // Get the column API object + var target_cols = $(this).attr('data-column').split(",") + for (let i = 0; i < target_cols.length; i++){ + var column = the_table.column( target_cols[i] ); + toggle_column(column); + } } ); - other_table.draw(); //ZS: This makes the table adjust its height properly on initial load } diff --git a/wqflask/wqflask/static/new/javascript/table_functions.js b/wqflask/wqflask/static/new/javascript/table_functions.js new file mode 100644 index 00000000..745563c2 --- /dev/null +++ b/wqflask/wqflask/static/new/javascript/table_functions.js @@ -0,0 +1,88 @@ +recheck_rows = function(the_table, checked_rows){ + //ZS: This is meant to recheck checkboxes after columns are resized + check_cells = the_table.column(0).nodes().to$(); + for (let i = 0; i < check_cells.length; i++) { + if (checked_rows.includes(i)){ + check_cells[i].childNodes[0].checked = true; + } + } + + check_rows = trait_table.rows().nodes(); + for (let i =0; i < check_rows.length; i++) { + if (checked_rows.includes(i)){ + check_rows[i].classList.add("selected") + } + } +} + +get_checked_rows = function(table_id){ + let checked_rows = [] + $("#" + table_id + " input").each(function(index){ + if ($(this).prop("checked") == true){ + checked_rows.push(index); + } + }); + + return checked_rows +} + +function setUserColumnsDefWidths(table_id) { + var userColumnDef; + + // Get the settings for this table from localStorage + var userColumnDefs = JSON.parse(localStorage.getItem(table_id)) || []; + + if (userColumnDefs.length === 0 ) return; + + columnDefs.forEach( function(columnDef) { + // Check if there is a width specified for this column + userColumnDef = userColumnDefs.find( function(column) { + return column.targets === columnDef.targets; + }); + + // If there is, set the width of this columnDef in px + if ( userColumnDef ) { + + columnDef.sWidth = userColumnDef.width + 'px'; + columnDef.width = userColumnDef.width + 'px'; + + $('.toggle-vis').each(function(){ + if ($(this).attr('data-column') == columnDef.targets){ + if ($(this).hasClass("active")){ + columnDef.bVisible = false + } else { + columnDef.bVisible = true + } + } + }) + } + }); +} + +function saveColumnSettings(table_id, trait_table) { + var userColumnDefs = JSON.parse(localStorage.getItem(table_id)) || []; + var width, header, existingSetting; + + trait_table.columns().every( function ( targets ) { + // Check if there is a setting for this column in localStorage + existingSetting = userColumnDefs.findIndex( function(column) { return column.targets === targets;}); + + // Get the width of this column + header = this.header(); + width = $(header).width(); + + if ( existingSetting !== -1 ) { + // Update the width + userColumnDefs[existingSetting].width = width; + } else { + // Add the width for this column + userColumnDefs.push({ + targets: targets, + width: width, + }); + } + }); + + // Save (or update) the settings in localStorage + localStorage.setItem(table_id, JSON.stringify(userColumnDefs)); +} diff --git a/wqflask/wqflask/templates/base.html b/wqflask/wqflask/templates/base.html index 14e6bc88..d30c575a 100644 --- a/wqflask/wqflask/templates/base.html +++ b/wqflask/wqflask/templates/base.html @@ -256,7 +256,8 @@ }) </script> <script src="{{ url_for('js', filename='jquery-cookie/jquery.cookie.js') }}" type="text/javascript"></script> - <script src="{{ url_for('js', filename='jquery-ui/jquery-ui.min.js') }}" type="text/javascript"></script> + <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script> + <!-- <script src="{{ url_for('js', filename='jquery-ui/jquery-ui.min.js') }}" type="text/javascript"></script> --> <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='colorbox/jquery.colorbox-min.js') }}"></script> diff --git a/wqflask/wqflask/templates/gsearch_gene.html b/wqflask/wqflask/templates/gsearch_gene.html index 5549ac8a..69281ec5 100644 --- a/wqflask/wqflask/templates/gsearch_gene.html +++ b/wqflask/wqflask/templates/gsearch_gene.html @@ -2,6 +2,7 @@ {% block title %}Search Results{% endblock %} {% block css %} <link rel="stylesheet" type="text/css" href="{{ url_for('css', filename='DataTables/css/jquery.dataTables.css') }}" /> + <link href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet" type="text/css" /> <link rel="stylesheet" type="text/css" href="/static/new/css/show_trait.css" /> {% endblock %} {% block content %} @@ -31,7 +32,7 @@ </form> <br /> <br /> - <div style="min-width: 2000px; width: 100%;"> + <div id="table_container" style="width: 2000px;"> <table id="trait_table" class="table-hover table-striped cell-border" style="float: left;"> <tbody> <td colspan="100%" align="center"><br><b><font size="15">Loading...</font></b><br></td> @@ -54,6 +55,7 @@ <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='DataTablesExtensions/colReorder/js/dataTables.colReorder.js') }}"></script> <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='DataTablesExtensions/colResize/dataTables.colResize.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/javascript/table_functions.js"></script> <script type='text/javascript'> var getParams = function(url) { @@ -73,51 +75,152 @@ <script type="text/javascript" charset="utf-8"> $(document).ready( function () { - - $('#trait_table tr').click(function(event) { - if (event.target.type !== 'checkbox') { - $(':checkbox', this).trigger('click'); - } - }); + var tableId = "trait_table"; - function change_buttons() { - buttons = ["#add", "#remove"]; - num_checked = $('.trait_checkbox:checked').length; - if (num_checked === 0) { - for (_i = 0, _len = buttons.length; _i < _len; _i++) { - button = buttons[_i]; - $(button).prop("disabled", true); - } - } else { - for (_j = 0, _len2 = buttons.length; _j < _len2; _j++) { - button = buttons[_j]; - $(button).prop("disabled", false); - } + var width_change = 0; //ZS: For storing the change in width so overall table width can be adjusted by that amount + + columnDefs = [ + { + 'orderDataType': "dom-checkbox", + 'width': "5px", + 'data': null, + 'targets': 0, + 'render': function(data, type, row, meta) { + return '<input type="checkbox" name="searchResult" class="trait_checkbox checkbox" value="' + data.hmac + '">' } - //}); - if ($(this).is(":checked")) { - if (!$(this).closest('tr').hasClass('selected')) { - $(this).closest('tr').addClass('selected') - } + }, + { + 'title': "Index", + 'type': "natural", + 'width': "30px", + 'targets': 1, + 'data': "index" + }, + { + 'title': "Record", + 'type': "natural", + 'orderDataType': "dom-inner-text", + 'width': "60px", + 'data': null, + 'targets': 2, + 'render': function(data, type, row, meta) { + return '<a target="_blank" href="/show_trait?trait_id=' + data.name + '&dataset=' + data.dataset + '">' + data.name + '</a>' } - else { - if ($(this).closest('tr').hasClass('selected')) { - $(this).closest('tr').removeClass('selected') - } + }, + { + 'title': "Species", + 'type': "natural", + 'width': "60px", + 'targets': 3, + 'data': "species" + }, + { + 'title': "Group", + 'type': "natural", + 'width': "150px", + 'targets': 4, + 'data': "group" + }, + { + 'title': "Tissue", + 'type': "natural", + 'width': "150px", + 'targets': 5, + 'data': "tissue" + }, + { + 'title': "Dataset", + 'type': "natural", + 'targets': 6, + 'width': "320px", + 'data': "dataset_fullname" + }, + { + 'title': "Symbol", + 'type': "natural", + 'width': "60px", + 'targets': 7, + 'data': "symbol" + }, + { + 'title': "Description", + 'type': "natural", + 'data': null, + 'width': "120px", + 'targets': 8, + 'render': function(data, type, row, meta) { + try { + return decodeURIComponent(escape(data.description)) + } catch(err) { + return escape(data.description) + } } - } + }, + { + 'title': "Location", + 'type': "natural-minus-na", + 'width': "125px", + 'targets': 9, + 'data': "location_repr" + }, + { + 'title': "Mean", + 'type': "natural-minus-na", + 'orderSequence': [ "desc", "asc"], + 'width': "30px", + 'targets': 10, + 'data': "mean" + }, + { + 'title': "Max<br>LRS<a href=\"{{ url_for('glossary_blueprint.glossary') }}#LRS\" target=\"_blank\" style=\"color: white;\"><sup>?</sup></a>", + 'type': "natural-minus-na", + 'width': "60px", + 'targets': 11, + 'data': "LRS_score_repr", + 'orderSequence': [ "desc", "asc"] + }, + { + 'title': "Max LRS Location", + 'type': "natural-minus-na", + 'width': "125px", + 'targets': 12, + 'data': "max_lrs_text" + }, + { + 'title': "Additive<br>Effect<a href=\"{{ url_for('glossary_blueprint.glossary') }}#A\" target=\"_blank\" style=\"color: white;\"><sup>?</sup></a>", + 'type': "natural-minus-na", + 'width': "50px", + 'targets': 13, + 'data': "additive", + 'orderSequence': [ "desc", "asc"] + } + ] + + loadDataTable(true); - var the_table = $('#trait_table').DataTable( { + function loadDataTable(first_run=false){ + + if (!first_run){ + setUserColumnsDefWidths(tableId); + } + + table_settings = { 'drawCallback': function( settings ) { - $('#trait_table tr').click(function(event) { - if (event.target.type !== 'checkbox' && event.target.tagName.toLowerCase() !== 'a') { - $(':checkbox', this).trigger('click'); - } - }); - $('.trait_checkbox:checkbox').on("change", change_buttons); + $('#' + tableId + ' tr').off().on("click", function(event) { + if (event.target.type !== 'checkbox' && event.target.tagName.toLowerCase() !== 'a') { + var obj =$(this).find('input'); + obj.prop('checked', !obj.is(':checked')); + } + if ($(this).hasClass("selected") && event.target.tagName.toLowerCase() !== 'a'){ + $(this).removeClass("selected") + } else if (event.target.tagName.toLowerCase() !== 'a') { + $(this).addClass("selected") + } + change_buttons() + }); }, 'createdRow': function ( row, data, index ) { - $('td', row).eq(0).attr("style", "text-align: center; padding: 0px 10px 2px 13px;"); + $('td', row).eq(0).attr("style", "text-align: center; padding: 0px 10px 2px 10px;"); $('td', row).eq(1).attr("align", "right"); $('td', row).eq(4).attr('title', $('td', row).eq(4).text()); if ($('td', row).eq(4).text().length > 30) { @@ -155,144 +258,60 @@ $('td', row).eq(13).attr('data-export', $('td', row).eq(13).text()); }, 'data': trait_list, - 'columns': [ - { - 'orderDataType': "dom-checkbox", - 'width': "10px", - 'data': null, - 'render': function(data, type, row, meta) { - return '<input type="checkbox" name="searchResult" class="trait_checkbox checkbox" value="' + data.hmac + '">' - } - }, - { - 'title': "Index", - 'type': "natural", - 'width': "30px", - 'data': "index" - }, - { - 'title': "Record", - 'type': "natural", - 'orderDataType': "dom-inner-text", - 'width': "60px", - 'data': null, - 'render': function(data, type, row, meta) { - return '<a target="_blank" href="/show_trait?trait_id=' + data.name + '&dataset=' + data.dataset + '">' + data.name + '</a>' - } - }, - { - 'title': "Species", - 'type': "natural", - 'width': "60px", - 'data': "species" - }, - { - 'title': "Group", - 'type': "natural", - 'width': "150px", - 'data': "group" - }, - { - 'title': "Tissue", - 'type': "natural", - 'width': "150px", - 'data': "tissue" - }, - { - 'title': "Dataset", - 'type': "natural", - 'data': "dataset_fullname" - }, - { - 'title': "Symbol", - 'type': "natural", - 'width': "60px", - 'data': "symbol" - }, - { - 'title': "Description", - 'type': "natural", - 'data': null, - 'render': function(data, type, row, meta) { - try { - return decodeURIComponent(escape(data.description)) - } catch(err) { - return escape(data.description) - } - } - }, - { - 'title': "Location", - 'type': "natural-minus-na", - 'width': "125px", - 'data': "location_repr" - }, - { - 'title': "Mean", - 'type': "natural-minus-na", - 'orderSequence': [ "desc", "asc"], - 'width': "30px", - 'data': "mean" - }, - { - 'title': "Max<br>LRS<a href=\"{{ url_for('glossary_blueprint.glossary') }}#LRS\" target=\"_blank\" style=\"color: white;\"><sup>?</sup></a>", - 'type': "natural-minus-na", - 'width': "60px", - 'data': "LRS_score_repr", - 'orderSequence': [ "desc", "asc"] - }, - { - 'title': "Max LRS Location", - 'type': "natural-minus-na", - 'width': "125px", - 'data': "max_lrs_text" - }, - { - 'title': "Additive<br>Effect<a href=\"{{ url_for('glossary_blueprint.glossary') }}#A\" target=\"_blank\" style=\"color: white;\"><sup>?</sup></a>", - 'type': "natural-minus-na", - 'width': "50px", - 'data': "additive", - 'orderSequence': [ "desc", "asc"] - } - ], + 'columns': columnDefs, "order": [[1, "asc" ]], 'sDom': "iti", - "autoWidth": true, + "destroy": true, + "deferRender": true, "bSortClasses": false, - 'processing': true, {% if trait_count > 20 %} "scrollY": "100vh", "scroller": true, - "scrollCollapse": true + "scrollCollapse": true, {% else %} - "iDisplayLength": -1 + "iDisplayLength": -1, {% endif %} - } ); + "initComplete": function (settings) { + //Add JQueryUI resizable functionality to each th in the ScrollHead table + $('#' + tableId + '_wrapper .dataTables_scrollHead thead th').resizable({ + handles: "e", + alsoResize: '#' + tableId + '_wrapper .dataTables_scrollHead table', //Not essential but makes the resizing smoother + resize: function( event, ui ) { + width_change = ui.size.width - ui.originalSize.width; + }, + stop: function () { + saveColumnSettings(tableId, trait_table); + loadDataTable(); + } + }); + } + } - $('#trait_table').append( - '<tfoot>' + - '<tr>' + - '<th></th>' + - '<th>Index</th>' + - '<th>Record ID</th>' + - '<th>Species</th> ' + - '<th>Group</th>' + - '<th>Tissue</th>' + - '<th>Dataset</th>' + - '<th>Symbol</th>' + - '<th>Description</th>' + - '<th>Location</th>' + - '<th>Mean</th>' + - '<th>Max LRS <a href="{{ url_for('glossary_blueprint.glossary') }}#LRS" target="_blank" style="color: white;"><sup>?</sup></a></th>' + - '<th>Max LRS Location</th>' + - '<th>Additive Effect <a href="{{ url_for('glossary_blueprint.glossary') }}#A" target="_blank" style="color: white;"><sup>?</sup></a></th>' + - '</tr>' + - '</tfoot>' - ); + if (!first_run){ + table_settings['autoWidth'] = false; + $('#table_container').css("width", String($('#trait_table').width() + width_change {% if trait_list|length > 20 %}+ 17{% endif %}) + "px"); //ZS : Change the container width by the change in width of the adjusted column, so the overall table size adjusts properly + } + + let checked_rows = get_checked_rows(tableId); + trait_table = $('#' + tableId).DataTable(table_settings); + if (checked_rows.length > 0){ + recheck_rows(trait_table, checked_rows); + } + + if (first_run){ + {% if trait_list|length > 20 %} + $('#table_container').css("width", String($('#trait_table').width() + 17) + "px"); + {% endif %} + trait_table.draw(); + } + } + + $('#redraw').click(function() { + var table = $('#' + tableId).DataTable(); + table.colReorder.reset() + }); - the_table.draw(); }); </script> - <script language="javascript" type="text/javascript" src="/static/new/javascript/search_results.js"></script> {% endblock %} diff --git a/wqflask/wqflask/templates/gsearch_pheno.html b/wqflask/wqflask/templates/gsearch_pheno.html index 89316cbc..7abdb222 100644 --- a/wqflask/wqflask/templates/gsearch_pheno.html +++ b/wqflask/wqflask/templates/gsearch_pheno.html @@ -2,6 +2,7 @@ {% block title %}Search Results{% endblock %} {% block css %} <link rel="stylesheet" type="text/css" href="{{ url_for('css', filename='DataTables/css/jquery.dataTables.css') }}" /> + <link href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet" type="text/css" /> <link rel="stylesheet" type="text/css" href="/static/new/css/show_trait.css" /> {% endblock %} {% block content %} @@ -21,8 +22,8 @@ <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-success" id="add" disabled ><span class="glyphicon glyphicon-plus-sign"></span> Add</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 ..."> + <input type="text" id="searchbox" class="form-control" style="width: 180px; display: inline;" placeholder="Search This Table For ..."> + <input type="text" id="select_top" class="form-control" style="width: 120px; display: inline;" placeholder="Select Top ..."> <form id="export_form" method="POST" action="/export_traits_csv" style="display: inline;"> <input type="hidden" name="headers" id="headers" value="{% for field in header_fields %}{{ field }},{% endfor %}"> <input type="hidden" name="database_name" id="database_name" value="None"> @@ -31,7 +32,7 @@ </form> <br /> <br /> - <div style="min-width: 2000px; width: 100%;"> + <div id="table_container" style="width: 2000px;"> <table id="trait_table" class="table-hover table-striped cell-border" style="float: left;"> <tbody> <td colspan="100%" align="center"><br><b><font size="15">Loading...</font></b><br></td> @@ -54,6 +55,7 @@ <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='DataTablesExtensions/colReorder/js/dataTables.colReorder.js') }}"></script> <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='DataTablesExtensions/colResize/dataTables.colResize.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/javascript/table_functions.js"></script> <script type='text/javascript'> var getParams = function(url) { @@ -73,218 +75,233 @@ <script type="text/javascript" charset="utf-8"> $(document).ready( function () { + var tableId = "trait_table"; - $('#trait_table tr').click(function(event) { - if (event.target.type !== 'checkbox') { - $(':checkbox', this).trigger('click'); - } - }); + var width_change = 0; //ZS: For storing the change in width so overall table width can be adjusted by that amount - function change_buttons() { - buttons = ["#add", "#remove"]; - num_checked = $('.trait_checkbox:checked').length; - if (num_checked === 0) { - for (_i = 0, _len = buttons.length; _i < _len; _i++) { - button = buttons[_i]; - $(button).prop("disabled", true); - } + columnDefs = [ + { + 'data': null, + 'orderDataType': "dom-checkbox", + 'width': "10px", + 'targets': 0, + 'render': function(data, type, row, meta) { + return '<input type="checkbox" name="searchResult" class="trait_checkbox checkbox" value="' + data.hmac + '">' + } + }, + { + 'title': "Index", + 'type': "natural", + 'width': "30px", + 'targets': 1, + 'data': "index" + }, + { + 'title': "Species", + 'type': "natural", + 'width': "60px", + 'targets': 2, + 'data': "species" + }, + { + 'title': "Group", + 'type': "natural", + 'width': "100px", + 'targets': 3, + 'data': "group" + }, + { + 'title': "Record", + 'type': "natural", + 'data': null, + 'width': "60px", + 'targets': 4, + 'orderDataType': "dom-inner-text", + 'render': function(data, type, row, meta) { + return '<a target="_blank" href="/show_trait?trait_id=' + data.name + '&dataset=' + data.dataset + '">' + data.display_name + '</a>' + } + }, + { + 'title': "Description", + 'type': "natural", + 'width': "500px", + 'targets': 5, + 'data': null, + 'render': function(data, type, row, meta) { + try { + return decodeURIComponent(escape(data.description)) + } catch(err) { + return data.description + } + } + }, + { + 'title': "Mean", + 'type': "natural-minus-na", + 'width': "30px", + 'targets': 6, + 'data': "mean" + }, + { + 'title': "Authors", + 'type': "natural", + 'width': "300px", + 'targets': 7, + 'data': null, + 'render': function(data, type, row, meta) { + author_list = data.authors.split(",") + if (author_list.length >= 6) { + author_string = author_list.slice(0, 6).join(",") + ", et al." + } else{ + author_string = data.authors + } + return author_string + } + }, + { + 'title': "Year", + 'type': "natural-minus-na", + 'data': null, + 'orderDataType': "dom-inner-text", + 'width': "25px", + 'targets': 8, + 'render': function(data, type, row, meta) { + if (data.pubmed_id != "N/A"){ + return '<a href="' + data.pubmed_link + '">' + data.pubmed_text + '</a>' } else { - for (_j = 0, _len2 = buttons.length; _j < _len2; _j++) { - button = buttons[_j]; - $(button).prop("disabled", false); - } + return data.pubmed_text } - //}); - if ($(this).is(":checked")) { - if (!$(this).closest('tr').hasClass('selected')) { - $(this).closest('tr').addClass('selected') - } + }, + 'orderSequence': [ "desc", "asc"] + }, + { + 'title': "Max LRS<a href=\"{{ url_for('glossary_blueprint.glossary') }}#LRS\" target=\"_blank\" style=\"color: white;\"><sup>?</sup></a>", + 'type': "natural-minus-na", + 'data': "LRS_score_repr", + 'width': "60px", + 'targets': 9, + 'orderSequence': [ "desc", "asc"] + }, + { + 'title': "Max LRS Location", + 'type': "natural-minus-na", + 'width': "125px", + 'targets': 10, + 'data': "max_lrs_text" + }, + { + 'title': "Additive Effect<a href=\"{{ url_for('glossary_blueprint.glossary') }}#A\" target=\"_blank\" style=\"color: white;\"><sup>?</sup></a>", + 'type': "natural-minus-na", + 'data': "additive", + 'width': "60px", + 'targets': 11, + 'orderSequence': [ "desc", "asc"] + } + ] + + loadDataTable(true); + + function loadDataTable(first_run=false){ + + if (!first_run){ + setUserColumnsDefWidths(tableId); + } + + table_settings = { + 'drawCallback': function( settings ) { + $('#' + tableId + ' tr').off().on("click", function(event) { + if (event.target.type !== 'checkbox' && event.target.tagName.toLowerCase() !== 'a') { + var obj =$(this).find('input'); + obj.prop('checked', !obj.is(':checked')); + } + if ($(this).hasClass("selected") && event.target.tagName.toLowerCase() !== 'a'){ + $(this).removeClass("selected") + } else if (event.target.tagName.toLowerCase() !== 'a') { + $(this).addClass("selected") + } + change_buttons() + }); + }, + "createdRow": function ( row, data, index ) { + $('td', row).eq(0).attr("style", "text-align: center; padding: 4px 10px 2px 10px;"); + $('td', row).eq(1).attr("align", "right"); + $('td', row).eq(5).attr('title', $('td', row).eq(5).text()); + if ($('td', row).eq(5).text().length > 150) { + $('td', row).eq(5).text($('td', row).eq(5).text().substring(0, 150)); + $('td', row).eq(5).text($('td', row).eq(5).text() + '...') } - else { - if ($(this).closest('tr').hasClass('selected')) { - $(this).closest('tr').removeClass('selected') - } + $('td', row).eq(6).attr('title', $('td', row).eq(6).text()); + if ($('td', row).eq(6).text().length > 150) { + $('td', row).eq(6).text($('td', row).eq(6).text().substring(0, 150)); + $('td', row).eq(6).text($('td', row).eq(6).text() + '...') } + $('td', row).eq(6).attr("align", "right"); + $('td', row).slice(8,11).attr("align", "right"); + $('td', row).eq(1).attr('data-export', $('td', row).eq(1).text()); + $('td', row).eq(2).attr('data-export', $('td', row).eq(2).text()); + $('td', row).eq(3).attr('data-export', $('td', row).eq(3).text()); + $('td', row).eq(4).attr('data-export', $('td', row).eq(4).text()); + $('td', row).eq(5).attr('data-export', $('td', row).eq(5).text()); + $('td', row).eq(6).attr('data-export', $('td', row).eq(6).text()); + $('td', row).eq(7).attr('data-export', $('td', row).eq(7).text()); + $('td', row).eq(8).attr('data-export', $('td', row).eq(8).text()); + $('td', row).eq(9).attr('data-export', $('td', row).eq(9).text()); + $('td', row).eq(10).attr('data-export', $('td', row).eq(10).text()); + }, + 'data': trait_list, + 'columns': columnDefs, + "order": [[1, "asc" ]], + 'sDom': "iti", + "destroy": true, + "deferRender": true, + "bSortClasses": false, + {% if trait_count > 20 %} + "scrollY": "100vh", + "scroller": true, + "scrollCollapse": true, + {% else %} + "iDisplayLength": -1, + {% endif %} + "initComplete": function (settings) { + //Add JQueryUI resizable functionality to each th in the ScrollHead table + $('#' + tableId + '_wrapper .dataTables_scrollHead thead th').resizable({ + handles: "e", + alsoResize: '#' + tableId + '_wrapper .dataTables_scrollHead table', //Not essential but makes the resizing smoother + resize: function( event, ui ) { + width_change = ui.size.width - ui.originalSize.width; + }, + stop: function () { + saveColumnSettings(tableId, trait_table); + loadDataTable(); + } + }); + } } - var the_table = $('#trait_table').DataTable( { - 'drawCallback': function( settings ) { - $('#trait_table tr').click(function(event) { - if (event.target.type !== 'checkbox' && event.target.tagName.toLowerCase() !== 'a') { - $(':checkbox', this).trigger('click'); - } - }); - $('.trait_checkbox:checkbox').on("change", change_buttons); - }, - "createdRow": function ( row, data, index ) { - $('td', row).eq(0).attr("style", "text-align: center; padding: 4px 10px 2px 10px;"); - $('td', row).eq(1).attr("align", "right"); - $('td', row).eq(5).attr('title', $('td', row).eq(5).text()); - if ($('td', row).eq(5).text().length > 150) { - $('td', row).eq(5).text($('td', row).eq(5).text().substring(0, 150)); - $('td', row).eq(5).text($('td', row).eq(5).text() + '...') - } - $('td', row).eq(6).attr('title', $('td', row).eq(6).text()); - if ($('td', row).eq(6).text().length > 150) { - $('td', row).eq(6).text($('td', row).eq(6).text().substring(0, 150)); - $('td', row).eq(6).text($('td', row).eq(6).text() + '...') - } - $('td', row).eq(6).attr("align", "right"); - $('td', row).slice(8,11).attr("align", "right"); - $('td', row).eq(1).attr('data-export', $('td', row).eq(1).text()); - $('td', row).eq(2).attr('data-export', $('td', row).eq(2).text()); - $('td', row).eq(3).attr('data-export', $('td', row).eq(3).text()); - $('td', row).eq(4).attr('data-export', $('td', row).eq(4).text()); - $('td', row).eq(5).attr('data-export', $('td', row).eq(5).text()); - $('td', row).eq(6).attr('data-export', $('td', row).eq(6).text()); - $('td', row).eq(7).attr('data-export', $('td', row).eq(7).text()); - $('td', row).eq(8).attr('data-export', $('td', row).eq(8).text()); - $('td', row).eq(9).attr('data-export', $('td', row).eq(9).text()); - $('td', row).eq(10).attr('data-export', $('td', row).eq(10).text()); - }, - 'data': trait_list, - 'columns': [ - { - 'data': null, - 'orderDataType': "dom-checkbox", - 'width': "10px", - 'render': function(data, type, row, meta) { - return '<input type="checkbox" name="searchResult" class="trait_checkbox checkbox" value="' + data.hmac + '">' - } - }, - { - 'title': "Index", - 'type': "natural", - 'width': "30px", - 'data': "index" - }, - { - 'title': "Species", - 'type': "natural", - 'width': "60px", - 'data': "species" - }, - { - 'title': "Group", - 'type': "natural", - 'width': "100px", - 'data': "group" - }, - { - 'title': "Record", - 'type': "natural", - 'data': null, - 'width': "60px", - 'orderDataType': "dom-inner-text", - 'render': function(data, type, row, meta) { - return '<a target="_blank" href="/show_trait?trait_id=' + data.name + '&dataset=' + data.dataset + '">' + data.display_name + '</a>' - } - }, - { - 'title': "Description", - 'type': "natural", - 'width': "500px", - 'data': null, - 'render': function(data, type, row, meta) { - try { - return decodeURIComponent(escape(data.description)) - } catch(err) { - return data.description - } - } - }, - { - 'title': "Mean", - 'type': "natural-minus-na", - 'width': "30px", - 'data': "mean" - }, - { - 'title': "Authors", - 'type': "natural", - 'width': "300px", - 'data': null, - 'render': function(data, type, row, meta) { - author_list = data.authors.split(",") - if (author_list.length >= 6) { - author_string = author_list.slice(0, 6).join(",") + ", et al." - } else{ - author_string = data.authors - } - return author_string - } - }, - { - 'title': "Year", - 'type': "natural-minus-na", - 'data': null, - 'orderDataType': "dom-inner-text", - 'width': "25px", - 'render': function(data, type, row, meta) { - if (data.pubmed_id != "N/A"){ - return '<a href="' + data.pubmed_link + '">' + data.pubmed_text + '</a>' - } else { - return data.pubmed_text - } - }, - 'orderSequence': [ "desc", "asc"] - }, - { - 'title': "Max LRS<a href=\"{{ url_for('glossary_blueprint.glossary') }}#LRS\" target=\"_blank\" style=\"color: white;\"><sup>?</sup></a>", - 'type': "natural-minus-na", - 'data': "LRS_score_repr", - 'width': "60px", - 'orderSequence': [ "desc", "asc"] - }, - { - 'title': "Max LRS Location", - 'type': "natural-minus-na", - 'width': "125px", - 'data': "max_lrs_text" - }, - { - 'title': "Additive Effect<a href=\"{{ url_for('glossary_blueprint.glossary') }}#A\" target=\"_blank\" style=\"color: white;\"><sup>?</sup></a>", - 'type': "natural-minus-na", - 'data': "additive", - 'width': "60px", - 'orderSequence': [ "desc", "asc"] - } - ], - "order": [[1, "asc" ]], - 'sDom': "iti", - "autoWidth": true, - "bSortClasses": false, - 'processing': true, - {% if trait_count > 20 %} - "scrollY": "100vh", - "scroller": true, - "scrollCollapse": true - {% else %} - "iDisplayLength": -1 - {% endif %} - } ); + if (!first_run){ + table_settings['autoWidth'] = false; + $('#table_container').css("width", String($('#trait_table').width() + width_change {% if trait_list|length > 20 %}+ 17{% endif %}) + "px"); // Change the container width by the change in width of the adjusted column, so the overall table size adjusts properly + } - $('#trait_table').append( - '<tfoot>' + - '<tr>' + - '<th></th>' + - '<th>Index</th>' + - '<th>Species</th> ' + - '<th>Group</th>' + - '<th>Record</th>' + - '<th>Description</th>' + - '<th>Authors</th>' + - '<th>Year</th>' + - '<th>Max LRS</th>' + - '<th>Max LRS Location</th>' + - '<th>Additive Effect</th>' + - '</tr>' + - '</tfoot>' - ); + let checked_rows = get_checked_rows(tableId); + trait_table = $('#' + tableId).DataTable(table_settings); + if (checked_rows.length > 0){ + recheck_rows(trait_table, checked_rows); + } - the_table.draw(); + if (first_run){ + {% if trait_list|length > 20 %} + $('#table_container').css("width", String($('#trait_table').width() + 17) + "px"); + {% endif %} + } + + trait_table.draw(); + } + + $('#redraw').click(function() { + var table = $('#' + tableId).DataTable(); + table.colReorder.reset() + }); }); - </script> - <script language="javascript" type="text/javascript" src="/static/new/javascript/search_results.js"></script> {% endblock %} diff --git a/wqflask/wqflask/templates/search_result_page.html b/wqflask/wqflask/templates/search_result_page.html index c499aa8f..72a4b560 100644 --- a/wqflask/wqflask/templates/search_result_page.html +++ b/wqflask/wqflask/templates/search_result_page.html @@ -5,6 +5,7 @@ <link rel="stylesheet" type="text/css" href="{{ url_for('css', filename='fontawesome/css/font-awesome.min.css') }}" /> <link rel="stylesheet" type="text/css" href="{{ url_for('js', filename='DataTablesExtensions/buttonStyles/css/buttons.dataTables.min.css') }}"> <link rel="stylesheet" type="text/css" href="{{ url_for('css', filename='fontawesome/css/all.min.css') }}"/> + <link href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet" type="text/css" /> <link rel="stylesheet" type="text/css" href="/static/new/css/show_trait.css" /> <link rel="stylesheet" type="text/css" href="static/new/css/trait_list.css" /> {% endblock %} @@ -125,8 +126,8 @@ {% endif %} </div> {% endif %} - <div id="table_container" {% if dataset.type == 'ProbeSet' or dataset.type == 'Publish' %}style="min-width: 1500px; max-width:100%;"{% endif %}> - <table class="table-hover table-striped cell-border" id='trait_table' style="float: left; width: {% if dataset.type == 'Geno' %}380px{% else %}100%{% endif %};"> + <div id="table_container" style="width: {% if dataset.type == 'Geno' %}270{% else %}1350{% endif %}px;"> + <table class="table-hover table-striped cell-border" id='trait_table' style="float: left;"> <tbody> <td colspan="100%" align="center"><br><b><font size="15">Loading...</font></b><br></td> </tbody> @@ -147,7 +148,6 @@ {% block js %} <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='js_alt/md5.min.js') }}"></script> - <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='DataTables/js/jquery.dataTables.min.js') }}"></script> <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='DataTablesExtensions/scroller/js/dataTables.scroller.min.js') }}"></script> <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='jszip/jszip.min.js') }}"></script> @@ -157,6 +157,7 @@ <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='fontawesome/js/all.min.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/javascript/table_functions.js"></script> <script type='text/javascript'> var trait_list = {{ trait_list|safe }}; @@ -176,10 +177,211 @@ }; {% if results|count > 0 %} - //ZS: Need to make sort by symbol, also need to make sure blank symbol fields at the bottom and symbols starting with numbers below letters - trait_table = $('#trait_table').DataTable( { + var tableId = "trait_table"; + + var width_change = 0; //ZS: For storing the change in width so overall table width can be adjusted by that amount + + columnDefs = [ + { + 'data': null, + 'width': "5px", + 'orderDataType': "dom-checkbox", + 'targets': 0, + 'render': function(data, type, row, meta) { + return '<input type="checkbox" name="searchResult" class="checkbox trait_checkbox" value="' + data.hmac + '">' + } + }, + { + 'title': "Index", + 'type': "natural", + 'width': "35px", + 'targets': 1, + 'data': "index" + } + {% if dataset.type == 'ProbeSet' %}, + { + 'title': "Record", + 'type': "natural-minus-na", + 'data': null, + 'width': "{{ max_widths.display_name * 8 }}px", + 'targets': 2, + 'render': function(data, type, row, meta) { + return '<a target="_blank" href="/show_trait?trait_id=' + data.name + '&dataset=' + data.dataset + '">' + data.display_name + '</a>' + } + }, + { + 'title': "Symbol", + 'type': "natural", + 'width': "{{ max_widths.symbol * 8 }}px", + 'targets': 3, + 'data': "symbol" + }, + { + 'title': "Description", + 'type': "natural", + 'data': null, + 'targets': 4, + 'render': function(data, type, row, meta) { + try { + return decodeURIComponent(escape(data.description)) + } catch(err){ + return escape(data.description) + } + } + }, + { + 'title': "<div style='text-align: right;'>Location</div>", + 'type': "natural-minus-na", + 'width': "125px", + 'targets': 5, + 'data': "location" + }, + { + 'title': "<div style='text-align: right;'>Mean</div>", + 'type': "natural-minus-na", + 'width': "40px", + 'data': "mean", + 'targets': 6, + 'orderSequence': [ "desc", "asc"] + }, + { + 'title': "<div style='text-align: right;'>Peak <a href=\"{{ url_for('glossary_blueprint.glossary') }}#LRS\" target=\"_blank\" style=\"color: white;\"> <i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i></a></div><div style='text-align: right;'>LOD  </div>", + 'type': "natural-minus-na", + 'data': "lod_score", + 'width': "60px", + 'targets': 7, + 'orderSequence': [ "desc", "asc"] + }, + { + 'title': "<div style='text-align: right;'>Peak Location</div>", + 'type': "natural-minus-na", + 'width': "125px", + 'targets': 8, + 'data': "lrs_location" + }, + { + 'title': "<div style='text-align: right;'>Effect <a href=\"{{ url_for('glossary_blueprint.glossary') }}#A\" target=\"_blank\" style=\"color: white;\"> <i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i></a></div><div style='text-align: right;'>Size  </div>", + 'type': "natural-minus-na", + 'data': "additive", + 'width': "65px", + 'targets': 9, + 'orderSequence': [ "desc", "asc"] + }{% elif dataset.type == 'Publish' %}, + { + 'title': "Record", + 'type': "natural-minus-na", + 'width': "{{ max_widths.display_name * 9 }}px", + 'data': null, + 'targets': 2, + 'render': function(data, type, row, meta) { + return '<a target="_blank" href="/show_trait?trait_id=' + data.name + '&dataset=' + data.dataset + '">' + data.display_name + '</a>' + } + }, + { + 'title': "Description", + 'type': "natural", + {% if (max_widths.description * 7) < 500 %} + 'width': "{{ max_widths.description * 7 }}px", + {% else %} + 'width': "500px", + {% endif %} + 'data': null, + 'targets': 3, + 'render': function(data, type, row, meta) { + try { + return decodeURIComponent(escape(data.description)) + } catch(err){ + return data.description + } + } + }, + { + 'title': "<div style='text-align: right;'>Mean</div>", + 'type': "natural-minus-na", + 'width': "60px", + 'data': "mean", + 'targets': 4, + 'orderSequence': [ "desc", "asc"] + }, + { + 'title': "Authors", + 'type': "natural", + {% if (max_widths.authors * 7) < 500 %} + 'width': "{{ max_widths.authors * 7 }}px", + {% else %} + 'width': "500px", + {% endif %} + 'data': null, + 'targets': 5, + 'render': function(data, type, row, meta) { + author_list = data.authors.split(",") + if (author_list.length >= 6) { + author_string = author_list.slice(0, 6).join(",") + ", et al." + } else{ + author_string = data.authors + } + return author_string + } + }, + { + 'title': "<div style='text-align: right;'>Year</div>", + 'type': "natural-minus-na", + 'data': null, + 'width': "50px", + 'targets': 6, + 'render': function(data, type, row, meta) { + if (data.pubmed_id != "N/A"){ + return '<a href="' + data.pubmed_link + '">' + data.pubmed_text + '</a>' + } else { + return data.pubmed_text + } + }, + 'orderSequence': [ "desc", "asc"] + }, + { + 'title': "<div style='text-align: right;'>Peak <a href=\"{{ url_for('glossary_blueprint.glossary') }}#LRS\" target=\"_blank\" style=\"color: white;\"> <i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i></a></div><div style='text-align: right;'>LOD  </div>", + 'type': "natural-minus-na", + 'data': "lod_score", + 'targets': 7, + 'width': "60px", + 'orderSequence': [ "desc", "asc"] + }, + { + 'title': "<div style='text-align: right;'>Peak Location</div>", + 'type': "natural-minus-na", + 'width': "120px", + 'targets': 8, + 'data': "lrs_location" + }, + { + 'title': "<div style='text-align: right;'>Effect <a href=\"{{ url_for('glossary_blueprint.glossary') }}#A\" target=\"_blank\" style=\"color: white;\"> <i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i></a></div><div style='text-align: right;'>Size  </div>", + 'type': "natural-minus-na", + 'width': "60px", + 'data': "additive", + 'targets': 9, + 'orderSequence': [ "desc", "asc"] + }{% elif dataset.type == 'Geno' %}, + { + 'title': "<div style='text-align: right;'>Location</div>", + 'type': "natural-minus-na", + 'width': "120px", + 'targets': 2, + 'data': "location" + }{% endif %} + ]; + + loadDataTable(true); + + function loadDataTable(first_run=false){ + + if (!first_run){ + setUserColumnsDefWidths(tableId); + } + + //ZS: Need to make sort by symbol, also need to make sure blank symbol fields at the bottom and symbols starting with numbers below letters + table_settings = { 'drawCallback': function( settings ) { - $('#trait_table tr').off().on("click", function(event) { + $('#' + tableId + ' tr').off().on("click", function(event) { if (event.target.type !== 'checkbox' && event.target.tagName.toLowerCase() !== 'a') { var obj =$(this).find('input'); obj.prop('checked', !obj.is(':checked')); @@ -193,7 +395,7 @@ }); }, 'createdRow': function ( row, data, index ) { - $('td', row).eq(0).attr("style", "text-align: center; padding: 0px 10px 2px 13px;"); + $('td', row).eq(0).attr("style", "text-align: center; padding: 0px 10px 2px 10px;"); $('td', row).eq(1).attr("align", "right"); $('td', row).eq(1).attr('data-export', index+1); $('td', row).eq(2).attr('data-export', $('td', row).eq(2).text()); @@ -228,173 +430,61 @@ $('td', row).eq(3).attr('data-export', $('td', row).eq(3).text()); {% endif %} }, - 'data': trait_list, - 'columns': [ - { - 'data': null, - 'width': "10px", - 'orderDataType': "dom-checkbox", - 'orderable': false, - 'render': function(data, type, row, meta) { - return '<input type="checkbox" name="searchResult" class="checkbox trait_checkbox" value="' + data.hmac + '">' - } - }, - { - 'title': "Index", - 'type': "natural", - 'width': "30px", - 'data': "index" - }, - { - 'title': "Record", - 'type': "natural-minus-na", - 'data': null, - 'width': "60px", - 'render': function(data, type, row, meta) { - return '<a target="_blank" href="/show_trait?trait_id=' + data.name + '&dataset=' + data.dataset + '">' + data.display_name + '</a>' - } - }{% if dataset.type == 'ProbeSet' %}, - { - 'title': "Symbol", - 'type': "natural", - 'width': "120px", - 'data': "symbol" - }, - { - 'title': "Description", - 'type': "natural", - 'data': null, - 'render': function(data, type, row, meta) { - try { - return decodeURIComponent(escape(data.description)) - } catch(err){ - return escape(data.description) - } - } - }, - { - 'title': "<div style='text-align: right;'>Location</div>", - 'type': "natural-minus-na", - 'width': "125px", - 'data': "location" - }, - { - 'title': "<div style='text-align: right;'>Mean</div>", - 'type': "natural-minus-na", - 'width': "30px", - 'data': "mean", - 'orderSequence': [ "desc", "asc"] - }, - { - 'title': "<div style='text-align: right;'>Peak <a href=\"{{ url_for('glossary_blueprint.glossary') }}#LRS\" target=\"_blank\" style=\"color: white;\"> <i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i></a></div><div style='text-align: right;'>LOD  </div>", - 'type': "natural-minus-na", - 'data': "lod_score", - 'width': "60px", - 'orderSequence': [ "desc", "asc"] - }, - { - 'title': "<div style='text-align: right;'>Peak Location</div>", - 'type': "natural-minus-na", - 'width': "125px", - 'data': "lrs_location" - }, - { - 'title': "<div style='text-align: right;'>Effect <a href=\"{{ url_for('glossary_blueprint.glossary') }}#A\" target=\"_blank\" style=\"color: white;\"> <i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i></a></div><div style='text-align: right;'>Size  </div>", - 'type': "natural-minus-na", - 'data': "additive", - 'width': "60px", - 'orderSequence': [ "desc", "asc"] - }{% elif dataset.type == 'Publish' %}, - { - 'title': "Description", - 'type': "natural", - 'width': "500px", - 'data': null, - 'render': function(data, type, row, meta) { - try { - return decodeURIComponent(escape(data.description)) - } catch(err){ - return data.description - } - } - }, - { - 'title': "<div style='text-align: right;'>Mean</div>", - 'type': "natural-minus-na", - 'width': "30px", - 'data': "mean", - 'orderSequence': [ "desc", "asc"] - }, - { - 'title': "Authors", - 'type': "natural", - 'width': "300px", - 'data': null, - 'render': function(data, type, row, meta) { - author_list = data.authors.split(",") - if (author_list.length >= 6) { - author_string = author_list.slice(0, 6).join(",") + ", et al." - } else{ - author_string = data.authors - } - return author_string - } - }, - { - 'title': "<div style='text-align: right;'>Year</div>", - 'type': "natural-minus-na", - 'data': null, - 'width': "25px", - 'render': function(data, type, row, meta) { - if (data.pubmed_id != "N/A"){ - return '<a href="' + data.pubmed_link + '">' + data.pubmed_text + '</a>' - } else { - return data.pubmed_text - } - }, - 'orderSequence': [ "desc", "asc"] - }, - { - 'title': "<div style='text-align: right;'>Peak <a href=\"{{ url_for('glossary_blueprint.glossary') }}#LRS\" target=\"_blank\" style=\"color: white;\"> <i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i></a></div><div style='text-align: right;'>LOD  </div>", - 'type': "natural-minus-na", - 'data': "lod_score", - 'width': "60px", - 'orderSequence': [ "desc", "asc"] - }, - { - 'title': "<div style='text-align: right;'>Peak Location</div>", - 'type': "natural-minus-na", - 'width': "120px", - 'data': "lrs_location" - }, - { - 'title': "<div style='text-align: right;'>Effect <a href=\"{{ url_for('glossary_blueprint.glossary') }}#A\" target=\"_blank\" style=\"color: white;\"> <i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i></a></div><div style='text-align: right;'>Size  </div>", - 'type': "natural-minus-na", - 'width': "60px", - 'data': "additive", - 'orderSequence': [ "desc", "asc"] - }{% elif dataset.type == 'Geno' %}, - { - 'title': "<div style='text-align: right;'>Location</div>", - 'type': "natural-minus-na", - 'width': "120px", - 'data': "location" - }{% endif %} - ], + "data": trait_list, + "columns": columnDefs, "order": [[1, "asc" ]], - 'sDom': "iti", - "autoWidth": true, + "sDom": "iti", + "destroy": true, + "autoWidth": false, + "deferRender": true, "bSortClasses": false, - {% if trait_list|length > 20 %} - "scrollY": "100vh", + "scrollY": "500px", + "scrollCollapse": true, + {% if trait_list|length > 5 %} "scroller": true, - "scrollCollapse": true + {% endif %} + "iDisplayLength": -1, + "initComplete": function (settings) { + //Add JQueryUI resizable functionality to each th in the ScrollHead table + $('#' + tableId + '_wrapper .dataTables_scrollHead thead th').resizable({ + handles: "e", + alsoResize: '#' + tableId + '_wrapper .dataTables_scrollHead table', //Not essential but makes the resizing smoother + resize: function( event, ui ) { + width_change = ui.size.width - ui.originalSize.width; + }, + stop: function () { + saveColumnSettings(tableId, trait_table); + loadDataTable(); + } + }); + } + } + + if (!first_run){ + $('#table_container').css("width", String($('#trait_table').width() + width_change {% if trait_list|length > 20 %}+ 17{% endif %}) + "px"); //ZS : Change the container width by the change in width of the adjusted column, so the overall table size adjusts properly + + let checked_rows = get_checked_rows(tableId); + trait_table = $('#' + tableId).DataTable(table_settings); + if (checked_rows.length > 0){ + recheck_rows(trait_table, checked_rows); + } + } else { + trait_table = $('#' + tableId).DataTable(table_settings); + trait_table.draw(); + } + + if (first_run){ + {% if trait_list|length > 20 %} + $('#table_container').css("width", String($('#trait_table').width() + 17) + "px"); {% else %} - "iDisplayLength": -1 + $('#table_container').css("width", String($('#trait_table').width()) + "px"); {% endif %} - } ); + } + } - trait_table.draw(); //ZS: This makes the table adjust its height properly on initial load + window.addEventListener('resize', function(){ + trait_table.columns.adjust(); + }); $('.toggle-vis').on( 'click', function (e) { e.preventDefault(); @@ -412,9 +502,8 @@ } } ); - $('#redraw').click(function() { - var table = $('#trait_table').DataTable(); + var table = $('#' + tableId).DataTable(); table.colReorder.reset() }); {% endif %} diff --git a/wqflask/wqflask/templates/show_trait.html b/wqflask/wqflask/templates/show_trait.html index f3fa1332..7074e21e 100644 --- a/wqflask/wqflask/templates/show_trait.html +++ b/wqflask/wqflask/templates/show_trait.html @@ -5,9 +5,10 @@ <link rel="stylesheet" type="text/css" href="/static/new/css/box_plot.css" /> <link rel="stylesheet" type="text/css" href="/static/new/css/prob_plot.css" /> <link rel="stylesheet" type="text/css" href="/static/new/css/scatter-matrix.css" /> - <link rel="stylesheet" type="text/css" href="{{ url_for('css', filename='d3-tip/d3-tip.css') }}" /> + <link rel="stylesheet" type="text/css" href="{{ url_for('css', filename='d3-tip/d3-tip.css') }}" /> <link rel="stylesheet" type="text/css" href="{{ url_for('css', filename='DataTables/css/jquery.dataTables.css') }}" /> <link rel="stylesheet" type="text/css" href="{{ url_for('css', filename='nouislider/nouislider.min.css') }}" /> + <link href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet" type="text/css" /> <link rel="stylesheet" type="text/css" href="/static/new/css/trait_list.css" /> <link rel="stylesheet" type="text/css" href="/static/new/css/show_trait.css" /> @@ -155,6 +156,7 @@ <script type="text/javascript" src="/static/new/javascript/show_trait.js"></script> <script type="text/javascript" src="/static/new/javascript/validation.js"></script> <script type="text/javascript" src="/static/new/javascript/get_covariates_from_collection.js"></script> + <script type="text/javascript" src="/static/new/javascript/table_functions.js"></script> <script type="text/javascript" charset="utf-8"> @@ -211,16 +213,6 @@ } }); - primary_table.on( 'order.dt search.dt draw.dt', function () { - primary_table.column(1, {search:'applied', order:'applied'}).nodes().each( function (cell, i) { - cell.innerHTML = i+1; - } ); - } ).draw(); - - $('#primary_searchbox').on( 'keyup', function () { - primary_table.search($(this).val()).draw(); - } ); - $('.toggle-vis').on('click', function (e) { e.preventDefault(); @@ -237,7 +229,6 @@ // Get the column API object var target_cols = $(this).attr('data-column').split(",") for (let i = 0; i < target_cols.length; i++){ - console.log("THE COL:", target_cols[i]) var column = primary_table.column( target_cols[i] ); toggle_column(column); @@ -248,11 +239,7 @@ } } ); - {% if sample_groups|length != 1 %} - $('#other_searchbox').on( 'keyup', function () { - other_table.search($(this).val()).draw(); - } ); - {% endif %} + $('#samples_primary, #samples_other').find("tr.outlier").css('background-color', 'orange') $('.edit_sample_checkbox:checkbox').change(function() { if ($(this).is(":checked")) { diff --git a/wqflask/wqflask/templates/show_trait_edit_data.html b/wqflask/wqflask/templates/show_trait_edit_data.html index 5939c953..e288e4d5 100644 --- a/wqflask/wqflask/templates/show_trait_edit_data.html +++ b/wqflask/wqflask/templates/show_trait_edit_data.html @@ -53,12 +53,12 @@ </div> </div> {% set outer_loop = loop %} - <div class="sample_group" style="width:{{ trait_table_width }}px;"> + <div class="sample_group"> <div style="position: relative;"> <div class="inline-div"><h3 style="float: left;">{{ sample_type.header }}<span name="transform_text"></span></h3></div> </div> - <div id="table_container"> - <table class="table-hover table-striped cell-border sample-table" id="samples_{{ sample_type.sample_group_type }}"> + <div id="{{ sample_type.sample_group_type }}_container" style="width: {{ trait_table_width }}px;"> + <table class="table-hover table-striped cell-border" id="samples_{{ sample_type.sample_group_type }}"> <tbody> <td colspan="100%" align="center"><br><b><font size="15">Loading...</font></b><br></td> </tbody> |