about summary refs log tree commit diff
path: root/uploader/static/js
diff options
context:
space:
mode:
Diffstat (limited to 'uploader/static/js')
-rw-r--r--uploader/static/js/datatables.js106
-rw-r--r--uploader/static/js/debug.js40
-rw-r--r--uploader/static/js/files.js4
-rw-r--r--uploader/static/js/misc.js6
-rw-r--r--uploader/static/js/populations.js47
-rw-r--r--uploader/static/js/pubmed.js113
-rw-r--r--uploader/static/js/species.js45
-rw-r--r--uploader/static/js/utils.js27
8 files changed, 284 insertions, 104 deletions
diff --git a/uploader/static/js/datatables.js b/uploader/static/js/datatables.js
index 8d54a84..82fd696 100644
--- a/uploader/static/js/datatables.js
+++ b/uploader/static/js/datatables.js
@@ -1,57 +1,69 @@
 /** Handlers for events in datatables **/
 
-var dtAddRowSelectionHandler = (tableId) => {
-    $(tableId).on("draw.dt", (event) => {
-        $(".chk-row-select").on("change", (event) => {
-            var checkboxOrRadio = event.target;
-            var tablerow = checkboxOrRadio.parentElement.parentElement;
-            var tableclass = tablerow.getAttribute("class");
-            if(checkboxOrRadio.checked) {
-                if (checkboxOrRadio.type == "radio") {
-                    $(tableId + " tr").each((index, row) => {
-                        var rowKlass = $(row).attr("class") || "";
-                        row.setAttribute(
-                            "class", rowKlass.replaceAll("selected", "").trim());
-                    });
-                }
-                tablerow.setAttribute("class", `${tableclass} selected`);
-            }
-            else {
-                tablerow.setAttribute(
-                    "class", tableclass.replaceAll("selected", "").trim());
-            }
-        });
-    });
+var addTableLength = (menuList, lengthToAdd, dataLength) => {
+    if(dataLength >= lengthToAdd) {
+        newList = structuredClone(menuList);//menuList.slice(0, menuList.length); // shallow copy
+        newList.push(lengthToAdd);
+        return newList;
+    }
+    return menuList;
 };
 
+var defaultLengthMenu = (data) => {
+    menuList = []
+    var lengths = [10, 25, 50, 100, 1000, data.length];
+    lengths.forEach((len) => {
+        menuList = addTableLength(menuList, len, data.length);
+    });
+    return menuList;
+};
 
-var toggleCheck = (checkboxOrRadio) => {
-    if (checkboxOrRadio.length > 0) {
-        var currentState = checkboxOrRadio.prop("checked");
-        var newState = !currentState;
-        if (currentState == true && checkboxOrRadio.attr("type").toLowerCase() == "radio") {
-            // We don't want to toggle from true to false by clicking on the row
-            // if it is a radio button.
-            newState = currentState;
+var buildDataTable = (tableId, data = [], columns = [], userSettings = {}) => {
+    var defaultSettings = {
+        responsive: true,
+        layout: {
+            topStart: null,
+            topEnd: null,
+            bottomStart: null,
+            bottomEnd: null,
+        },
+        select: true,
+        lengthMenu: defaultLengthMenu(data),
+        language: {
+            processing: "Processing… Please wait.",
+            loadingRecords: "Loading table data… Please wait.",
+            lengthMenu: "",
+            info: ""
+        },
+        data: data,
+        columns: columns,
+        drawCallback: (settings) => {
+            $(this[0]).find("tbody tr").each((idx, row) => {
+                var arow = $(row);
+                var checkboxOrRadio = arow.find(".chk-row-select");
+                if (checkboxOrRadio) {
+                    if (arow.hasClass("selected")) {
+                        checkboxOrRadio.prop("checked", true);
+                    } else {
+                        checkboxOrRadio.prop("checked", false);
+                    }
+                }
+            });
         }
-        checkboxOrRadio.prop("checked", newState);
-        checkboxOrRadio.trigger("change");
     }
-};
-
-
-var dtAddRowClickHandler = (tableId) => {
-    $(tableId).on("draw.dt", (event) => {
-        $(tableId + " tbody tr").on("click", (event) => {
-            var row = event.target.closest("tr");
-            var checkboxOrRadio = $(row).find(".chk-row-select");
-            toggleCheck(checkboxOrRadio);
+    var theDataTable = $(tableId).DataTable({
+        ...defaultSettings,
+        ...userSettings
+    });
+    theDataTable.on("select", (event, datatable, type, cell, originalEvent) => {
+        datatable.rows({selected: true}).nodes().each((node, index) => {
+            $(node).find(".chk-row-select").prop("checked", true)
         });
     });
+    theDataTable.on("deselect", (event, datatable, type, cell, originalEvent) => {
+        datatable.rows({selected: false}).nodes().each((node, index) => {
+            $(node).find(".chk-row-select").prop("checked", false)
+        });
+    });
+    return theDataTable;
 };
-
-
-var dtAddCommonHandlers = (tableId) => {
-    dtAddRowSelectionHandler(tableId);
-    dtAddRowClickHandler(tableId);
-}
diff --git a/uploader/static/js/debug.js b/uploader/static/js/debug.js
new file mode 100644
index 0000000..eb01209
--- /dev/null
+++ b/uploader/static/js/debug.js
@@ -0,0 +1,40 @@
+/**
+ * The entire purpose of this function is for use to debug values inline
+ * without changing the flow of the code too much.
+ *
+ * This **MUST** be a non-arrow function to allow access to the `arguments`
+ * object.
+ *
+ * This function expects at least one argument.
+ *
+ * If more than one argument is provided, then:
+ * a) the last argument is considered the value, and will be returned
+ * b) all other arguments will be converted to string and output
+ *
+ * If only one argument is provided, it is considered the value, and will be
+ * returned.
+ *
+ * Zero arguments is an error condition.
+ **/
+function __pk__(val) {
+    /* Handle zero arguments */
+    if (arguments.length < 1) {
+        throw new Error("Invalid arguments: Expected at least one argument.");
+    }
+
+    msg = "/********** DEBUG **********/";
+    if (arguments.length > 1) {
+        msg = Array.from(
+            arguments
+        ).slice(
+            0,
+            arguments.length - 1
+        ).map((val) => {
+            return String(val);
+        }).join("; ")
+    }
+
+    value = arguments[arguments.length - 1];
+    console.debug("/********** " + msg + " **********/", value);
+    return value;
+}
diff --git a/uploader/static/js/files.js b/uploader/static/js/files.js
index 9d6bca1..0bde6f7 100644
--- a/uploader/static/js/files.js
+++ b/uploader/static/js/files.js
@@ -84,8 +84,8 @@ var errorHandler = makeResumableHandler("error");
 var markResumableDragAndDropElement = (resumable, fileinput, droparea, browsebutton) => {
     if(resumable.support) {
         //Hide file input element and display drag&drop UI
-        add_class(fileinput, "hidden");
-        remove_class(droparea, "hidden");
+        add_class(fileinput, "visually-hidden");
+        remove_class(droparea, "visually-hidden");
 
         // Define UI elements for browse and drag&drop
         resumable.assignDrop(droparea);
diff --git a/uploader/static/js/misc.js b/uploader/static/js/misc.js
deleted file mode 100644
index cf7b39e..0000000
--- a/uploader/static/js/misc.js
+++ /dev/null
@@ -1,6 +0,0 @@
-"Miscellaneous functions and event-handlers"
-
-$(".not-implemented").click((event) => {
-    event.preventDefault();
-    alert("This feature is not implemented yet. Please bear with us.");
-});
diff --git a/uploader/static/js/populations.js b/uploader/static/js/populations.js
index 5c1f848..89ededa 100644
--- a/uploader/static/js/populations.js
+++ b/uploader/static/js/populations.js
@@ -1,19 +1,9 @@
-var populationDataTable = (populationdata) => {
-    var lengthMenu = [10, 25, 50, 100, 1000];
-    if(populationdata.length > 1000) {
-        lengthMenu.push(populationdata.length)
-    }
-    $("#tbl-select-population").DataTable({
-        responsive: true,
-        lengthMenu: lengthMenu,
-        language: {
-            processing: "Processing… Please wait.",
-            loadingRecords: "Loading population — Please wait.",
-            lengthMenu: "Show _MENU_ populations",
-            info: "Showing _START_ to _END_ of _TOTAL_ populations"
-        },
-        data: populationdata,
-        columns: [
+$(() => {
+    var populationsDataTable = buildDataTable(
+        "#tbl-select-population",
+        JSON.parse(
+            $("#tbl-select-population").attr("data-populations-list")),
+        [
             {
                 data: (apopulation) => {
                     return `<input type="radio" name="population_id"`
@@ -23,17 +13,24 @@ var populationDataTable = (populationdata) => {
                 }
             },
             {
+                searchable: true,
                 data: (apopulation) => {
                     return `${apopulation.FullName} (${apopulation.InbredSetName})`;
                 }
             }
-        ]
-    });
-};
-
-
-$(() => {
-    dtAddCommonHandlers("#tbl-select-population");
-    populationDataTable(JSON.parse(
-        $("#tbl-select-population").attr("data-populations-list")));
+        ],
+        {
+            select: "single",
+            paging: true,
+            scrollY: 700,
+            deferRender: true,
+            scroller: true,
+            scrollCollapse: true,
+            layout: {
+                topStart: "info",
+                topEnd: "search",
+                bottomStart: "pageLength",
+                bottomEnd: false
+            }
+        });
 });
diff --git a/uploader/static/js/pubmed.js b/uploader/static/js/pubmed.js
new file mode 100644
index 0000000..9afd4c3
--- /dev/null
+++ b/uploader/static/js/pubmed.js
@@ -0,0 +1,113 @@
+var extract_details = (pubmed_id, details) => {
+    var months = {
+        "jan": "January",
+        "feb": "February",
+        "mar": "March",
+        "apr": "April",
+        "may": "May",
+        "jun": "June",
+        "jul": "July",
+        "aug": "August",
+        "sep": "September",
+        "oct": "October",
+        "nov": "November",
+        "dec": "December"
+    };
+    var _date = details[pubmed_id].pubdate.split(" ");
+    return {
+        "authors": details[pubmed_id].authors.map((authobj) => {
+            return authobj.name;
+        }),
+        "title": details[pubmed_id].title,
+        "journal": details[pubmed_id].fulljournalname,
+        "volume": details[pubmed_id].volume,
+        "pages": details[pubmed_id].pages,
+        "month": _date.length > 1 ? months[_date[1].toLowerCase()] : "jan",
+        "year": _date[0],
+    };
+};
+
+var update_publication_details = (details) => {
+    Object.entries(details).forEach((entry) => {;
+                                                switch(entry[0]) {
+                                                case "authors":
+                                                    $("#txt-publication-authors").val(entry[1].join(", "));
+                                                    break;
+                                                case "month":
+                                                    $("#select-publication-month")
+                                                        .children("option")
+                                                        .each((index, child) => {
+                                                            console.debug(entry[1].toLowerCase());
+                                                            child.selected = child.value == entry[1].toLowerCase();
+                                                        });
+                                                default:
+                                                    $("#txt-publication-" + entry[0]).val(entry[1]);
+                                                    break;
+                                                }
+                                               });
+};
+
+var fetch_publication_abstract = (pubmed_id, pub_details) => {
+    $.ajax("https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi",
+           {
+               "method": "GET",
+               "data": {
+                   "db": "pubmed",
+                   "id": pubmed_id,
+                   "rettype": "abstract",
+                   "retmode": "xml"
+               },
+               "success": (data, textStatus, jqXHR) => {
+                   update_publication_details({
+                       ...pub_details,
+                       ...{
+                           "abstract": Array.from(data
+                                                  .getElementsByTagName(
+                                                      "Abstract")[0]
+                                                  .children)
+                               .map((elt) => {return elt.textContent.trim();})
+                               .join("\r\n")
+                       }});
+               },
+               "error": (jqXHR, textStatus, errorThrown) => {},
+               "complete": (jqXHR, textStatus) => {},
+               "dataType": "xml"
+           });
+};
+
+var fetch_publication_details = (pubmed_id, complete_thunks) => {
+    error_display = $("#search-pubmed-id-error");
+    error_display.text("");
+    add_class(error_display, "visually-hidden");
+    $.ajax("https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi",
+           {
+               "method": "GET",
+               "data": {"db": "pubmed", "id": pubmed_id, "format": "json"},
+               "success": (data, textStatus, jqXHR) => {
+                   // process and update publication details
+                   hasError = (
+                       Object.hasOwn(data, "error") ||
+                           Object.hasOwn(data.result[pubmed_id], "error"));
+                   if(hasError) {
+                       error_display.text(
+                           "There was an error fetching a publication with " +
+                               "the given PubMed ID! The error received " +
+                               "was: '" + (
+                                   data.error ||
+                                       data.result[pubmed_id].error) +
+                               "'. Please check ID you provided and try " +
+                               "again.");
+                       remove_class(error_display, "visually-hidden");
+                   } else {
+                       fetch_publication_abstract(
+                           pubmed_id,
+                           extract_details(pubmed_id, data.result));
+                   }
+               },
+               "error": (jqXHR, textStatus, errorThrown) => {},
+               "complete": () => {
+                   complete_thunks.forEach((thunk) => {thunk()});
+               },
+               "dataType": "json"
+           });
+};
diff --git a/uploader/static/js/species.js b/uploader/static/js/species.js
index 1f2aa3b..d42e081 100644
--- a/uploader/static/js/species.js
+++ b/uploader/static/js/species.js
@@ -1,19 +1,9 @@
-var speciesDataTable = (speciesdata) => {
-    var lengthMenu = [10, 25, 50, 100, 1000];
-    if(speciesdata.length > 1000) {
-        lengthMenu.push(speciesdata.length)
-    }
-    $("#tbl-select-species").DataTable({
-        responsive: true,
-        lengthMenu: lengthMenu,
-        language: {
-            processing: "Processing… Please wait.",
-            loadingRecords: "Loading species — Please wait.",
-            lengthMenu: "Show _MENU_ species",
-            info: "Showing _START_ to _END_ of _TOTAL_ species"
-        },
-        data: speciesdata,
-        columns: [
+$(() => {
+    var speciesDataTable = buildDataTable(
+        "#tbl-select-species",
+        JSON.parse(
+            $("#tbl-select-species").attr("data-species-list")),
+        [
             {
                 data: (aspecies) => {
                     return `<input type="radio" name="species_id"`
@@ -26,12 +16,19 @@ var speciesDataTable = (speciesdata) => {
                     return `${aspecies.FullName} (${aspecies.SpeciesName})`;
                 }
             }
-        ]
-    });
-};
-
-$(() => {
-    dtAddCommonHandlers("#tbl-select-species");
-    speciesDataTable(JSON.parse(
-        $("#tbl-select-species").attr("data-species-list")));
+        ],
+        {
+            select: "single",
+            paging: true,
+            scrollY: 700,
+            deferRender: true,
+            scroller: true,
+            scrollCollapse: true,
+            layout: {
+                topStart: "info",
+                topEnd: "search",
+                bottomStart: "pageLength",
+                bottomEnd: false
+            }
+        });
 });
diff --git a/uploader/static/js/utils.js b/uploader/static/js/utils.js
index 045dd47..1b31661 100644
--- a/uploader/static/js/utils.js
+++ b/uploader/static/js/utils.js
@@ -8,3 +8,30 @@ function trigger_change_event(element) {
     evt = new Event("change");
     element.dispatchEvent(evt);
 }
+
+
+var remove_class = (element, classvalue) => {
+    new_classes = (element.attr("class") || "").split(" ").map((val) => {
+        return val.trim();
+    }).filter((val) => {
+        return ((val !== classvalue) &&
+                (val !== ""))
+    }).join(" ");
+
+    if(new_classes === "") {
+        element.removeAttr("class");
+    } else {
+        element.attr("class", new_classes);
+    }
+};
+
+
+var add_class = (element, classvalue) => {
+    remove_class(element, classvalue);
+    element.attr("class", (element.attr("class") || "") + " " + classvalue);
+};
+
+$(".not-implemented").click((event) => {
+    event.preventDefault();
+    alert("This feature is not implemented yet. Please bear with us.");
+});