From 78b36452aef778b5d58347df4090a05d0256dee2 Mon Sep 17 00:00:00 2001 From: mkelvers Date: Sat, 6 Jun 2026 16:51:12 +0200 Subject: [PATCH] refactor: migrate from htmx:afterSwap to onHtmxLoad --- static/player/main.ts | 15 +++++++-------- static/schedule_board.ts | 9 +++++---- static/timezone.ts | 10 +++++----- static/top_pick_carousel.ts | 18 ++++++++---------- 4 files changed, 25 insertions(+), 27 deletions(-) diff --git a/static/player/main.ts b/static/player/main.ts index 3d28af7..f93300f 100644 --- a/static/player/main.ts +++ b/static/player/main.ts @@ -20,6 +20,7 @@ import { displayTimeFromAbsolute, } from "./timeline"; import { formatTime } from "./controls"; +import { onHtmxLoad, onReady } from "../utils"; let currentContainer: HTMLElement | null = null; let cleanup: (() => void) | null = null; @@ -113,10 +114,9 @@ const initPlayer = (): void => { }; // build video src from mode, token, and saved quality preference - // Only set if not already provided by the inline script during HTML parsing const preferredQuality = safeLocalStorage.getItem("mal:preferred-quality") || "best"; const streamToken = state.modeSources[state.currentMode]?.token; - if (!state.video.src && streamToken) { + if (streamToken) { state.video.src = `${state.streamURL}?mode=${encodeURIComponent(state.currentMode)}&token=${encodeURIComponent(streamToken)}${preferredQuality !== "best" ? `&quality=${encodeURIComponent(preferredQuality)}` : ""}`; } @@ -205,8 +205,6 @@ const initPlayer = (): void => { }; state.video.addEventListener("loadedmetadata", onLoadedMetadata, { signal }); - // inline script runs during HTML parsing before initPlayer; if metadata - // already loaded, fire the handler immediately if (state.video.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA) { onLoadedMetadata(); } @@ -389,10 +387,11 @@ const initPlayer = (): void => { setupThumbnails(); }; -document.addEventListener("DOMContentLoaded", initPlayer); -document.body.addEventListener("htmx:afterSwap", (e: Event) => { - const target = (e as CustomEvent).detail?.target as HTMLElement | null; - if (target?.querySelector("[data-video-player]")) initPlayer(); +onReady(initPlayer); +onHtmxLoad((root) => { + if (root.matches("[data-video-player]") || root.querySelector("[data-video-player]")) { + initPlayer(); + } }); document.body.addEventListener("htmx:beforeSwap", (e: Event) => { diff --git a/static/schedule_board.ts b/static/schedule_board.ts index 79b04c8..b1ba21a 100644 --- a/static/schedule_board.ts +++ b/static/schedule_board.ts @@ -1,3 +1,4 @@ +import { onHtmxLoad, onReady } from "./utils"; import { isJstTimezone, normalizeWeekday, parseHHMM } from "./shared/broadcast"; export {}; @@ -328,13 +329,13 @@ const buildBoard = (section: HTMLElement): void => { }; const initScheduleBoard = (): void => { - const run = (): void => { - const sections = document.querySelectorAll("[data-schedule-section]"); + const run = (root: ParentNode): void => { + const sections = root.querySelectorAll("[data-schedule-section]"); sections.forEach(buildBoard); }; - document.addEventListener("DOMContentLoaded", run); - document.body.addEventListener("htmx:afterSwap", run); + onReady(() => run(document)); + onHtmxLoad((root) => run(root)); }; initScheduleBoard(); diff --git a/static/timezone.ts b/static/timezone.ts index f8b8f6e..e80dcb0 100644 --- a/static/timezone.ts +++ b/static/timezone.ts @@ -7,6 +7,8 @@ import { export {}; +import { onHtmxLoad } from "./utils"; + interface ParsedBroadcast { day: string; hour: number; @@ -188,16 +190,14 @@ const updateNode = (node: Element, localOffsetMinutes: number): void => { updateNextAiring(node, parsed); }; -const updateAll = (): void => { +const updateAll = (root: ParentNode): void => { const localOffsetMinutes = -new Date().getTimezoneOffset(); - const nodes = document.querySelectorAll("[data-jst-text]"); + const nodes = root.querySelectorAll("[data-jst-text]"); nodes.forEach((node) => updateNode(node, localOffsetMinutes)); }; const initTimezoneConversion = (): void => { - // run on initial load and after htmx swaps (content may change) - document.addEventListener("DOMContentLoaded", updateAll); - document.body.addEventListener("htmx:afterSwap", updateAll); + onHtmxLoad((root) => updateAll(root)); }; initTimezoneConversion(); diff --git a/static/top_pick_carousel.ts b/static/top_pick_carousel.ts index d23c4d0..47a766a 100644 --- a/static/top_pick_carousel.ts +++ b/static/top_pick_carousel.ts @@ -24,8 +24,8 @@ const getTopPickCarousel = (root: HTMLElement): TopPickCarousel | null => { return { track, previous, next, previousFade, nextFade }; }; -const topPickCarousels = (): HTMLElement[] => - Array.from(document.querySelectorAll("[data-top-pick-carousel]")); +const topPickCarousels = (root: ParentNode = document): HTMLElement[] => + Array.from(root.querySelectorAll("[data-top-pick-carousel]")); const maxScrollLeft = (track: HTMLElement): number => Math.max(0, track.scrollWidth - track.clientWidth); @@ -56,8 +56,8 @@ const updateTopPickCarousel = (root: HTMLElement): void => { carousel.nextFade.classList.toggle("hidden", !hasNext); }; -const updateTopPickCarousels = (): void => { - topPickCarousels().forEach(updateTopPickCarousel); +const updateTopPickCarousels = (root: ParentNode = document): void => { + topPickCarousels(root).forEach(updateTopPickCarousel); }; const carouselScrollAmount = (track: HTMLElement): number => { @@ -145,9 +145,7 @@ document.addEventListener( true, ); -document.addEventListener("DOMContentLoaded", updateTopPickCarousels); -document.addEventListener("htmx:afterSwap", updateTopPickCarousels); -document.addEventListener("htmx:afterSettle", updateTopPickCarousels); -window.addEventListener("resize", updateTopPickCarousels); - -updateTopPickCarousels(); +onReady(() => updateTopPickCarousels()); +onHtmxLoad((root) => updateTopPickCarousels(root)); +window.addEventListener("resize", () => updateTopPickCarousels()); +import { onHtmxLoad, onReady } from "./utils";