mirror of
https://github.com/BetterSEQTA/BetterSEQTA-Plus.git
synced 2026-06-06 03:34:40 +00:00
feat: add plugin system
This commit is contained in:
+3
-193
@@ -13,11 +13,9 @@ import {
|
||||
settingsState,
|
||||
} from "@/seqta/utils/listeners/SettingsState"
|
||||
import { StorageChangeHandler } from "@/seqta/utils/listeners/StorageChanges"
|
||||
import { convertTo12HourFormat } from "@/seqta/utils/convertTo12HourFormat"
|
||||
import { eventManager } from "@/seqta/utils/listeners/EventManager"
|
||||
|
||||
// UI and theme management
|
||||
import { enableNotificationCollector } from "@/seqta/utils/CreateEnable/EnableNotificationCollector"
|
||||
import RegisterClickListeners from "@/seqta/utils/listeners/ClickListeners"
|
||||
import { AddBetterSEQTAElements } from "@/seqta/ui/AddBetterSEQTAElements"
|
||||
import { updateAllColors } from "@/seqta/ui/colors/Manager"
|
||||
@@ -240,14 +238,14 @@ async function LoadPageElements(): Promise<void> {
|
||||
handleReports,
|
||||
)
|
||||
|
||||
eventManager.register(
|
||||
/* eventManager.register(
|
||||
"timetableAdded",
|
||||
{
|
||||
elementType: "div",
|
||||
className: "timetablepage",
|
||||
},
|
||||
handleTimetable,
|
||||
)
|
||||
) */
|
||||
|
||||
eventManager.register(
|
||||
"noticesAdded",
|
||||
@@ -274,159 +272,6 @@ async function LoadPageElements(): Promise<void> {
|
||||
await handleSublink(sublink)
|
||||
}
|
||||
|
||||
function handleTimetableZoom(): void {
|
||||
console.log("Initializing timetable zoom controls")
|
||||
|
||||
// Lazy initialize state variables only when function is first called
|
||||
let timetableZoomLevel = 1
|
||||
let baseContainerHeight: number | null = null
|
||||
const originalEntryPositions = new Map<
|
||||
Element,
|
||||
{ topRatio: number; heightRatio: number }
|
||||
>()
|
||||
|
||||
// Create zoom controls
|
||||
const zoomControls = document.createElement("div")
|
||||
zoomControls.className = "timetable-zoom-controls"
|
||||
|
||||
const zoomIn = document.createElement("button")
|
||||
zoomIn.className = "uiButton timetable-zoom iconFamily"
|
||||
zoomIn.innerHTML = "" // Using unicode for zoom in icon
|
||||
|
||||
const zoomOut = document.createElement("button")
|
||||
zoomOut.className = "uiButton timetable-zoom iconFamily"
|
||||
zoomOut.innerHTML = "" // Using unicode for zoom out icon
|
||||
|
||||
zoomControls.appendChild(zoomOut)
|
||||
zoomControls.appendChild(zoomIn)
|
||||
|
||||
const toolbar = document.getElementById("toolbar")
|
||||
toolbar?.appendChild(zoomControls)
|
||||
|
||||
const initializePositions = () => {
|
||||
// Get the base container height from the first TD
|
||||
const firstDayColumn = document.querySelector(
|
||||
".dailycal .content .days td",
|
||||
) as HTMLElement
|
||||
if (!firstDayColumn) return false
|
||||
|
||||
baseContainerHeight =
|
||||
parseInt(firstDayColumn.style.height) || firstDayColumn.offsetHeight
|
||||
|
||||
// Store original ratios
|
||||
const entries = document.querySelectorAll(".entriesWrapper .entry")
|
||||
entries.forEach((entry: Element) => {
|
||||
const entryEl = entry as HTMLElement
|
||||
|
||||
// Calculate ratios relative to detected base height
|
||||
if (baseContainerHeight === null) return
|
||||
const topRatio = parseInt(entryEl.style.top) / baseContainerHeight
|
||||
const heightRatio = parseInt(entryEl.style.height) / baseContainerHeight
|
||||
|
||||
originalEntryPositions.set(entry, { topRatio, heightRatio })
|
||||
})
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
const updateZoom = () => {
|
||||
// Initialize positions if not already done
|
||||
if (baseContainerHeight === null && !initializePositions()) {
|
||||
console.error("Failed to initialize positions")
|
||||
return
|
||||
}
|
||||
|
||||
console.debug(`Updating zoom level to: ${timetableZoomLevel}`)
|
||||
|
||||
// Calculate new container height
|
||||
if (baseContainerHeight === null) return
|
||||
const newContainerHeight = baseContainerHeight * timetableZoomLevel
|
||||
|
||||
// Update all day columns (TDs)
|
||||
const dayColumns = document.querySelectorAll(".dailycal .content .days td")
|
||||
dayColumns.forEach((td: Element) => {
|
||||
(td as HTMLElement).style.height = `${newContainerHeight}px`
|
||||
})
|
||||
|
||||
// Update all entries using stored ratios
|
||||
const entries = document.querySelectorAll(".entriesWrapper .entry")
|
||||
entries.forEach((entry: Element) => {
|
||||
const entryEl = entry as HTMLElement
|
||||
const originalRatios = originalEntryPositions.get(entry)
|
||||
|
||||
if (originalRatios) {
|
||||
// Calculate new positions from original ratios
|
||||
const newTop = originalRatios.topRatio * newContainerHeight
|
||||
const newHeight = originalRatios.heightRatio * newContainerHeight
|
||||
|
||||
// Apply new values
|
||||
entryEl.style.top = `${Math.round(newTop)}px`
|
||||
entryEl.style.height = `${Math.round(newHeight)}px`
|
||||
}
|
||||
})
|
||||
|
||||
// Update time column to match
|
||||
const timeColumn = document.querySelector(".times")
|
||||
if (timeColumn) {
|
||||
const times = timeColumn.querySelectorAll(".time")
|
||||
const timeHeight = newContainerHeight / times.length
|
||||
times.forEach((time: Element) => {
|
||||
(time as HTMLElement).style.height = `${timeHeight}px`
|
||||
})
|
||||
}
|
||||
|
||||
entries[Math.round((entries.length - 1) / 2)].scrollIntoView({
|
||||
behavior: "instant",
|
||||
block: "center",
|
||||
})
|
||||
}
|
||||
|
||||
zoomIn.addEventListener("click", () => {
|
||||
if (timetableZoomLevel < 2) {
|
||||
timetableZoomLevel += 0.2
|
||||
updateZoom()
|
||||
}
|
||||
})
|
||||
|
||||
zoomOut.addEventListener("click", () => {
|
||||
if (timetableZoomLevel > 0.6) {
|
||||
timetableZoomLevel -= 0.2
|
||||
updateZoom()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function handleTimetableAssessmentHide(): void {
|
||||
const hideControls = document.createElement("div") // Creates the div element which houses the eye icon
|
||||
hideControls.className = "timetable-hide-controls"
|
||||
|
||||
const hideOn = document.createElement("button") // Creates the actual button which is clicked
|
||||
hideOn.className = "uiButton timetable-hide iconFamily"
|
||||
hideOn.innerHTML = "👁" // Using unicode for hide icon
|
||||
|
||||
hideControls.appendChild(hideOn)
|
||||
|
||||
const toolbar = document.getElementById("toolbar") // Appends the new button to the toolbar
|
||||
toolbar?.appendChild(hideControls)
|
||||
|
||||
function hideElements(): void {
|
||||
const entries = document.querySelectorAll(".entry") // Gets all the timetables entries on the page, and loops through
|
||||
entries.forEach((entry: Element) => {
|
||||
const entryEl = entry as HTMLElement
|
||||
if (!entryEl.classList.contains("assessment") && !(entryEl.style.opacity === "0.3")) { // If the entry is not an assessment, and hasn't already been hidden, hide it.
|
||||
entryEl.style.opacity = "0.3"
|
||||
} else { // Otherwise, it should be shown.
|
||||
entryEl.style.opacity = "1"
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
hideOn.addEventListener("click", () => { // Listen for when the button is pressed
|
||||
hideElements()
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
async function handleNotices(node: Element): Promise<void> {
|
||||
if (!(node instanceof HTMLElement)) return
|
||||
if (!settingsState.animations) return
|
||||
@@ -454,11 +299,8 @@ async function handleSublink(sublink: string | undefined): Promise<void> {
|
||||
await handleNewsPage()
|
||||
break
|
||||
case undefined:
|
||||
window.location.replace(
|
||||
`${location.origin}/#?page=/${settingsState.defaultPage}`,
|
||||
)
|
||||
window.location.replace(`${location.origin}/#?page=/${settingsState.defaultPage}`)
|
||||
if (settingsState.defaultPage === "home") loadHomePage()
|
||||
if (settingsState.defaultPage === "timetable") handleTimetable()
|
||||
if (settingsState.defaultPage === "documents")
|
||||
handleDocuments(document.querySelector(".documents")!)
|
||||
if (settingsState.defaultPage === "reports")
|
||||
@@ -481,48 +323,16 @@ async function handleSublink(sublink: string | undefined): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
async function handleTimetable(): Promise<void> {
|
||||
await waitForElm(".time", true, 10)
|
||||
|
||||
// Store original heights when timetable loads
|
||||
const lessons = document.querySelectorAll(".dailycal .lesson")
|
||||
lessons.forEach((lesson: Element) => {
|
||||
const lessonEl = lesson as HTMLElement
|
||||
lessonEl.setAttribute(
|
||||
"data-original-height",
|
||||
lessonEl.offsetHeight.toString(),
|
||||
)
|
||||
})
|
||||
|
||||
// Existing time format code
|
||||
if (settingsState.timeFormat == "12") {
|
||||
const times = document.querySelectorAll(".timetablepage .times .time")
|
||||
for (const time of times) {
|
||||
if (!time.textContent) continue
|
||||
time.textContent = convertTo12HourFormat(time.textContent, true)
|
||||
}
|
||||
}
|
||||
|
||||
handleTimetableZoom()
|
||||
handleTimetableAssessmentHide()
|
||||
}
|
||||
|
||||
async function handleNewsPage(): Promise<void> {
|
||||
console.info("[BetterSEQTA+] Started Init")
|
||||
if (settingsState.onoff) {
|
||||
SendNewsPage()
|
||||
if (settingsState.notificationcollector) {
|
||||
enableNotificationCollector()
|
||||
}
|
||||
finishLoad()
|
||||
}
|
||||
}
|
||||
|
||||
async function handleDefault(): Promise<void> {
|
||||
finishLoad()
|
||||
if (settingsState.notificationcollector) {
|
||||
enableNotificationCollector()
|
||||
}
|
||||
}
|
||||
|
||||
async function handleMessages(node: Element): Promise<void> {
|
||||
|
||||
Reference in New Issue
Block a user