From 7fd2b2b3c3c0d7a798146a33a4fd030162b7e352 Mon Sep 17 00:00:00 2001 From: ladddder <151469127+ladddder@users.noreply.github.com> Date: Tue, 5 Dec 2023 16:32:42 +0100 Subject: [PATCH] move script from main to handlers --- cmd/main.go | 15 +-- handlers/script.go | 23 ++++ handlers/script.js | 296 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 320 insertions(+), 14 deletions(-) create mode 100644 handlers/script.go create mode 100644 handlers/script.js diff --git a/cmd/main.go b/cmd/main.go index cf22557..397ba9a 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -19,9 +19,6 @@ import ( //go:embed styles.css var cssData embed.FS -//go:embed script.js -var scriptData embed.FS - //go:embed VERSION var version string @@ -169,17 +166,7 @@ func main() { return c.Send(cssData) }) - // TODO: move to handlers/script.go - app.Get("/script.js", func(c *fiber.Ctx) error { - scriptData, err := scriptData.ReadFile("script.js") - if err != nil { - return c.Status(fiber.StatusInternalServerError).SendString("Internal Server Error") - } - - c.Set("Content-Type", "text/javascript") - - return c.Send(scriptData) - }) + app.Get("/script.js", handlers.Script) app.Get("ruleset", handlers.Ruleset) app.Get("raw/*", handlers.Raw) diff --git a/handlers/script.go b/handlers/script.go new file mode 100644 index 0000000..c35e6ca --- /dev/null +++ b/handlers/script.go @@ -0,0 +1,23 @@ +package handlers + +import ( + "embed" + + "github.com/gofiber/fiber/v2" +) + +//go:embed script.js +var scriptData embed.FS + +func Script(c *fiber.Ctx) error { + + scriptData, err := scriptData.ReadFile("script.js") + if err != nil { + return c.Status(fiber.StatusInternalServerError).SendString("Internal Server Error") + } + + c.Set("Content-Type", "text/javascript") + + return c.Send(scriptData) + +} diff --git a/handlers/script.js b/handlers/script.js new file mode 100644 index 0000000..c430c4e --- /dev/null +++ b/handlers/script.js @@ -0,0 +1,296 @@ +const labels = document.querySelectorAll("label"); +const inputs = document.querySelectorAll('input[type="radio"]'); +const mainElement = document.querySelector("main"); + +const handleDOMContentLoaded = () => { + handleFontChange(); + handleFontSizeChange(); + inputs.forEach((input) => { + const storedValue = localStorage.getItem(input.name); + if (storedValue === input.value) { + input.checked = true; + } + }); + window.removeEventListener("DOMContentLoaded", handleDOMContentLoaded); +}; + +function focusable_children(node) { + const nodes = Array.from( + node.querySelectorAll( + 'a[href], button, input, textarea, select, details, [tabindex]:not([tabindex="-1"])' + ) + ).filter((s) => s.offsetParent !== null); + const index = nodes.indexOf(document.activeElement); + const update = (d) => { + let i = index + d; + i += nodes.length; + i %= nodes.length; + nodes[i].focus(); + }; + return { + next: (selector) => { + const reordered = [ + ...nodes.slice(index + 1), + ...nodes.slice(0, index + 1), + ]; + for (let i = 0; i < reordered.length; i += 1) { + if (!selector || reordered[i].matches(selector)) { + reordered[i].focus(); + return; + } + } + }, + prev: (selector) => { + const reordered = [ + ...nodes.slice(index + 1), + ...nodes.slice(0, index + 1), + ]; + for (let i = reordered.length - 2; i >= 0; i -= 1) { + if (!selector || reordered[i].matches(selector)) { + reordered[i].focus(); + return; + } + } + }, + update, + }; +} + +function trap(node) { + const handle_keydown = (e) => { + if (e.key === "Tab") { + e.preventDefault(); + const group = focusable_children(node); + if (e.shiftKey) { + group.prev(); + } else { + group.next(); + } + } + }; + node.addEventListener("keydown", handle_keydown); + return { + destroy: () => { + node.removeEventListener("keydown", handle_keydown); + }, + }; +} + +const toggleDropdown = () => { + const dropdown = document.getElementById("dropdown"); + const dropdown_panel = document.getElementById("dropdown_panel"); + const focusTrap = trap(dropdown); + + const closeDropdown = () => { + dropdown_panel.classList.add("hidden"); + focusTrap.destroy(); + dropdown.removeEventListener("keydown", handleEscapeKey); + document.removeEventListener("click", handleClickOutside); + inputs.forEach((input) => { + input.removeEventListener("change", handleInputChange); + }); + labels.forEach((label) => { + label.removeEventListener("click", handleLabelSelection); + }); + }; + + const handleClickOutside = (e) => { + if (!dropdown.contains(e.target)) { + closeDropdown(); + } + }; + + const handleEscapeKey = (e) => { + if (e.key === "Escape") { + dropdown_panel.classList.add("hidden"); + closeDropdown(); + } + }; + + const handleInputChange = (e) => { + if (e.target.checked) { + localStorage.setItem(e.target.name, e.target.value); + switch (e.target.name) { + case "theme": { + handleThemeChange(); + break; + } + case "font": { + handleFontChange(); + break; + } + case "fontsize": { + handleFontSizeChange(); + break; + } + default: { + console.error("Unknown event"); + break; + } + } + } + }; + + const handleLabelSelection = (e) => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + const input = document.getElementById(e.target.getAttribute("for")); + input.checked = true; + input.dispatchEvent(new Event("change", { bubbles: true })); + } + }; + + if (dropdown_panel.classList.contains("hidden")) { + dropdown_panel.classList.remove("hidden"); + dropdown.addEventListener("keydown", handleEscapeKey); + inputs.forEach((input) => { + input.addEventListener("change", handleInputChange); + }); + labels.forEach((label) => { + label.addEventListener("keydown", handleLabelSelection); + }); + document.addEventListener("click", handleClickOutside); + } else { + closeDropdown(); + } +}; + +const handleFontChange = () => { + if (mainElement === null) { + return; + } + let font = localStorage.getItem("font"); + if (font === null) { + localStorage.setItem("font", "sans-serif"); + font = "sans-serif"; + } + if (font === "serif") { + mainElement.classList.add("font-serif"); + mainElement.classList.remove("font-sans"); + } else { + mainElement.classList.add("font-sans"); + mainElement.classList.remove("font-serif"); + } +}; + +const changeFontSize = (node, classes) => { + const sizes = [ + "text-xs", + "text-sm", + "text-base", + "text-lg", + "text-xl", + "text-2xl", + "text-3xl", + "text-4xl", + "text-5xl", + "lg:text-4xl", + "lg:text-5xl", + "lg:text-6xl", + ]; + const currentClasses = sizes.filter((size) => node.classList.contains(size)); + node.classList.remove(...currentClasses); + node.classList.add(...classes); +}; + +const handleFontSizeChange = () => { + if (mainElement === null) { + return; + } + let fontSize = localStorage.getItem("fontsize"); + if (fontSize === null) { + localStorage.setItem("fontsize", "text-base"); + fontSize = "text-base"; + } + if (fontSize === "text-sm") { + changeFontSize(document.querySelector("body"), ["text-sm"]); + } else if (fontSize === "text-lg") { + changeFontSize(document.querySelector("body"), ["text-lg"]); + } else { + changeFontSize(document.querySelector("body"), ["text-base"]); + } + + const nodes = document.querySelectorAll( + "h1, h2, h3, h4, h5, h6, code, pre, kbd, table" + ); + if (fontSize === "text-sm") { + changeFontSize(mainElement, ["text-sm"]); + } else if (fontSize === "text-lg") { + changeFontSize(mainElement, ["text-lg"]); + } else { + changeFontSize(mainElement, ["text-base"]); + } + nodes.forEach((node) => { + let classes = ""; + switch (node.tagName) { + case "H1": { + if (fontSize === "text-sm") { + classes = ["text-3xl", "lg:text-4xl"]; + } else if (fontSize === "text-lg") { + classes = ["text-5xl", "lg:text-6xl"]; + } else { + classes = ["text-4xl", "lg:text-5xl"]; + } + break; + } + case "H2": { + if (fontSize === "text-sm") { + classes = ["text-2xl"]; + } else if (fontSize === "text-lg") { + classes = ["text-4xl"]; + } else { + classes = ["text-3xl"]; + } + break; + } + case "H3": { + if (fontSize === "text-sm") { + classes = ["text-xl"]; + } else if (fontSize === "text-lg") { + classes = ["text-3xl"]; + } else { + classes = ["text-2xl"]; + } + break; + } + case "H4": + case "H5": + case "H6": { + if (fontSize === "text-sm") { + classes = ["text-lg"]; + } else if (fontSize === "text-lg") { + classes = ["text-2xl"]; + } else { + classes = ["text-xl"]; + } + break; + } + case "CODE": + case "PRE": + case "KBD": + case "TABLE": { + if (fontSize === "text-sm") { + classes = ["text-xs"]; + } else if (fontSize === "text-lg") { + classes = ["text-base"]; + } else { + classes = ["text-sm"]; + } + break; + } + default: { + if (fontSize === "text-sm") { + classes = ["text-sm"]; + } else if (fontSize === "text-lg") { + classes = ["text-lg"]; + } else { + classes = ["text-base"]; + } + break; + } + } + changeFontSize(node, classes); + }); +}; + +window.addEventListener("DOMContentLoaded", handleDOMContentLoaded);