diff --git a/src/SEQTA.ts b/src/SEQTA.ts index 8aac5f43..f89a4124 100644 --- a/src/SEQTA.ts +++ b/src/SEQTA.ts @@ -26,7 +26,7 @@ import { injectYouTubeVideo } from './seqta/ui/VideoLoader' import { initializeSettingsState, settingsState } from './seqta/utils/listeners/SettingsState' import { StorageChangeHandler } from './seqta/utils/listeners/StorageChanges' import { AddBetterSEQTAElements } from './seqta/ui/AddBetterSEQTAElements' -import { eventManager } from './seqta/utils/listeners/EventManager' +import { eventManager, initializeEventManager } from './seqta/utils/listeners/EventManager' declare global { interface Window { @@ -312,7 +312,7 @@ export function OpenWhatsNewPopup() { }) } -async function finishLoad() { +export async function finishLoad() { try { document.querySelector('.legacy-root')?.classList.remove('hidden'); @@ -377,35 +377,63 @@ export function RemoveBackground() { bk3[0].remove() } -export async function waitForElm(selector: string) { - return new Promise((resolve) => { - const querySelector = () => document.querySelector(selector); +export async function waitForElm(selector: string, usePolling: boolean = false, interval: number = 100): Promise { + console.log('[BetterSEQTA+] Waiting for element:', selector); - if (querySelector()) { - return resolve(querySelector()); - } + if (usePolling) { + return new Promise((resolve) => { + const checkForElement = () => { + const element = document.querySelector(selector); + if (element) { + console.log('[BetterSEQTA+] Element found:', selector); + resolve(element); + } else { + setTimeout(checkForElement, interval); + } + }; - const observer = new MutationObserver(() => { - if (querySelector()) { - resolve(querySelector()); - observer.disconnect(); + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', checkForElement); + } else { + checkForElement(); } }); - - if (document.body) { - observer.observe(document.body, { - childList: true, - subtree: true, - }); - } else { - document.addEventListener('DOMContentLoaded', () => { - observer.observe(document.body, { - childList: true, - subtree: true, + } else { + return new Promise((resolve) => { + const registerObserver = () => { + const { unregister } = eventManager.register(`${selector}`, { + customCheck: (element) => element.matches(selector) + }, (element) => { + console.log('[BetterSEQTA+] Element found:', selector); + resolve(element); + unregister(); // Remove the listener once the element is found }); - }); - } - }); + return unregister; + }; + + let unregister = null; + + if (document.readyState === 'loading') { + // DOM is still loading, wait for it to be ready + document.addEventListener('DOMContentLoaded', () => { + unregister = registerObserver(); + }); + } else { + unregister = registerObserver(); + } + + const querySelector = () => document.querySelector(selector); + const element = querySelector(); + + if (element) { + console.log('[BetterSEQTA+] Element found:', selector); + if (unregister) unregister(); + resolve(element); + return; + } + + }); + } } export function GetCSSElement(file: string) { @@ -531,7 +559,9 @@ async function handleSublink(sublink: string | undefined): Promise { case 'home': case undefined: window.location.replace(`${location.origin}/#?page=/home`); - LoadInit(); + console.log('[BetterSEQTA+] Started Init') + if (settingsState.onoff) loadHomePage() + finishLoad(); break; default: await handleDefault(); @@ -565,6 +595,8 @@ async function handleMessages(node: Element): Promise { document.title = 'Direct Messages ― SEQTA Learn'; SortMessagePageItems(node); + if (!settingsState.animations) return; + await waitForElm('[data-message]'); animate( '[data-message]', @@ -579,6 +611,7 @@ async function handleMessages(node: Element): Promise { async function handleDashboard(node: Element): Promise { if (!(node instanceof HTMLElement)) return; + if (!settingsState.animations) return; await waitForElm('.dashlet'); animate( @@ -594,6 +627,7 @@ async function handleDashboard(node: Element): Promise { async function handleDocuments(node: Element): Promise { if (!(node instanceof HTMLElement)) return; + if (!settingsState.animations) return; await waitForElm('.document'); animate( @@ -609,6 +643,7 @@ async function handleDocuments(node: Element): Promise { async function handleReports(node: Element): Promise { if (!(node instanceof HTMLElement)) return; + if (!settingsState.animations) return; await waitForElm('.report'); animate( @@ -652,11 +687,11 @@ export function tryLoad() { elm.classList.remove('active') }) - waitForElm('.code').then((elm: any) => { + waitForElm('.code', true, 50).then((elm: any) => { if (!elm.innerText.includes('BetterSEQTA')) LoadPageElements() }) -updateIframesWithDarkMode() + updateIframesWithDarkMode() // Waits for page to call on load, run scripts document.addEventListener( 'load', @@ -1951,7 +1986,7 @@ export async function loadHomePage() { // Appends the timetable container into the home container document.getElementById('home-container')?.append(Timetable?.firstChild!) - + // Formats the current date used send a request for timetable and notices later const TodayFormatted = date.getFullYear() + '-' + ((date.getMonth() + 1) < 10 ? '0' : '') + (date.getMonth() + 1) + '-' + (date.getDate() < 10 ? '0' : '') + date.getDate() @@ -2462,9 +2497,4 @@ export function documentTextColor() { item.setAttribute('style', 'color: black') } } -} - -function LoadInit() { - console.log('[BetterSEQTA+] Started Init') - if (settingsState.onoff) loadHomePage() -} +} \ No newline at end of file diff --git a/src/background.ts b/src/background.ts index 5d6543ad..84dfd058 100644 --- a/src/background.ts +++ b/src/background.ts @@ -177,6 +177,7 @@ const DefaultValues: SettingsState = { selectedColor: 'linear-gradient(40deg, rgba(201,61,0,1) 0%, RGBA(170, 5, 58, 1) 100%)', originalSelectedColor: '', DarkMode: true, + animations: true, shortcuts: [ { name: 'YouTube', diff --git a/src/seqta/utils/listeners/EventManager.ts b/src/seqta/utils/listeners/EventManager.ts index 5d271dc0..b475192d 100644 --- a/src/seqta/utils/listeners/EventManager.ts +++ b/src/seqta/utils/listeners/EventManager.ts @@ -33,6 +33,12 @@ class EventManager { return EventManager.instance; } + public static async initialize(): Promise { + const instance = EventManager.getInstance(); + await instance.startObserving(); + return instance; + } + public register(event: string, options: EventListenerOptions, callback: (element: Element) => void): { unregister: () => void } { const id = this.generateUniqueId(); if (!this.listeners.has(event)) { @@ -57,7 +63,7 @@ class EventManager { } } - private startObserving(parentElement?: Element): void { + private async startObserving(parentElement?: Element): Promise { const elementToObserve = parentElement || document.documentElement; if (!this.mutationObservers.has(elementToObserve)) { const observer = new MutationObserver(this.handleMutations.bind(this)); @@ -113,6 +119,7 @@ class EventManager { } private async checkElement(element: Element): Promise { + if (element.classList.contains('code')) console.log('Code Detected!'); for (const [event, listeners] of this.listeners.entries()) { for (const { id, options, callback } of listeners) { if (this.matchesOptions(element, options)) { @@ -140,3 +147,4 @@ class EventManager { } export const eventManager = EventManager.getInstance(); +export const initializeEventManager = async () => await EventManager.initialize(); diff --git a/src/types/storage.ts b/src/types/storage.ts index 16e8dc5d..eb073387 100644 --- a/src/types/storage.ts +++ b/src/types/storage.ts @@ -34,6 +34,7 @@ export interface SettingsState { transparencyEffects: boolean; justupdated?: boolean; timeFormat?: string; + animations: boolean; } interface ToggleItem {