feat: on-page Download PDF opens Letter-size printable Study Load; drop pdf-lib/background path
This commit is contained in:
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user