class InvalidCSSIDSelector extends Error { constructor(message) { super(message); this.name = "InvalidCSSIDSelector"; } } class InvalidDataAttributeName extends Error { constructor(message) { super(message); this.name = "InvalidDataAttributeName"; } } /** * CSSIDSelector: A CSS ID Selector * @param {String} A CSS selector of the form '#...' */ class CSSIDSelector { constructor(selector) { if(!selector.startsWith("#")) { throw new InvalidCSSIDSelector( "Expected the CSS selector to begin with a `#` character."); } let id_str = selector.slice(1, selector.length); if(document.getElementById(id_str) == null) { throw new InvalidCSSIDSelector( "Element with ID '" + id_str + "' does not exist."); } this.selector = selector; } } /** * TableDataSource: A type to represent a table's data source * @param {String} A CSS selector for an ID * @param {String} A `data-*` attribute name */ class TableDataSource { constructor(table_id, data_attribute_name, checkbox_creation_function) { this.table_id = new CSSIDSelector(table_id); let data = document.querySelector( table_id).getAttribute(data_attribute_name); if(data == null) { throw new InvalidDataAttributeName( "data-* attribute '" + data_attribute_name + "' does not exist " + "for table with ID '" + table_id.slice(1, table_id.length) + "'."); } else { this.data_attribute_name = data_attribute_name; } this.checkbox_creation_function = checkbox_creation_function; } } /** * Render the table * @param {String} The selector for the table's ID * @param {String} The name of the data-* attribute holding the table's data * @param {Function} The function to call to generate the appropriate checkbox */ function render_table(table_data_source) { table_id = table_data_source.table_id.selector; data_attr_name = table_data_source.data_attribute_name; $(table_id + " tbody tr").remove(); table_data = JSON.parse($(table_id).attr(data_attr_name)).sort((d1, d2) => { return (d1.dataset_name > d2.dataset_name ? 1 : ( d1.dataset_name < d2.dataset_name ? -1 : 0)) }); if(table_data.length < 1) { row = $("") cell = $(''); cell.append( $('')); cell.append(" "); cell.append("No genotype datasets remaining."); row.append(cell); $(table_id + " tbody").append(row); } table_data.forEach(function(dataset) { row = $("") row.append(table_data_source.checkbox_creation_function(dataset)); row.append(table_cell(dataset.InbredSetName)); row.append(table_cell(dataset.dataset_name)); row.append(table_cell(dataset.dataset_fullname)); row.append(table_cell(dataset.dataset_shortname)); $(table_id + " tbody").append(row); }); } function in_array(items, filter_fn) { return items.filter(filter_fn).length > 0; } function remove_from_table_data(dataset, table_data_source, filter_fn) { let table_id = table_data_source.table_id.selector; let data_attr_name = table_data_source.data_attribute_name; without_dataset = JSON.parse($(table_id).attr(data_attr_name)).filter( filter_fn); $(table_id).attr(data_attr_name, JSON.stringify(without_dataset)); } function add_to_table_data(dataset, table_data_source, filter_fn) { let table_id = table_data_source.table_id.selector; let data_attr_name = table_data_source.data_attribute_name; table_data = JSON.parse($(table_id).attr(data_attr_name)); if(!in_array(table_data, filter_fn)) { table_data.push(dataset); } $(table_id).attr(data_attr_name, JSON.stringify(Array.from(table_data))); } /** * Switch the dataset/trait from search table to selection table and vice versa * @param {Object} A dataset/trait object * @param {TableDataSource} The source table for the dataset/trait * @param {TableDataSource} The destination table for the dataset/trait */ function select_deselect(item, source, destination, filter_fn, render_fn=render_table) { dest_selector = destination.table_id.selector dest_data = JSON.parse( $(dest_selector).attr(destination.data_attribute_name)); add_to_table_data(item, destination, filter_fn); // Add to destination table remove_from_table_data(item, source, (arg) => {return !filter_fn(arg)}); // Remove from source table /***** BEGIN: Re-render tables *****/ render_fn(destination); render_fn(source); /***** END: Re-render tables *****/ } function debounce(func, delay=500) { var timeout; return function search(event) { clearTimeout(timeout); timeout = setTimeout(func, delay); }; } /** * Build a checkbox * @param {Dataset Object} A JSON.stringify-able object * @param {String} The name to assign the checkbox */ function build_checkbox(data_object, checkbox_name, checkbox_aux_classes="", checked=false) { cell = $(""); check = $( ''); check.val(JSON.stringify(data_object)); check.prop("checked", checked); auxilliary_classes = checkbox_aux_classes.trim(); if(Boolean(auxilliary_classes)) { check.attr("class", check.attr("class") + " " + auxilliary_classes.trim()); } cell.append(check); return cell; } function link_checkbox(dataset) { return build_checkbox(dataset, "selected", "checkbox-selected", true); } function search_checkbox(dataset) { return build_checkbox(dataset, "search_datasets", "checkbox-search"); } function table_cell(value) { cell = $(""); cell.html(value); return cell; }