Restructure source tree

This commit is contained in:
Hamcha 2020-06-26 13:59:13 +02:00
parent f179b0805c
commit 3abfef4528
Signed by untrusted user: hamcha
GPG key ID: 41467804B19A3315
10 changed files with 173 additions and 130 deletions

View file

@ -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) {

View file

@ -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
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 // eslint-disable-next-line @typescript-eslint/no-unused-vars
case 66: { export function postProcessHTML(root: HTMLElement, docname: string): void {
const size = parseInt( // This should be noop unless we're testing changes before committing them to processHTML
prompt("Write target ml (0 to reset)", "90"), document.querySelectorAll("img[width]").forEach((img) => {
10 const width = img.getAttribute("width");
);
if (Number.isNaN(size) || size <= 0) { // Don't care if they are not absolutely sized
// Reset to parts/unit if (width.includes("%")) {
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,
}; };

View 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
}
}
});
}

View file

View 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
View 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 };

View file

@ -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);

View file

@ -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 };