(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 : ''; 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 = {}; } return { header, courses }; } // ---- 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 = ' Opening...'; const { header, courses } = await scrapeStudyLoad(); const included = ISMIStools.filterStudyLoadCourses(courses); if (!included.length) throw new Error('No enrolled courses found.'); const totalUnits = ISMIStools.sumUnits(included); const html = ISMIStools.buildStudyLoadHtml({ header, courses: included, totalUnits }); const blob = new Blob([html], { type: 'text/html' }); const url = URL.createObjectURL(blob); const win = window.open(url, '_blank'); if (!win) { URL.revokeObjectURL(url); showToast('Popup blocked — allow popups for this site, then try again.', true); return; } // The blob document runs its own onload → window.print(). Never touch // win.document here: if the new tab navigates cross-origin, accessing it // throws "Permission denied". setTimeout(() => URL.revokeObjectURL(url), 60000); showToast('Opened printable Study Load.'); } 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 btn = document.createElement('button'); btn.id = BTN_ID; btn.type = 'button'; btn.className = 'btn green pull-right'; btn.style.margin = '10px 0'; btn.innerHTML = ' Download PDF'; btn.addEventListener('click', onDownloadPdf); unitsP.insertAdjacentElement('afterend', btn); } 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(); })(); })();