Restructure source tree
This commit is contained in:
parent
f179b0805c
commit
3abfef4528
10 changed files with 173 additions and 130 deletions
|
@ -1,7 +1,7 @@
|
||||||
import TabManager from "./TabManager";
|
import TabManager from "./ui/TabManager";
|
||||||
import sections from "./sections";
|
import sections from "./ui/sections";
|
||||||
import { nextAnimationFrame } from "./utils";
|
import { nextAnimationFrame } from "./utils";
|
||||||
import { searchBox } from "./search";
|
import { searchBox } from "./scripts/search";
|
||||||
|
|
||||||
// @ts-expect-error: Parcel image import
|
// @ts-expect-error: Parcel image import
|
||||||
import unknown from "~/assets/images/tab-icons/unknown.svg";
|
import unknown from "~/assets/images/tab-icons/unknown.svg";
|
||||||
|
@ -51,7 +51,7 @@ async function load() {
|
||||||
manager.setLoading(false);
|
manager.setLoading(false);
|
||||||
|
|
||||||
// Set first page as active
|
// Set first page as active
|
||||||
manager.setActive("Guide_to_chemistry");
|
manager.setActive("Infections");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if ("serviceWorker" in navigator) {
|
if ("serviceWorker" in navigator) {
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import { darken, ColorFmt, lighten } from "./darkmode";
|
import { darken, ColorFmt, lighten } from "./darkmode";
|
||||||
import { registerSearchEntries } from "./search";
|
import { registerSearchEntries } from "./search";
|
||||||
import { findParent } from "./utils";
|
import { findParent } from "./utils";
|
||||||
|
import chemistryScript from "./pages/chemistry";
|
||||||
|
|
||||||
// This is used for cache busting when userscript changes significantly.
|
// This is used for cache busting when userscript changes significantly.
|
||||||
// Only change it when you made changes to the processHTML part!
|
// Only change it when you made changes to the processHTML part!
|
||||||
export const CURRENT_VERSION = "bb7abd544a19369d4b6b7e3dde3eb3cc34c023d4";
|
export const CURRENT_VERSION = "bb7abd544a19369d4b6b7e3dde3eb3cc34c023d4";
|
||||||
|
|
||||||
|
const MAX_WIDTH = 440;
|
||||||
|
|
||||||
function chemistryFixups(root: HTMLElement) {
|
function chemistryFixups(root: HTMLElement) {
|
||||||
// Fix inconsistencies with <p> on random parts
|
// Fix inconsistencies with <p> on random parts
|
||||||
// Ideally I'd like a <p> or something on every part, wrapping it completely, but for now let's just kill 'em
|
// Ideally I'd like a <p> or something on every part, wrapping it completely, but for now let's just kill 'em
|
||||||
|
@ -246,115 +249,35 @@ export function processHTML(root: HTMLElement, docname: string): void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function chemistryScript(root: HTMLElement) {
|
function virologyScript(root: HTMLElement): void {
|
||||||
// Add event to autofill child checkboxes
|
const symptoms = document.querySelector("#Symptoms_Table .wikitable");
|
||||||
root
|
//parseTable(symptoms);
|
||||||
.querySelectorAll(".bgus_part_tooltip > .bgus_checkbox")
|
}
|
||||||
.forEach((box: HTMLInputElement) => {
|
|
||||||
const tooltip = box.parentElement.nextElementSibling;
|
|
||||||
box.addEventListener("click", () => {
|
|
||||||
tooltip
|
|
||||||
.querySelectorAll(".bgus_checkbox")
|
|
||||||
.forEach((el: HTMLInputElement) => {
|
|
||||||
el.checked = box.checked;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add event to collapse subsections
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
root.querySelectorAll(".bgus_nested_element").forEach((twistie) => {
|
export function postProcessHTML(root: HTMLElement, docname: string): void {
|
||||||
twistie.addEventListener("click", () => {
|
// This should be noop unless we're testing changes before committing them to processHTML
|
||||||
twistie.classList.toggle("bgus_collapsed");
|
document.querySelectorAll("img[width]").forEach((img) => {
|
||||||
});
|
const width = img.getAttribute("width");
|
||||||
});
|
|
||||||
|
|
||||||
const setPartSize = (labels, ml) => {
|
// Don't care if they are not absolutely sized
|
||||||
labels.forEach((el) => {
|
if (width.includes("%")) {
|
||||||
const part = el.parentElement.dataset.amount;
|
|
||||||
const total = el.parentElement.parentElement.dataset.parts;
|
|
||||||
const amt = Math.ceil(ml * (part / total));
|
|
||||||
el.innerHTML = `${amt} ml`;
|
|
||||||
// Lookup tooltips
|
|
||||||
let next = el.parentElement.nextElementSibling;
|
|
||||||
while (next) {
|
|
||||||
if (next.classList.contains("tooltip")) {
|
|
||||||
const sublabels = [];
|
|
||||||
next.querySelector(".tooltiptext").childNodes.forEach((ch) => {
|
|
||||||
if (ch.classList && ch.classList.contains("bgus_part")) {
|
|
||||||
sublabels.push(ch.querySelector(".bgus_part_label"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
setPartSize(sublabels, amt);
|
|
||||||
}
|
|
||||||
if (next.classList.contains("bgus_part")) {
|
|
||||||
// Done searching
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
next = next.nextElementSibling;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Init fuzzy search with elements
|
|
||||||
const el = Array.from(
|
|
||||||
root.querySelectorAll<HTMLElement>(
|
|
||||||
"table.wikitable > tbody > tr:not(:first-child) > th"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
registerSearchEntries(
|
|
||||||
el.map((element, id) => ({
|
|
||||||
page: "Guide_to_chemistry",
|
|
||||||
name: element
|
|
||||||
.querySelector(".reagent-header")
|
|
||||||
.textContent.trim()
|
|
||||||
.replace("▮", ""),
|
|
||||||
element,
|
|
||||||
alignment: "center",
|
|
||||||
id,
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
|
|
||||||
document.body.addEventListener("keydown", (ev) => {
|
|
||||||
if (ev.shiftKey) {
|
|
||||||
switch (ev.keyCode) {
|
|
||||||
// SHIFT+C = Toggle checkboxes
|
|
||||||
case 67: {
|
|
||||||
root.classList.toggle("bgus_cbox");
|
|
||||||
root
|
|
||||||
.querySelectorAll(".bgus_checkbox:checked")
|
|
||||||
.forEach((sel: HTMLInputElement) => {
|
|
||||||
sel.checked = false;
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// SHIFT+B = Set whole size (beaker?) for parts/units
|
|
||||||
case 66: {
|
|
||||||
const size = parseInt(
|
|
||||||
prompt("Write target ml (0 to reset)", "90"),
|
|
||||||
10
|
|
||||||
);
|
|
||||||
if (Number.isNaN(size) || size <= 0) {
|
|
||||||
// Reset to parts/unit
|
|
||||||
root
|
|
||||||
.querySelectorAll(".bgus_part_label")
|
|
||||||
.forEach((sel: HTMLElement) => {
|
|
||||||
sel.innerHTML = sel.dataset.src;
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setPartSize(
|
|
||||||
root.querySelectorAll("td > .bgus_part > .bgus_part_label"),
|
|
||||||
+size
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
const widthI = parseInt(width, 10);
|
||||||
// Do nothing
|
if (widthI > MAX_WIDTH) {
|
||||||
}
|
img.setAttribute("width", "100%");
|
||||||
|
img.removeAttribute("height"); // Remove any height so we don't have to deal with the crazy math
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
switch (docname) {
|
||||||
|
case "Infections":
|
||||||
|
virologyScript(root);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function genericScript(root: HTMLElement, docname: string) {
|
function genericScript(root: HTMLElement, docname: string) {
|
||||||
|
@ -387,6 +310,7 @@ export function bindFunctions(root: HTMLElement, docname: string): void {
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
CURRENT_VERSION,
|
CURRENT_VERSION,
|
||||||
|
postProcessHTML,
|
||||||
processHTML,
|
processHTML,
|
||||||
bindFunctions,
|
bindFunctions,
|
||||||
};
|
};
|
112
src/scripts/pages/chemistry.ts
Normal file
112
src/scripts/pages/chemistry.ts
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
import { registerSearchEntries } from "../search";
|
||||||
|
|
||||||
|
export default function chemistryScript(root: HTMLElement): void {
|
||||||
|
// Add event to autofill child checkboxes
|
||||||
|
root
|
||||||
|
.querySelectorAll(".bgus_part_tooltip > .bgus_checkbox")
|
||||||
|
.forEach((box: HTMLInputElement) => {
|
||||||
|
const tooltip = box.parentElement.nextElementSibling;
|
||||||
|
box.addEventListener("click", () => {
|
||||||
|
tooltip
|
||||||
|
.querySelectorAll(".bgus_checkbox")
|
||||||
|
.forEach((el: HTMLInputElement) => {
|
||||||
|
el.checked = box.checked;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add event to collapse subsections
|
||||||
|
root.querySelectorAll(".bgus_nested_element").forEach((twistie) => {
|
||||||
|
twistie.addEventListener("click", () => {
|
||||||
|
twistie.classList.toggle("bgus_collapsed");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const setPartSize = (labels, ml) => {
|
||||||
|
labels.forEach((el) => {
|
||||||
|
const part = el.parentElement.dataset.amount;
|
||||||
|
const total = el.parentElement.parentElement.dataset.parts;
|
||||||
|
const amt = Math.ceil(ml * (part / total));
|
||||||
|
el.innerHTML = `${amt} ml`;
|
||||||
|
// Lookup tooltips
|
||||||
|
let next = el.parentElement.nextElementSibling;
|
||||||
|
while (next) {
|
||||||
|
if (next.classList.contains("tooltip")) {
|
||||||
|
const sublabels = [];
|
||||||
|
next.querySelector(".tooltiptext").childNodes.forEach((ch) => {
|
||||||
|
if (ch.classList && ch.classList.contains("bgus_part")) {
|
||||||
|
sublabels.push(ch.querySelector(".bgus_part_label"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setPartSize(sublabels, amt);
|
||||||
|
}
|
||||||
|
if (next.classList.contains("bgus_part")) {
|
||||||
|
// Done searching
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
next = next.nextElementSibling;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Init fuzzy search with elements
|
||||||
|
const el = Array.from(
|
||||||
|
root.querySelectorAll<HTMLElement>(
|
||||||
|
"table.wikitable > tbody > tr:not(:first-child) > th"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
registerSearchEntries(
|
||||||
|
el.map((element, id) => ({
|
||||||
|
page: "Guide_to_chemistry",
|
||||||
|
name: element
|
||||||
|
.querySelector(".reagent-header")
|
||||||
|
.textContent.trim()
|
||||||
|
.replace("▮", ""),
|
||||||
|
element,
|
||||||
|
alignment: "center",
|
||||||
|
id,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
|
document.body.addEventListener("keydown", (ev) => {
|
||||||
|
if (ev.shiftKey) {
|
||||||
|
switch (ev.keyCode) {
|
||||||
|
// SHIFT+C = Toggle checkboxes
|
||||||
|
case 67: {
|
||||||
|
root.classList.toggle("bgus_cbox");
|
||||||
|
root
|
||||||
|
.querySelectorAll(".bgus_checkbox:checked")
|
||||||
|
.forEach((sel: HTMLInputElement) => {
|
||||||
|
sel.checked = false;
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SHIFT+B = Set whole size (beaker?) for parts/units
|
||||||
|
case 66: {
|
||||||
|
const size = parseInt(
|
||||||
|
prompt("Write target ml (0 to reset)", "90"),
|
||||||
|
10
|
||||||
|
);
|
||||||
|
if (Number.isNaN(size) || size <= 0) {
|
||||||
|
// Reset to parts/unit
|
||||||
|
root
|
||||||
|
.querySelectorAll(".bgus_part_label")
|
||||||
|
.forEach((sel: HTMLElement) => {
|
||||||
|
sel.innerHTML = sel.dataset.src;
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setPartSize(
|
||||||
|
root.querySelectorAll("td > .bgus_part > .bgus_part_label"),
|
||||||
|
+size
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
0
src/scripts/pages/virology.ts
Normal file
0
src/scripts/pages/virology.ts
Normal file
|
@ -1,5 +1,5 @@
|
||||||
import { nextAnimationFrame } from "./utils";
|
import { nextAnimationFrame } from "../utils";
|
||||||
import TabManager from "./TabManager";
|
import TabManager from "../ui/TabManager";
|
||||||
|
|
||||||
interface SearchEntry {
|
interface SearchEntry {
|
||||||
page: string;
|
page: string;
|
15
src/scripts/utils.ts
Normal file
15
src/scripts/utils.ts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
export function findParent(
|
||||||
|
base: HTMLElement,
|
||||||
|
matchFn: (candidate: HTMLElement) => boolean
|
||||||
|
): HTMLElement | null {
|
||||||
|
let parent = base.parentElement;
|
||||||
|
while (parent != null) {
|
||||||
|
if (matchFn(parent)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
parent = parent.parentElement;
|
||||||
|
}
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default { findParent };
|
|
@ -1,10 +1,14 @@
|
||||||
// @ts-expect-error: Asset imports are handled by parcel
|
// @ts-expect-error: Asset imports are handled by parcel
|
||||||
import speen from "~/assets/images/speen.svg";
|
import speen from "~/assets/images/speen.svg";
|
||||||
import { getPageHTML } from "./wiki";
|
import { getPageHTML } from "../wiki";
|
||||||
import { processHTML, bindFunctions, CURRENT_VERSION } from "./userscript";
|
import {
|
||||||
import cache from "./cache";
|
processHTML,
|
||||||
import { nextAnimationFrame, delay } from "./utils";
|
bindFunctions,
|
||||||
import { TabInfo } from "./sections";
|
CURRENT_VERSION,
|
||||||
|
postProcessHTML,
|
||||||
|
} from "../scripts/index";
|
||||||
|
import cache from "../cache";
|
||||||
|
import { nextAnimationFrame, delay } from "../utils";
|
||||||
|
|
||||||
// @ts-expect-error: Parcel image import
|
// @ts-expect-error: Parcel image import
|
||||||
import unknown from "~/assets/images/tab-icons/unknown.svg";
|
import unknown from "~/assets/images/tab-icons/unknown.svg";
|
||||||
|
@ -76,6 +80,8 @@ async function loadPage(page: string, elem: HTMLElement): Promise<HTMLElement> {
|
||||||
} else {
|
} else {
|
||||||
// Set cached content as HTML
|
// Set cached content as HTML
|
||||||
elem.innerHTML = html;
|
elem.innerHTML = html;
|
||||||
|
|
||||||
|
postProcessHTML(elem, page); // noop in prod, used in dev for testing candidate DOM changes
|
||||||
}
|
}
|
||||||
|
|
||||||
bindFunctions(elem, page);
|
bindFunctions(elem, page);
|
16
src/utils.ts
16
src/utils.ts
|
@ -1,17 +1,3 @@
|
||||||
export function findParent(
|
|
||||||
base: HTMLElement,
|
|
||||||
matchFn: (candidate: HTMLElement) => boolean
|
|
||||||
): HTMLElement | null {
|
|
||||||
let parent = base.parentElement;
|
|
||||||
while (parent != null) {
|
|
||||||
if (matchFn(parent)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
parent = parent.parentElement;
|
|
||||||
}
|
|
||||||
return parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function nextAnimationFrame(): Promise<void> {
|
export function nextAnimationFrame(): Promise<void> {
|
||||||
return new Promise((resolve) => requestAnimationFrame(() => resolve()));
|
return new Promise((resolve) => requestAnimationFrame(() => resolve()));
|
||||||
}
|
}
|
||||||
|
@ -22,4 +8,4 @@ export function delay(ms: number): Promise<void> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default { findParent, nextAnimationFrame, delay };
|
export default { nextAnimationFrame, delay };
|
||||||
|
|
Reference in a new issue