diff options
author | Frederick Muriuki Muriithi | 2023-12-07 12:40:37 +0300 |
---|---|---|
committer | Frederick Muriuki Muriithi | 2023-12-07 12:40:37 +0300 |
commit | 8760d188faebe552028f3142a821d0851df4e1e9 (patch) | |
tree | dc56fe37d79685c1107765d80ffe78085c7df7f1 | |
parent | 493f8fbe747650a4fbac2e0b153ad0074b4f91e4 (diff) | |
download | gn-uploader-8760d188faebe552028f3142a821d0851df4e1e9.tar.gz |
Samples: Provide preview feature.
-rw-r--r-- | qc_app/static/js/upload_samples.js | 132 | ||||
-rw-r--r-- | qc_app/templates/samples/upload-samples.html | 56 |
2 files changed, 178 insertions, 10 deletions
diff --git a/qc_app/static/js/upload_samples.js b/qc_app/static/js/upload_samples.js new file mode 100644 index 0000000..aed536f --- /dev/null +++ b/qc_app/static/js/upload_samples.js @@ -0,0 +1,132 @@ +/* + * Read the file content and set the `data-preview-content` attribute on the + * file element + */ +function read_first_n_lines(event, + fileelement, + numlines, + firstlineheading = true) { + var thefile = fileelement.files[0]; + var reader = new FileReader(); + reader.addEventListener("load", (event) => { + var filecontent = event.target.result.split( + "\n").slice( + 0, (numlines + (firstlineheading ? 1 : 0))).map( + (line) => {return line.trim("\r");}); + fileelement.setAttribute( + "data-preview-content", JSON.stringify(filecontent)); + display_preview(event); + }) + reader.readAsText(thefile); +} + +function remove_rows(preview_table) { + var table_body = preview_table.getElementsByTagName("tbody")[0]; + while(table_body.children.length > 0) { + table_body.removeChild(table_body.children.item(0)); + } +} + +/* + * Display error row + */ +function display_error_row(preview_table, error_message) { + remove_rows(preview_table); + row = document.createElement("tr"); + cell = document.createElement("td"); + cell.setAttribute("colspan", 4); + cell.innerHTML = error_message; + row.appendChild(cell); + preview_table.getElementsByTagName("tbody")[0].appendChild(row); +} + +function strip(str, chars) { + var end = str.length; + var start = 0 + for(var j = str.length; j > 0; j--) { + if(!chars.includes(str[j - 1])) { + break; + } + end = end - 1; + } + for(var i = 0; i < end; i++) { + if(!chars.includes(str[i])) { + break; + } + start = start + 1; + } + return str.slice(start, end); +} + +function process_preview_data(preview_data, separator, delimiter) { + return preview_data.map((line) => { + return line.split(separator).map((field) => { + return strip(field, delimiter); + }); + }); +} + +function render_preview(preview_table, preview_data) { + remove_rows(preview_table); + var table_body = preview_table.getElementsByTagName("tbody")[0]; + preview_data.forEach((line) => { + var row = document.createElement("tr"); + line.forEach((field) => { + var cell = document.createElement("td"); + cell.innerHTML = field; + row.appendChild(cell); + }); + table_body.appendChild(row); + }); +} + +/* + * Display a preview of the data, relying on the user's selection. + */ +function display_preview(event) { + var data_preview_table = document.getElementById("tbl:samples-preview"); + remove_rows(data_preview_table); + + var separator = document.getElementById("select:separator").value; + if(separator === "other") { + separator = document.getElementById("txt:separator").value; + } + if(separator == "") { + display_error_row(data_preview_table, "Please provide a separator."); + return false; + } + + var delimiter = document.getElementById("txt:delimiter").value; + + var firstlineheading = document.getElementById("chk:heading").checked; + + var fileelement = document.getElementById("file:samples"); + var preview_data = JSON.parse( + fileelement.getAttribute("data-preview-content") || "[]"); + if(preview_data.length == 0) { + display_error_row( + data_preview_table, + "No file data to preview. Check that file is provided."); + } + + render_preview(data_preview_table, process_preview_data( + preview_data.slice(0 + (firstlineheading ? 1 : 0)), + separator, + delimiter)); +} + +document.getElementById("chk:heading").addEventListener( + "change", display_preview); +document.getElementById("select:separator").addEventListener( + "change", display_preview); +document.getElementById("txt:separator").addEventListener( + "keyup", display_preview); +document.getElementById("txt:delimiter").addEventListener( + "keyup", display_preview); +document.getElementById("file:samples").addEventListener( + "change", (event) => { + read_first_n_lines(event, + document.getElementById("file:samples"), + 30, + document.getElementById("chk:heading").checked); + }); diff --git a/qc_app/templates/samples/upload-samples.html b/qc_app/templates/samples/upload-samples.html index b19e38c..23dc8a8 100644 --- a/qc_app/templates/samples/upload-samples.html +++ b/qc_app/templates/samples/upload-samples.html @@ -46,13 +46,21 @@ <fieldset> <input type="hidden" name="species_id" value="{{species.SpeciesId}}" /> <label class="form-col-1">species:</label> - <label class="form-col-2">{{species.SpeciesName}} [{{species.MenuName}}]</label> + <span class="form-col-2">{{species.SpeciesName}} [{{species.MenuName}}]</span> </fieldset> <fieldset> <input type="hidden" name="inbredset_id" value="{{population.InbredSetId}}" /> <label class="form-col-1">grouping/population:</label> - <label class="form-col-2">{{population.Name}} [{{population.FullName}}]</label> + <span class="form-col-2">{{population.Name}} [{{population.FullName}}]</span> + </fieldset> + + <fieldset> + <input id="chk:heading" + type="checkbox" + name="first_line_heading" + class="form-col-1" /> + <label for="chk:heading" class="form-col-2">first line is a heading?</label> </fieldset> <fieldset> @@ -68,27 +76,34 @@ <option value=";">Semicolon</option> <option value="other">Other</option> </select> - <input type="text" name="other_separator" class="form-col-2" /> - <label class="form-col-2"> + <input id="txt:separator" + type="text" + name="other_separator" + class="form-col-2" /> + <span class="form-col-2"> This is the character that separates the fields in your CSV file. If you select "<strong>Other</strong>", then you must provide the separator in the text field provided. - </label> + </span> </fieldset> <fieldset> <label for="txt:delimiter" class="form-col-1">field delimiter</label> - <input type="text" name="field_delimiter" class="form-col-2" /> - <label class="form-col-2"> + <input id="txt:delimiter" + type="text" + name="field_delimiter" + maxlength="1" + class="form-col-2" /> + <span class="form-col-2"> If there is a character delimiting the string texts within particular fields in your CSV, provide the character here. This can be left blank if no such delimiters exist in your file. - </label> + </span> </fieldset> <fieldset> - <label for="file_upload" class="form-col-1">select file</label> - <input type="file" name="samples_file" id="file_upload" + <label for="file:samples" class="form-col-1">select file</label> + <input type="file" name="samples_file" id="file:samples" accept="text/csv, text/tab-separated-values" class="form-col-2" /> </fieldset> @@ -100,8 +115,29 @@ </fieldset> </form> +<table id="tbl:samples-preview"> + <caption class="heading">preview content</caption> + + <thead> + <tr> + <th>Name</th> + <th>Name2</th> + <th>Symbol</th> + <th>Alias</th> + </tr> + </thead> + + <tbody> + <tr id="default-row"> + <td colspan="4"> + Please make some selections to preview the data.</td> + </tr> + </tbody> +</table> + {%endblock%} {%block javascript%} +<script src="/static/js/upload_samples.js" type="text/javascript"></script> {%endblock%} |