diff --git a/src/SEQTA.ts b/src/SEQTA.ts
index 60592ffa..c6699e64 100644
--- a/src/SEQTA.ts
+++ b/src/SEQTA.ts
@@ -1763,8 +1763,8 @@ function createAssessmentDateDiv(date: string, value: any, datecase?: any) {
let titlesvg =
stringToHTML(``).firstChild
+
+ `).firstChild
titlediv.append(titlesvg!)
let detailsdiv = document.createElement('div')
@@ -2143,174 +2143,159 @@ async function AddCustomShortcutsToPage() {
}
export async function loadHomePage() {
- // Sends the html data for the home page
console.info('[BetterSEQTA+] Started Loading Home Page')
document.title = 'Home ― SEQTA Learn'
const element = document.querySelector('[data-key=home]')
+ element?.classList.add('active')
- await delay(8)
-
- // Apply the active class to indicate clicked on home button
- element!.classList.add('active')
-
- // Remove all current elements in the main div to add new elements
+ // Cache DOM queries
const main = document.getElementById('main')
-
if (!main) {
console.error('Main element not found.')
return
- } else {
- main!.innerHTML = ''
}
- currentSelectedDate = new Date()
-
- // Creates the root of the home page added to the main div
- let homeContainer = stringToHTML(/* html */`
+ // Create root container first
+ const homeRoot = stringToHTML(`
`)
- // Appends the html file to main div
- // Note: firstChild of html is done due to needing to grab the body from the stringToHTML function
- main.append(homeContainer?.firstChild!)
+ // Clear main and add home root
+ main.innerHTML = ''
+ main.appendChild(homeRoot?.firstChild!)
- // Gets the current date
+ // Get reference to home container for all subsequent additions
+ const homeContainer = document.getElementById('home-container')
+ if (!homeContainer) return
+
+ // Add initial style to prevent flash
+ if (settingsState.animations) {
+ const style = document.createElement('style')
+ style.textContent = `
+ .home-container > div {
+ opacity: 0;
+ transform: translateY(10px) scale(0.99);
+ }
+ `
+ document.head.appendChild(style)
+ }
+
+ // Use DocumentFragment for batch DOM updates inside home-container
+ const fragment = document.createDocumentFragment()
+
+ // Batch state updates
const date = new Date()
+ currentSelectedDate = new Date()
+ const TodayFormatted = formatDate(date)
- // Creates the shortcut container into the home container
- const Shortcut = stringToHTML(/* html */`
+ // Create shortcuts section
+ const shortcutContainer = stringToHTML(`
`)
+ fragment.appendChild(shortcutContainer?.firstChild!)
- // Appends the shortcut container into the home container
- document.getElementById('home-container')?.append(Shortcut?.firstChild!)
-
- // Creates the container div for the timetable portion of the home page
- const Timetable = stringToHTML(/* html */`
-
`
-
- var Notices = stringToHTML(NoticesStr)
- // Appends the shortcut container into the home container
- document.getElementById('home-container')!.append(Notices.firstChild!) // HERE!!!
+
`)
+ fragment.appendChild(notices?.firstChild!)
+ // Single DOM update to home-container
+ homeContainer.appendChild(fragment)
+
+ // Setup event listeners with cleanup
+ const cleanup = setupTimetableListeners()
+
+ // Parallel data fetching
+ const [assessments, classes, prefs] = await Promise.all([
+ GetUpcomingAssessments(),
+ GetActiveClasses(),
+ fetch(`${location.origin}/seqta/student/load/prefs?`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ asArray: true, request: 'userPrefs' })
+ }).then(res => res.json())
+ ])
+
+ // Process data
+ const activeClass = classes.find((c: any) => c.hasOwnProperty("active"))
+ const activeSubjects = activeClass?.subjects || []
+ const activeSubjectCodes = activeSubjects.map((s: any) => s.code)
+ const currentAssessments = assessments
+ .filter((a: any) => activeSubjectCodes.includes(a.code))
+ .sort(comparedate)
+
+ // Initialize components
+ addShortcuts(settingsState.shortcuts)
+ AddCustomShortcutsToPage()
+ await callHomeTimetable(TodayFormatted, true)
+ await CreateUpcomingSection(currentAssessments, activeSubjects)
+
+ // Setup notices
+ const labelArray = prefs.payload
+ .filter((item: any) => item.name === 'notices.filters')
+ .map((item: any) => item.value)
+
+ if (labelArray.length > 0) {
+ setupNotices(labelArray[0].split(' '), TodayFormatted)
+ }
+
+ if (settingsState.notificationcollector) {
+ enableNotificationCollector()
+ }
+
+ // Setup animations
if (settingsState.animations) {
+ // Remove the initial style
+ document.head.querySelector('style:last-child')?.remove()
+
+ // Animate with motion
animate(
'.home-container > div',
{ opacity: [0, 1], y: [10, 0], scale: [0.99, 1] },
@@ -2324,135 +2309,76 @@ export async function loadHomePage() {
)
}
- callHomeTimetable(TodayFormatted)
-
- const GetPrefs = await fetch(`${location.origin}/seqta/student/load/prefs?`, {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ asArray: true, request: 'userPrefs' })
- })
-
- const response = await GetPrefs.json()
-
- const labelArray = response.payload.filter((item: any) => item.name === 'notices.filters').map((item: any) => item.value)
-
- if (labelArray.length !== 0) {
- const labelArray = response.payload.filter((item: any) => item.name === 'notices.filters').map((item: any) => item.value)[0].split(' ')
- const xhr2 = new XMLHttpRequest()
- xhr2.open(
- 'POST',
- `${location.origin}/seqta/student/load/notices?`,
- true
- )
- xhr2.setRequestHeader('Content-Type', 'application/json; charset=utf-8')
-
- xhr2.onreadystatechange = function () {
- if (xhr2.readyState === 4) {
- processNotices(xhr2.response, labelArray);
- }
- };
-
- const dateControl = document.querySelector('input[type="date"]') as HTMLInputElement;
- xhr2.send(JSON.stringify({ date: dateControl.value }));
-
- function onInputChange(e: any) {
- xhr2.open('POST', `${location.origin}/seqta/student/load/notices?`, true);
- xhr2.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
- xhr2.send(JSON.stringify({ date: e.target.value }));
-
- xhr2.onreadystatechange = function () {
- if (xhr2.readyState === 4) {
- processNotices(xhr2.response, labelArray);
- }
- };
- }
-
- dateControl.addEventListener('input', onInputChange);
- }
-
- if (settingsState.notificationcollector) {
- enableNotificationCollector()
- }
-
- const assessments = await GetUpcomingAssessments()
- const classes = await GetActiveClasses()
-
- let activeClass;
-
- // Gets all subjects for the student
- for (let i = 0; i < classes.length; i++) {
- const element = classes[i];
-
- if (element.hasOwnProperty("active")) {
- // Finds the active class list with the current subjects
- activeClass = classes[i]
- }
- }
-
- let activeSubjects = []
- if (activeClass?.subjects) {
- activeSubjects = activeClass.subjects
- }
-
- let activeSubjectCodes = []
-
- // Gets the code for each of the subjects and puts them in an array
- for (let i = 0; i < activeSubjects.length; i++) {
- activeSubjectCodes.push(activeSubjects[i].code)
- }
-
- let CurrentAssessments = []
- for (let i = 0; i < assessments.length; i++) {
- if (activeSubjectCodes.includes(assessments[i].code)) {
- CurrentAssessments.push(assessments[i])
- }
- }
-
- CurrentAssessments.sort(comparedate)
-
- await CreateUpcomingSection(CurrentAssessments, activeSubjects)
+ return cleanup
}
-function processNotices(responseText: any, labelArray: any) {
- const NoticesPayload = JSON.parse(responseText);
- const NoticeContainer = document.getElementById('notice-container');
- if (NoticesPayload.payload.length === 0) {
- if (!NoticeContainer?.innerText) {
- const dummyNotice = document.createElement('div');
- dummyNotice.textContent = 'No notices for today.';
- dummyNotice.classList.add('dummynotice');
- NoticeContainer?.append(dummyNotice);
- }
- } else {
- if (!NoticeContainer?.innerText) {
- document.querySelectorAll('.notice').forEach(e => e.remove());
+// Helper functions
+function formatDate(date: Date): string {
+ const year = date.getFullYear()
+ const month = (date.getMonth() + 1).toString().padStart(2, '0')
+ const day = date.getDate().toString().padStart(2, '0')
+ return `${year}-${month}-${day}`
+}
- NoticesPayload.payload.forEach((notice: any) => {
- if (labelArray.includes(JSON.stringify(notice.label))) {
- let htmlContent = `
-