From 098fc26513b9a32b3a2ebe97af33340b8f8bec81 Mon Sep 17 00:00:00 2001 From: Kari Lavikka Date: Wed, 2 Oct 2024 14:39:24 +0300 Subject: [PATCH] refactor: separate app and gui the gui will allow embedding --- index.html | 22 ++---------- src/gui/app.ts | 25 +++++++++++++ src/gui/{index.ts => gui.ts} | 69 ++++++++++++++++++++++-------------- src/utils.ts | 4 +++ 4 files changed, 74 insertions(+), 46 deletions(-) create mode 100644 src/gui/app.ts rename src/gui/{index.ts => gui.ts} (81%) diff --git a/index.html b/index.html index 3809109..7663910 100644 --- a/index.html +++ b/index.html @@ -11,26 +11,8 @@

Jellyfish Plotter

-
-
-
-
- -
- +
+ diff --git a/src/gui/app.ts b/src/gui/app.ts new file mode 100644 index 0000000..fc10fd6 --- /dev/null +++ b/src/gui/app.ts @@ -0,0 +1,25 @@ +import { DataTables, loadDataTables } from "../data.js"; +import { escapeHtml } from "../utils.js"; +import { setupGui } from "./gui.js"; + +export default async function main() { + const appElement = document.getElementById("app"); + + let tables: DataTables; + try { + tables = await loadDataTables(); + } catch (e) { + showError(appElement, (e as Error).message); + throw e; + } + + setupGui(appElement, tables); +} + +function showError(container: HTMLElement, message: string) { + container.innerHTML = `
${escapeHtml( + message + )}
`; +} + +main(); diff --git a/src/gui/index.ts b/src/gui/gui.ts similarity index 81% rename from src/gui/index.ts rename to src/gui/gui.ts index d4f89cd..453dabb 100644 --- a/src/gui/index.ts +++ b/src/gui/gui.ts @@ -1,9 +1,5 @@ import GUI, { Controller } from "lil-gui"; -import { - DataTables, - filterDataTablesByPatient, - loadDataTables, -} from "../data.js"; +import { DataTables, filterDataTablesByPatient } from "../data.js"; import { tablesToJellyfish } from "../jellyfish.js"; import { CostWeights, @@ -13,6 +9,7 @@ import { import { addInteractions } from "../interactions.js"; import { downloadSvg, downloadPng } from "./download.js"; import { DEFAULT_BELL_PLOT_PROPERTIES } from "../bellplot.js"; +import { escapeHtml } from "../utils.js"; interface GeneralProperties { patient: string | null; @@ -41,22 +38,15 @@ const DEFAULT_LAYOUT_PROPERTIES = { ...DEFAULT_BELL_PLOT_PROPERTIES, } as LayoutProperties; -export default async function main() { - const jellyfishGui = document.querySelector(".jellyfish-gui") as HTMLElement; +export function setupGui(container: HTMLElement, tables: DataTables) { + container.innerHTML = HTML_TEMPLATE; + const jellyfishGui = container.querySelector(".jellyfish-gui") as HTMLElement; const { generalProps, layoutProps, costWeights } = getSavedOrDefaultSettings(); const saveSettings = () => saveSettingsToSessionStorage(generalProps, layoutProps, costWeights); - let tables: DataTables; - try { - tables = await loadDataTables(); - } catch (e) { - showError(jellyfishGui, (e as Error).message); - throw e; - } - const patients = Array.from(new Set(tables.samples.map((d) => d.patient))); generalProps.patient ??= patients[0]; @@ -163,10 +153,12 @@ function updatePlot( } } -function showError(jellyfishGui: HTMLElement, message: string) { - jellyfishGui.querySelector( +function showError(container: HTMLElement, message: string) { + container.querySelector( ".jellyfish-plot" - ).innerHTML = `
${message}
`; + ).innerHTML = `
${escapeHtml( + message + )}
`; } const STORAGE_KEY = "jellyfish-plotter-settings"; @@ -224,13 +216,18 @@ function setupPatientNavigation( .querySelector(".jellyfish-next-patient") .addEventListener("click", () => navigate(1)); - document.addEventListener("keydown", (event) => { - if (event.key === "ArrowLeft") { - navigate(-1); - } else if (event.key === "ArrowRight") { - navigate(1); - } - }); + // If used in the standalone mode, enable keyboard navigation. + // Otherwise, like when multiple instances are embedded in a page, + // we don't want to interfere with the page's keyboard navigation. + if (jellyfishGui?.parentElement.id === "app") { + document.addEventListener("keydown", (event) => { + if (event.key === "ArrowLeft") { + navigate(-1); + } else if (event.key === "ArrowRight") { + navigate(1); + } + }); + } } function makePatientNavigator( @@ -255,4 +252,24 @@ function makePatientNavigator( }; } -main(); +const HTML_TEMPLATE = ` +
+
+
+
+ +
+`; diff --git a/src/utils.ts b/src/utils.ts index 63b149e..542558c 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -41,3 +41,7 @@ export function mapUnion(...maps: Array>): Map { } return union; } + +export function escapeHtml(unsafe: string) { + return unsafe.replace(//g, ">"); +}