From 5b3c3e5006d46f804fbb6103f6d98f8557757d65 Mon Sep 17 00:00:00 2001 From: Alphons Joseph <93847055+Crazypersonalph@users.noreply.github.com> Date: Sat, 24 Jan 2026 17:59:10 +0800 Subject: [PATCH] feat: initial changes (not fixed yet) --- src/plugins/monofile.ts | 8 +- src/seqta/utils/fixTimetableColours.ts | 126 +++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 src/seqta/utils/fixTimetableColours.ts diff --git a/src/plugins/monofile.ts b/src/plugins/monofile.ts index 77ffd39b..7b015aba 100644 --- a/src/plugins/monofile.ts +++ b/src/plugins/monofile.ts @@ -27,6 +27,7 @@ import { OpenWhatsNewPopup } from "@/seqta/utils/Openers/OpenWhatsNewPopup"; import { showPrivacyNotification } from "@/seqta/utils/Openers/OpenPrivacyNotification"; import { updateTimetableTimes } from "@/seqta/utils/updateTimetableTimes"; +import { fixTimetableColours } from "@/seqta/utils/fixTimetableColours"; // JSON content import MenuitemSVGKey from "@/seqta/content/MenuItemSVGKey.json"; @@ -99,7 +100,11 @@ export async function finishLoad() { await showPrivacyNotification(); } - if (settingsState.justupdated && !document.getElementById("whatsnewbk") && !document.getElementById("privacy-notification")) { + if ( + settingsState.justupdated && + !document.getElementById("whatsnewbk") && + !document.getElementById("privacy-notification") + ) { OpenWhatsNewPopup(); } } @@ -257,6 +262,7 @@ async function LoadPageElements(): Promise { }, async () => { await updateTimetableTimes(); + await fixTimetableColours(); }, ); diff --git a/src/seqta/utils/fixTimetableColours.ts b/src/seqta/utils/fixTimetableColours.ts new file mode 100644 index 00000000..65a826f1 --- /dev/null +++ b/src/seqta/utils/fixTimetableColours.ts @@ -0,0 +1,126 @@ +import { waitForElm } from "./waitForElm"; + +let timetableObserver: MutationObserver | null = null; +let isOnTimetablePage = false; +let isInitialized = false; +let abortController: AbortController | null = null; + +let lastSnapshot: String = ""; + +function checkIfOnTimetablePage(): boolean { + return window.location.hash.includes("page=/timetable"); +} + +function startTimetableMonitoring(): void { + if (timetableObserver) return; + + const timetablePage = document.querySelector(".timetablepage"); + if (!timetablePage) return; + + lastSnapshot = Array.from( + timetablePage.querySelectorAll("*"), + (el) => getComputedStyle(el).color, + ).join("|"); + + // Create observer for timetable content changes + timetableObserver = new MutationObserver((mutations) => { + const snapshot = Array.from( + timetablePage.querySelectorAll("*"), + (el) => getComputedStyle(el).color, + ).join("|"); + + if (snapshot !== lastSnapshot) { + // implement colour fix code here + lastSnapshot = snapshot; + } + }); + + timetableObserver.observe(timetablePage, { + childList: true, + subtree: true, + }); +} + +function handleUrlChange(): void { + const currentlyOnTimetable = checkIfOnTimetablePage(); + + if (currentlyOnTimetable !== isOnTimetablePage) { + isOnTimetablePage = currentlyOnTimetable; + + if (isOnTimetablePage) { + // Wait a bit for the page to load, then start monitoring + setTimeout(() => { + startTimetableMonitoring(); + }, 100); + } else { + stopTimetableMonitoring(); + } + } else if (isOnTimetablePage) { + } +} + +function startUrlMonitoring(): void { + if (isInitialized) return; + isInitialized = true; + + // Create abort controller for cleanup + abortController = new AbortController(); + const signal = abortController.signal; + + // Listen for hash changes (more efficient than polling) + window.addEventListener("hashchange", handleUrlChange, { signal }); + window.addEventListener("popstate", handleUrlChange, { signal }); + + // Initial check + handleUrlChange(); +} + +function stopTimetableMonitoring(): void { + if (timetableObserver) { + timetableObserver.disconnect(); + timetableObserver = null; + } +} + +function stopUrlMonitoring(): void { + if (!isInitialized) return; + isInitialized = false; + + // Abort all event listeners at once + if (abortController) { + abortController.abort(); + abortController = null; + } + + stopTimetableMonitoring(); +} + +// Initialize monitoring on page load +if (typeof window !== "undefined") { + // Start URL monitoring immediately + startUrlMonitoring(); +} + +export async function fixTimetableColours(): Promise { + const timetablePage = document.querySelector(".timetablepage"); + if (!timetablePage) return; + + // Wait for time elements to exist if page is still loading + try { + await waitForElm(".timetablepage .time", true, 10); + } catch { + return; + } + + // Start continuous monitoring when this function is called + isOnTimetablePage = checkIfOnTimetablePage(); + if (isOnTimetablePage) { + startTimetableMonitoring(); + startUrlMonitoring(); + } +} + +// Cleanup function for when the module is unloaded +export function cleanup(): void { + stopUrlMonitoring(); +}