Skip to content

Commit

Permalink
refactoring to addres github security checks
Browse files Browse the repository at this point in the history
  • Loading branch information
adkinsrs committed Dec 13, 2023
1 parent 74f7ab6 commit 0a1ed64
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 97 deletions.
32 changes: 10 additions & 22 deletions www/js/common.v2.js
Original file line number Diff line number Diff line change
Expand Up @@ -314,18 +314,6 @@ const handleLoginUIUpdates = () => {
End of login-related code
*************************************************************************************/

/**
* Generates an element from the provided HTML string.
*
* @param {string} html - The HTML string to generate the element from.
* @returns {Element} - The generated element.
*/
const generateElements = (html) => {
const template = document.createElement('template');
template.innerHTML = html.trim();
return template.content.children[0]; // htmlCollection that can be appended to a parent HTML
}

/**
* Triggers an event on the given element.
* @param {HTMLElement} el - The element on which to trigger the event.
Expand Down Expand Up @@ -414,29 +402,29 @@ const convertToFormData = (object) => {
* @param {string} [levelClass="is-danger"] - The level class for the toast notification. Defaults to "is-danger".
*/
const createToast = (msg, levelClass="is-danger") => {
const template = `
<div class="notification js-toast ${levelClass} animate__animated animate__fadeInUp animate__faster">
const toast = document.createElement("div");
toast.classList.add("notification", "js-toast", levelClass, "animate__animated", "animate__fadeInUp", "animate__faster");
toast.innerHTML = `
<button class="delete"></button>
${msg}
</div>
`
const html = generateElements(template);
`;


const numToasts = document.querySelectorAll(".js-toast.notification").length;

if (document.querySelector(".js-toast.notification")) {
// If .js-toast notifications are present, append under final notification
// This is to prevent overlapping toast notifications
document.querySelector(".js-toast.notification:last-of-type").insertAdjacentElement("afterend", html);
document.querySelector(".js-toast.notification:last-of-type").insertAdjacentElement("afterend", toast);
// Position new toast under previous toast with CSS
html.style.setProperty("top", `${(numToasts * 70) + 30}px`);
toast.style.setProperty("top", `${(numToasts * 70) + 30}px`);
} else {
// Otherwise prepend to top of main content
document.getElementById("main_c").prepend(html);
document.getElementById("main_c").prepend(toast);
}

// This should get the newly added notification since it is now the first
html.querySelector(".js-toast.notification .delete").addEventListener("click", (event) => {
toast.querySelector(".js-toast.notification .delete").addEventListener("click", (event) => {
const notification = event.target.closest(".js-toast.notification");
notification.remove(notification);
});
Expand All @@ -451,7 +439,7 @@ const createToast = (msg, levelClass="is-danger") => {
}

// remove the toast
html.addEventListener("animationend", (event) => {
toast.addEventListener("animationend", (event) => {
if (event.animationName === "fadeOutDown") {
event.target.remove();
}
Expand Down
19 changes: 9 additions & 10 deletions www/js/compare_datasets.v2.js
Original file line number Diff line number Diff line change
Expand Up @@ -735,15 +735,14 @@ const plotDataToGraph = (data) => {

// NOTE: Plot initially is created to a default width but is responsive.
// Noticed container within our "column" will make full-width go beyond the screen
const divElt = generateElements('<div class="container is-max-desktop" id="plotly_preview"></div>');
plotContainer.append(divElt);
const plotlyPreview = document.getElementById("plotly_preview");
plotlyPreview.classList.add("container", "is-max-desktop");
plotContainer.append(plotlyPreview);

Plotly.purge("plotly_preview"); // clear old Plotly plots

Plotly.newPlot("plotly_preview", plotData, layout, config);


const plotlyPreview = document.getElementById("plotly_preview");

// If plot data is selected, create the right-column table and do other misc things
plotlyPreview.on("plotly_selected", (eventData) => {

Expand Down Expand Up @@ -799,12 +798,12 @@ const plotDataToGraph = (data) => {
}
});

const plotlyNote = generateElements(`
<div id="tip_on_editing" class="notification content is-info is-light">
<p><strong>Tip:</strong> Use the Plotly box and lasso select tools (upper-right) to select genes to view as a table.</p>
const plotlyNote = document.createElement("div");
plotlyNote.id = "tip_on_editing";
plotlyNote.classList.add("notification", "content", "is-info", "is-light");
plotlyNote.innerHTML = `<p><strong>Tip:</strong> Use the Plotly box and lasso select tools (upper-right) to select genes to view as a table.</p>
<p>You can also click the plot title or axis labels to edit them. Hit Enter to apply edit.</p>
</div>`);
<p>You can also click the plot title or axis labels to edit them. Hit Enter to apply edit.</p>`;
plotlyPreview.append(plotlyNote);
}

Expand Down
31 changes: 19 additions & 12 deletions www/js/curator_common.js
Original file line number Diff line number Diff line change
Expand Up @@ -1192,13 +1192,19 @@ const renderDisplayCards = async (userDisplays, ownerDisplays, defaultDisplayId)

// Add titles to each section if there are displays
if (userDisplays.length) {
const userTitle = generateElements(`<p class="has-text-weight-bold is-underlined column is-full">Your Displays</p>`);
const userTitle = document.createElement("p");
userTitle.classList.add("has-text-weight-bold", "is-underlined", "column", "is-full");
userTitle.textContent = "Your Displays";
userDisplaysElt.append(userTitle);

}

if (ownerDisplays.length) {
const ownerTitle = generateElements(`<p class="has-text-weight-bold is-underlined column is-full">Displays by Dataset Owner</p>`);
ownerDisplaysElt.append(ownerTitle);
const ownerTitle = document.createElement("p");
ownerTitle.classList.add("has-text-weight-bold", "is-underlined", "column", "is-full");
ownerTitle.textContent = "Displays by Dataset Owner";
ownerDisplaysElt.append(ownerTitle);

}

for (const display of userDisplays) {
Expand Down Expand Up @@ -1230,24 +1236,25 @@ const renderOrderSortableSeries = (series) => {
// Create parent template
// Designed so the title is a full row and the draggables are 50% width
const parentList = `<ul id="${series}_order_list" class="content column is-two-thirds js-plot-order-sortable"></ul>`;
const template = `
<div id="${series}_order" class="columns is-multiline">

const orderDiv = document.createElement("div");
orderDiv.id = `${series}_order`;
orderDiv.classList.add("columns", "is-multiline");
orderDiv.innerHTML = `
<p id="${series}_order_title" class="has-text-weight-bold column is-full">${series}</p>
${parentList}
</div
`;

const htmlCollection = generateElements(template);
orderContainer.append(htmlCollection);
orderContainer.append(orderDiv);

// Add in list elements
for (const group of levels[series]) {
// If filters are present and group is not in filters, skip
if (facetWidget.filters.hasOwnProperty(series) && !facetWidget.filters[series].includes(group)) continue;

const listElt = `<li class="has-background-grey-lighter has-text-dark">${group}</li>`;
const listCollection = generateElements(listElt);
document.getElementById(`${series}_order_list`).append(listCollection);
const listElt = document.createElement("li");
listElt.classList.add("has-background-grey-lighter", "has-text-dark");
listElt.textContent = group;
document.getElementById(`${series}_order_list`).append(listElt);
}

// Create sortable for this series
Expand Down
75 changes: 46 additions & 29 deletions www/js/dataset_curator.v2.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,10 @@ class PlotlyHandler extends PlotHandler {

// NOTE: Plot initially is created to a default width but is responsive.
// Noticed container within our "column" will make full-width go beyond the screen
const divElt = generateElements('<div class="container is-max-desktop" id="plotly_preview"></div>');
plotContainer.append(divElt);
const plotlyPreview = document.createElement("div");
plotlyPreview.classList.add("container", "is-max-desktop");
plotlyPreview.id = "plotly_preview";
plotContainer.append(plotlyPreview);
Plotly.purge("plotly_preview"); // clear old Plotly plots

if (!plotJson) {
Expand All @@ -164,23 +166,24 @@ class PlotlyHandler extends PlotHandler {
const seriesGroups = levels[seriesName];
return seriesGroups.length > 20;
});
if (overcrowdedSeries.length) {
const template = `
<article class="message is-warning" id="overcrowded_series_warning">
<div class="message-body">
<strong>WARNING:</strong> One or more of the selected categorical series has more than 20 groups. This may cause the plot to be more difficult to read or render properly.
</div>
</article>
`
const elt = generateElements(template);
plotContainer.prepend(elt);

// Add event listener to delete button
const deleteButton = document.getElementById("overcrowded_series_warning").querySelector(".delete");
deleteButton.addEventListener("click", (event) => {
event.target.parentElement.parentElement.remove();
});
if (!overcrowdedSeries.length) {
return;
}
const overcrowdedSeriesWarning = document.createElement("article");
overcrowdedSeriesWarning.classList.add("message", "is-warning");
overcrowdedSeriesWarning.id = "overcrowded_series_warning";
overcrowdedSeriesWarning.innerHTML = `
<div class="message-body">
<strong>WARNING:</strong> One or more of the selected categorical series has more than 20 groups. This may cause the plot to be more difficult to read or render properly.
</div>
`;
plotContainer.prepend(overcrowdedSeriesWarning);

// Add event listener to delete button
const deleteButton = document.getElementById("overcrowded_series_warning").querySelector(".delete");
deleteButton.addEventListener("click", (event) => {
event.target.parentElement.parentElement.remove();
});

}

Expand Down Expand Up @@ -413,8 +416,10 @@ class ScanpyHandler extends PlotHandler {
const plotContainer = document.getElementById("plot_container");
plotContainer.replaceChildren(); // erase plot

const imgElt = generateElements('<img class="image" id="tsne_preview"></img>');
plotContainer.append(imgElt);
const tsnePreview = document.createElement("img");
tsnePreview.classList.add("image");
tsnePreview.id = "tsne_preview";
plotContainer.append(tsnePreview);

if (image) {
document.getElementById("tsne_preview").setAttribute("src", `data:image/png;base64,${image}`);
Expand Down Expand Up @@ -948,8 +953,10 @@ const renderColorPicker = (seriesName) => {
return;
}

const seriesNameHtml = generateElements(`<p class="has-text-weight-bold is-underlined">${seriesName}</p>`);
colorsContainer.append(seriesNameHtml);
const seriesNameElt = document.createElement("p");
seriesNameElt.classList.add("has-text-weight-bold", "is-underlined");
seriesNameElt.textContent = seriesName;
colorsContainer.append(seriesNameElt);

// Otherwise d3 category10 colors
const swatchColors = ["#1f77b4","#ff7f0e","#2ca02c","#d62728","#9467bd","#8c564b","#e377c2","#7f7f7f","#bcbd22","#17becf"];
Expand All @@ -962,13 +969,23 @@ const renderColorPicker = (seriesName) => {
? d3.color(baseColor).darker(darkerLevel).formatHex()
: baseColor; // Cycle through swatch but make darker if exceeding 10 groups
counter++;
const groupHtml = generateElements(`
<p class="is-flex is-justify-content-space-between pr-3">
<span class="has-text-weight-medium">${group}</span>
<input class="js-plot-color" id="${group}_color" type="color" value="${groupColor}" aria-label="Select a color" />
</p>
`);
colorsContainer.append(groupHtml)

const groupElt = document.createElement("p");
groupElt.classList.add("is-flex", "is-justify-content-space-between", "pr-3");

const groupText = document.createElement("span");
groupText.classList.add("has-text-weight-medium");
groupText.textContent = group;

const colorInput = document.createElement("input");
colorInput.classList.add("js-plot-color");
colorInput.id = `${group}_color`;
colorInput.type = "color";
colorInput.value = groupColor;
colorInput.setAttribute("aria-label", "Select a color");

groupElt.append(groupText, colorInput);
colorsContainer.append(groupElt);
}

colorsSection.classList.remove("is-hidden");
Expand Down
18 changes: 10 additions & 8 deletions www/js/gene_collection_manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,7 @@ const addGeneCollectionEventListeners = () => {
const shareUrl = `${currentUrl.substring(0, currentPage)}p?c=${shareId}`;
const gcId = e.currentTarget.dataset.gcId;

if (copyToClipboard(shareUrl)) {
showGcActionNote(gcId, "URL copied to clipboard");
} else {
showGcActionNote(gcId, `Failed to copy to clipboard. URL: ${shareUrl}`);
}
showGcActionNote(gcId, shareUrl);

});
}
Expand Down Expand Up @@ -1098,14 +1094,20 @@ const setupPagination = (pagination) => {

}


/**
* Updates the action note for a given gene collection.
* Displays an action note for a gene collection.
*
* @param {string} gcId - The ID of the gene collection.
* @param {string} msg - The message to display in the action note.
* @param {string} shareUrl - The URL to be copied to the clipboard.
* @returns {void}
*/
const showGcActionNote = (gcId, msg) => {
const showGcActionNote = (gcId, shareUrl) => {
const noteSelector = `#result_gc_id_${gcId} span.js-gc-action-note`;
const noteSelecterElt = document.querySelector(noteSelector);

const msg = copyToClipboard(shareUrl) ? "URL copied to clipboard" : `Failed to copy to clipboard. URL: ${shareUrl}`;

noteSelecterElt.innerHTML = msg;
noteSelecterElt.classList.remove("is-hidden");

Expand Down
42 changes: 26 additions & 16 deletions www/js/multigene_curator.v2.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,10 @@ class GenesAsAxisHandler extends PlotHandler {

// NOTE: Plot initially is created to a default width but is responsive.
// Noticed container within our "column" will make full-width go beyond the screen
const divElt = generateElements('<div class="container is-max-desktop" id="plotly_preview"></div>');
plotContainer.append(divElt);
const plotlyPreview = document.createElement("div");
plotlyPreview.classList.add("container", "is-max-desktop");
plotlyPreview.id = "plotly_preview";
plotContainer.append(plotlyPreview);
Plotly.purge("plotly_preview"); // clear old Plotly plots

if (!this.plotJson) {
Expand Down Expand Up @@ -242,15 +244,22 @@ class GenesAsAxisHandler extends PlotHandler {
for (const classElt of document.getElementsByClassName("js-dash-clusterbar")) {
for (const catColumn of catColumns) {

const template = `<div class="control">
<label class="checkbox">
<input type="checkbox" value="${catColumn}" class="js-dash-clusterbar-checkbox" />
${catColumn}
</label>
<div>`
const clusterbarElt = document.createElement("div");
clusterbarElt.classList.add("control");

const label = document.createElement("label");
label.classList.add("checkbox");

const input = document.createElement("input");
input.type = "checkbox";
input.value = catColumn;
input.classList.add("js-dash-clusterbar-checkbox");
label.appendChild(input);
label.innerHTML += catColumn;
clusterbarElt.appendChild(label);

classElt.appendChild(clusterbarElt);

const html = generateElements(template);
classElt.append(html);
}
}

Expand Down Expand Up @@ -393,8 +402,10 @@ class GenesAsDataHandler extends PlotHandler {

// NOTE: Plot initially is created to a default width but is responsive.
// Noticed container within our "column" will make full-width go beyond the screen
const divElt = generateElements('<div class="container is-max-desktop" id="plotly_preview"></div>');
plotContainer.append(divElt);
const plotlyPreviewElt = document.createElement("div");
plotlyPreviewElt.classList.add("container", "is-max-desktop");
plotlyPreviewElt.id = "plotly_preview";
plotContainer.append(plotlyPreviewElt);
Plotly.purge("plotly_preview"); // clear old Plotly plots

if (!this.plotJson) {
Expand All @@ -414,10 +425,9 @@ class GenesAsDataHandler extends PlotHandler {
const plotlyPreview = document.getElementById("plotly_preview");

// Append small note about using the Plotly selection utilities
const plotlyNote = generateElements(`
<div class="notification is-info is-light">
<p><strong>Tip:</strong> Use the Plotly box and lasso select tools (upper-right) to select genes to view as a table.</p>
</div>`);
const plotlyNote = document.createElement("div");
plotlyNote.classList.add("notification", "is-info", "is-light");
plotlyNote.innerHTML = `<p><strong>Tip:</strong> Use the Plotly box and lasso select tools (upper-right) to select genes to view as a table.</p>`;
plotlyPreview.append(plotlyNote);

// If plot data is selected, create the right-column table and do other misc things
Expand Down

0 comments on commit 0a1ed64

Please sign in to comment.