(function () { 'use strict'; const MASTER_KEY = 'enabled'; async function isEnabled() { const { enabled } = await browser.storage.local.get(MASTER_KEY); return enabled !== false; } function autoAcceptPrivacy() { const modal = document.getElementById('myModal'); if (!modal) return; const checkbox = document.getElementById('Confirmation'); const submit = document.getElementById('Submit'); if (checkbox && !checkbox.checked) checkbox.click(); if (submit) submit.click(); } function watchPrivacyModal() { autoAcceptPrivacy(); const observer = new MutationObserver(() => autoAcceptPrivacy()); observer.observe(document.body, { childList: true, subtree: true }); setTimeout(() => observer.disconnect(), 30000); } async function autoLogin() { const { profiles } = await browser.storage.local.get('profiles'); const active = (profiles || []).find((p) => p.enabled); if (!active) return; const userField = document.querySelector( 'input[name="Username"], input[id="Username"], input[name="UserName"], input[name="username"], input[id="UserName"], input[id="username"]' ); const passField = document.querySelector('input[type="password"]'); if (!userField || !passField) return; userField.value = active.username; passField.value = active.password; userField.dispatchEvent(new Event('input', { bubbles: true })); passField.dispatchEvent(new Event('input', { bubbles: true })); const form = userField.closest('form') || passField.closest('form'); if (!form) return; setTimeout(() => { const submitBtn = form.querySelector('input[type="submit"], button[type="submit"]'); if (submitBtn) submitBtn.click(); else form.submit(); }, 300); } async function fetchCourseDescription(courseCode, academicPeriod, academicYear, token) { const body = new URLSearchParams(); body.set('Courses', courseCode); body.set('AcademicPeriod', academicPeriod); body.set('AcademicYear', academicYear); body.set('AjaxFormVM.Controller', 'CourseSchedule'); body.set('AjaxFormVM.Action', 'CourseScheduleOffered'); body.set('AjaxFormVM.ResultTargetId', 'CourseScheduleOfferedList'); body.set('AjaxFormVM.LinkToReturn', ''); body.set('AjaxFormVM.LinkToReturnTargetId', ''); body.set('AjaxFormVM.FormHeader', 'Choose term to view courses offered'); body.set('AjaxFormVM.FormHeaderIcon', ''); body.set('AjaxFormVM.FormId', 'CourseScheduleCourseScheduleOffered'); body.set('AjaxFormVM.ShowCloseButton', 'True'); body.set('AjaxFormVM.PreventAutoUpdateTarget', 'True'); body.set('AjaxFormVM.CloseModalAfterSubmit', 'False'); body.set('AjaxFormVM.AjaxFormType', 'Search'); body.set('AjaxFormVM.FormNoteLocation', ''); body.set('AjaxFormVM.SubmitButton.FaIcon', ''); body.set('AjaxFormVM.SubmitButton.ButtonText', ''); body.set('AjaxFormVM.SubmitButton.ButtonSize', ''); body.set('__RequestVerificationToken', token); const resp = await fetch('/CourseSchedule/CourseScheduleOffered?Length=14', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'X-Requested-With': 'XMLHttpRequest' }, body: body.toString(), credentials: 'same-origin' }); if (!resp.ok) throw new Error('Offered courses request failed: ' + resp.status); const html = await resp.text(); const courses = ISMIStools.parseOfferedCourses(html); const match = courses.find((c) => c.courseCode === courseCode); return match ? match.description : ''; } function extractTotalUnits(text) { const m = /Total Units:\s*([\d.]+)/i.exec(text); return m ? m[1] : ''; } async function scrapeStudyLoad() { const table = document.querySelector('table.table-forum'); if (!table) throw new Error('No study load table found on this page.'); const courses = ISMIStools.parseStudyLoadTable(table.outerHTML); if (!courses.length) throw new Error('No courses found in study load table.'); const periodEl = document.getElementById('AcademicPeriod'); const yearEl = document.getElementById('AcademicYear'); const tokenEl = document.querySelector('input[name="__RequestVerificationToken"]'); const academicPeriod = periodEl ? periodEl.value : ''; const academicYear = yearEl ? yearEl.value : ''; const token = tokenEl ? tokenEl.value : ''; // Semester/year come from the search dropdowns the user picked. // AcademicPeriod's selected option label (e.g. "1ST Semester") + year. const periodLabel = (periodEl && periodEl.selectedOptions && periodEl.selectedOptions[0]) ? periodEl.selectedOptions[0].textContent.trim() : ''; const selectedPeriod = periodLabel || academicPeriod; const selectedYear = academicYear; const uniqueCodes = [...new Set(courses.map((c) => c.courseCode))]; const descMap = {}; for (const code of uniqueCodes) { try { descMap[code] = await fetchCourseDescription(code, academicPeriod, academicYear, token); } catch (e) { descMap[code] = ''; } } courses.forEach((c) => { c.description = descMap[c.courseCode] || ''; }); let header = {}; try { const resp = await fetch('/Manage/Student', { credentials: 'same-origin' }); if (!resp.ok) throw new Error('Profile request failed: ' + resp.status); const html = await resp.text(); header = ISMIStools.parseProfilePage(html); } catch (e) { header = {}; } // Semester goes into the header so the PDF shows the dropdown's term/year. header.semester = (selectedPeriod && selectedYear) ? selectedPeriod + ' ' + selectedYear : (header.semester || ''); return { header, courses, period: selectedPeriod, year: selectedYear }; } // ---- On-page Download PDF button ---- const BTN_ID = 'ismisHelperDownloadBtn'; function showToast(msg, isError) { if (window.toastr) { if (isError) window.toastr.error(msg); else window.toastr.success(msg); } else if (isError) { alert(msg); } } function findTotalUnitsP() { const ps = document.querySelectorAll('#StudyLoad p'); for (const p of ps) { if (/Total Units/i.test(p.textContent || '')) return p; } return null; } async function onDownloadPdf() { const btn = document.getElementById(BTN_ID); try { btn.disabled = true; btn.innerHTML = ' Downloading...'; const { header, courses, period: selectedPeriod } = await scrapeStudyLoad(); const included = ISMIStools.filterStudyLoadCourses(courses); if (!included.length) throw new Error('No enrolled courses found.'); const totalUnits = ISMIStools.sumUnits(included); const settings = await browser.storage.local.get(['truncateDescription', 'showYearLevel', 'customYearLevel']); // Resolve the Year Level: custom value wins; otherwise prefer the scraped // value, smart-adjusted (minus one) during SUMMER when the year level has // not yet advanced. header.showYearLevel = settings.showYearLevel !== false; const custom = String(settings.customYearLevel || '').trim(); if (custom) { header.yearLevel = custom; } else if (/summer/i.test(selectedPeriod || '')) { const n = parseInt(header.yearLevel, 10); if (Number.isFinite(n) && n > 1) header.yearLevel = String(n - 1); } const res = await browser.runtime.sendMessage({ type: 'generate-pdf', data: { header, courses: included, totalUnits, truncateDescription: settings.truncateDescription !== false } }); if (!res || !res.ok) throw new Error((res && res.error) || 'PDF generation failed'); showToast('PDF downloaded.'); } catch (err) { showToast('Error: ' + ((err && err.message) || err), true); } finally { btn.disabled = false; btn.innerHTML = ' Download PDF'; } } function injectDownloadButton() { if (document.getElementById(BTN_ID)) return; const unitsP = findTotalUnitsP(); if (!unitsP) return; const wrapper = document.createElement('div'); wrapper.style.display = 'flex'; wrapper.style.alignItems = 'center'; wrapper.style.justifyContent = 'space-between'; wrapper.style.margin = '10px 0'; const btn = document.createElement('button'); btn.id = BTN_ID; btn.type = 'button'; btn.className = 'btn green'; btn.innerHTML = ' Download PDF'; btn.addEventListener('click', onDownloadPdf); unitsP.parentNode.insertBefore(wrapper, unitsP); wrapper.appendChild(btn); wrapper.appendChild(unitsP); } function tryInjectButton() { if (document.getElementById(BTN_ID)) return; if (document.querySelector('#StudyLoad table.table-forum')) injectDownloadButton(); } function watchStudyLoad() { tryInjectButton(); const observer = new MutationObserver((mutations) => { const inStudyLoad = mutations.some( (m) => m.target && m.target.closest && m.target.closest('#StudyLoad') ); if (inStudyLoad) tryInjectButton(); }); observer.observe(document.body, { childList: true, subtree: true }); } (async function init() { if (!(await isEnabled())) return; watchPrivacyModal(); if (/\/Account\/Login/i.test(location.href)) autoLogin(); if (document.getElementById('StudyLoad')) watchStudyLoad(); })(); })();