feat: on-page Download PDF opens Letter-size printable Study Load; drop pdf-lib/background path

This commit is contained in:
adrianbonpin
2026-08-18 19:28:44 +08:00
parent d6bacef1ec
commit cb2beecc0e
12 changed files with 287 additions and 480 deletions
@@ -11,40 +11,42 @@ student portal experience. It provides three features:
1. **Auto-login** — auto-fill and auto-submit the login form from a saved profile.
2. **Auto-accept Privacy Policy** — dismiss the recurring privacy-policy modal.
3. **Study Load PDF** — generate a PDF of the student's study load, replicating the
official ISMIS document, including course descriptions looked up from the
Offered Courses endpoint.
3. **Printable Study Load** — an on-page "Download PDF" button on the Study Load page
that opens a print-ready Letter-size document replicating the official ISMIS Study
Load (with course descriptions looked up from the Offered Courses endpoint),
triggering the browser print dialog so the user can print or "Save as PDF".
A single **master toggle** disables all extension behavior on the portal.
## Architecture
Single MV3 extension, plain JavaScript, no bundler.
Single MV3 extension, plain JavaScript, no bundler. No background script — all logic
runs in the content script (scraping and print-document building happen in-page).
```
ismis-helper/
├── manifest.json # MV3 manifest, permissions, content script, popup
├── background.js # service worker: message routing + PDF generation
├── content.js # runs on ismis.usc.edu.ph: auto-login, privacy, scraping
├── popup.html # popup UI
├── content.js # runs on ismis.usc.edu.ph: auto-login, privacy, button, print flow
├── parsers.js # UMD: table/profile/offered-courses parsing + filtering
├── printdoc.js # UMD: buildStudyLoadHtml (Letter-size printable document)
├── popup.html # popup UI (master toggle + profiles)
├── popup.js # popup logic
├── popup.css # popup styles
├── libs/pdf-lib.min.js # vendored pdf-lib library
└── icons/ # extension icons (16, 32, 48, 128)
```
### Permissions (manifest.json)
- `storage` — persist profiles and the master toggle.
- `downloads` — save the generated Study Load PDF.
- `activeTab` — access the current tab for scraping.
- Content script matches `https://ismis.usc.edu.ph/*`.
- `host_permissions` — `https://ismis.usc.edu.ph/*` for the content script.
- No background, no `downloads` permission (the print flow uses `window.open` +
the browser's print dialog).
## Component 1 — Auto-login
- Content script runs on `https://ismis.usc.edu.ph/Account/Login`.
- Reads the active (first enabled) profile from `browser.storage.local`.
- Locates the username and password input fields (by common `name`/`id` values such
as `UserName`, `Password`, `username`, `password`).
- Reads the active (enabled) profile from `browser.storage.local`.
- Locates the username and password input fields (`name`/`id` = `Username` /
`Password`, with fallback variants).
- Fills both fields, then submits the form (auto-submit).
- If no profile is enabled, or the master toggle is off, does nothing.
@@ -62,68 +64,74 @@ ismis-helper/
- Stored in `browser.storage.local` under key `profiles` as an array of:
`{ id, name, username, password, enabled }`.
- Popup provides add, edit, delete, and enable/disable per profile.
- The first profile with `enabled === true` is used for auto-login.
- Only one profile can be enabled at a time (enabling one disables the others);
that profile is used for auto-login.
- Master toggle stored under key `enabled` (boolean).
## Component 4 — Study Load PDF
## Component 4 — Printable Study Load
### On-page button
- The content script watches the Study Load page (`#StudyLoad`). When the course
table appears (after the user selects academic period/year and searches), it
injects a **"Download PDF"** button below the `12.00 Units / Total Units: 18.00`
footer, styled like the page's buttons (`btn green pull-right`).
### Scrape
- On the Study Load page, parse the course table with columns:
**Group #, Course Code, Schedule, Faculty, Units, Status**.
- Read the total-units footer (e.g. `12.00 Units / Total Units: 18.00`).
- Parse the course table (columns: Group #, Course Code, Schedule, Faculty, Units,
Status) via `parseStudyLoadTable`.
- **Header info** (full name, student ID, program, year level, semester) is scraped
from the **My Profile** page (`/Manage/Student`), which exposes: Full Name,
Student ID, Program, Year Level, and current semester. If the profile page is not
available, the header fields are entered manually in the popup before generating
the PDF.
from the **My Profile** page (`/Manage/Student`).
### Filtering
- **DISSOLVED courses are excluded** (`filterStudyLoadCourses`).
- Total units = sum of the included courses' units (`sumUnits`).
### Description lookup
- For each unique course code, POST to
`https://ismis.usc.edu.ph/CourseSchedule/CourseScheduleOffered` with form data:
- `Courses=<course code>`
- `AcademicPeriod=<selected value>`
- `AcademicYear=<selected value>`
- `__RequestVerificationToken=<token from page>`
- plus the `AjaxFormVM.*` fields observed in the HAR capture.
- Parse the returned HTML table to extract the **Course Description** for the course.
- If lookup fails for a course, leave the description blank and continue.
`https://ismis.usc.edu.ph/CourseSchedule/CourseScheduleOffered` with the
`__RequestVerificationToken` and selected `AcademicPeriod`/`AcademicYear`, then
parse the returned table for the **Course Description**.
- If lookup fails for a course, the description is left blank and generation
continues.
### Manual fallback
- If scraping finds no table, the popup shows a manual entry form for the same fields
(including optional course descriptions).
### PDF generation
- `background.js` uses **pdf-lib** to build the PDF replicating the official layout:
- Header block: semester, "STUDENT'S STUDY LOAD", date range, date enrolled,
student ID, name, program, year level.
- Course table: Course, Course Description, Units, Teacher, Group, Note
(status: REGULAR/PARALLEL/DISSOLVED), Schedule.
- Footer: total units, printed-by line.
- Downloads the PDF via the `downloads` API.
### Print document
- `buildStudyLoadHtml` (printdoc.js) produces a self-contained HTML document at the
official dimensions (**Letter, 8.5in × 11in** via `@page`), replicating the official
layout: title block (STUDENT'S STUDY LOAD, semester, date range, date enrolled),
student info row (ID, name, program, year level), the course table (GROUP, COURSE,
COURSE DESCRIPTION, TEACHER, UNITS, NOTE — NOTE is the status), and a footer
(total units, "Printed by: …").
- The button opens this document in a new window and auto-triggers
`window.print()`, so the user prints or "Save as PDF" at the official dimensions.
- All scraped/entered values are HTML-escaped.
## Data flow
```
popup ──message──▶ background ──message──▶ content (scrape + description lookup)
▲ │
└────────────── data back ◀────────────────────┘
│
▼
pdf-lib → download
Study Load page ──▶ content script (scrape + filter + description lookup)
│
▼
buildStudyLoadHtml (printdoc.js)
│
▼
window.open + window.print() → print / Save as PDF (Letter)
```
## Error handling
- Master toggle off → no extension behavior on the portal.
- No enabled profile → no auto-login.
- Description lookup fails for a course → blank description, PDF still generated.
- Scrape fails entirely → manual entry form in the popup.
- Login fields not found → log a warning, no crash.
- Description lookup fails for a course → blank description, document still opens.
- No enrolled (non-DISSOLVED) courses → error toast, no window opened.
- Popup blocked → toast explaining popups must be allowed for the site.
## Testing
- Node `node:test` suites: parsers (table/profile/offered-courses/filter/sum) and
printdoc (page size, layout, escaping, auto-print).
- Load via `about:debugging` → "Load Temporary Add-on".
- Verify auto-login on the login page.
- Verify privacy modal auto-accept.
- Verify profile add/edit/delete/toggle and master toggle.
- Verify Study Load PDF generation: scrape, description lookup, manual fallback.
- Verify the on-page Download PDF button: appears below the total-units footer,
excludes DISSOLVED courses, and opens the Letter-size printable document.