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
+85
View File
@@ -0,0 +1,85 @@
(function (root, factory) {
if (typeof module === 'object' && module.exports) {
module.exports = factory();
} else {
root.ISMIStools = Object.assign(root.ISMIStools || {}, factory());
}
})(typeof self !== 'undefined' ? self : this, function () {
'use strict';
function escapeHtml(s) {
return String(s == null ? '' : s).replace(/[&<>"']/g, (c) => ({
'&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;'
}[c]));
}
// Builds a printable HTML document replicating the official ISMIS Study Load
// layout (Letter size, 8.5in x 11in). Auto-triggers window.print() on load so
// the user can print or "Save as PDF" at the official dimensions.
function buildStudyLoadHtml(data) {
const header = data.header || {};
const courses = data.courses || [];
const rows = courses.map((c) =>
'<tr>' +
'<td class="col-g">' + escapeHtml(c.group) + '</td>' +
'<td class="col-c">' + escapeHtml(c.courseCode) + '</td>' +
'<td class="col-d">' + escapeHtml(c.description) +
(c.schedule ? '<div class="sched">' + escapeHtml(c.schedule) + '</div>' : '') +
'</td>' +
'<td class="col-t">' + escapeHtml(c.teacher) + '</td>' +
'<td class="col-u">' + escapeHtml(c.units) + '</td>' +
'<td class="col-n">' + escapeHtml(c.status) + '</td>' +
'</tr>'
).join('\n');
const studentLine = [
header.studentId ? '<b>' + escapeHtml(header.studentId) + '</b>' : '',
escapeHtml(header.fullName || ''),
escapeHtml(header.program || ''),
header.yearLevel ? 'Year Level: ' + escapeHtml(header.yearLevel) : ''
].filter(Boolean).join('&nbsp;&nbsp;&nbsp;');
const semester = header.semester ? '<div class="centered">' + escapeHtml(header.semester) + '</div>\n' : '';
const dateRange = header.dateRange ? '<div class="centered">' + escapeHtml(header.dateRange) + '</div>\n' : '';
const dateEnrolled = header.dateEnrolled
? '<div class="date-enrolled">Date Enrolled: ' + escapeHtml(header.dateEnrolled) + '</div>\n'
: '';
const printedBy = 'Printed by: ' + (header.studentId || '') + ' on ' + new Date().toLocaleDateString();
return '<!DOCTYPE html>\n<html>\n<head>\n<meta charset="utf-8">\n' +
'<title>Student\'s Study Load</title>\n<style>\n' +
'@page { size: 8.5in 11in; margin: 0.45in 0.5in; }\n' +
'html, body { margin: 0; padding: 0; }\n' +
'body { font-family: "Segoe UI", Arial, sans-serif; font-size: 9pt; color: #000; }\n' +
'.title { text-align: center; font-weight: bold; font-size: 9.5pt; margin: 0 0 2pt 0; }\n' +
'.centered { text-align: center; margin: 2pt 0; }\n' +
'.date-enrolled { font-style: italic; margin: 3pt 0; }\n' +
'.student { margin: 4pt 0 8pt 0; }\n' +
'table { width: 100%; border-collapse: collapse; border-bottom: 0.75pt solid #000; }\n' +
'thead th { font-weight: normal; font-size: 8pt; text-align: left; ' +
'border-top: 0.75pt solid #000; border-bottom: 0.75pt solid #000; padding: 1pt 2pt; }\n' +
'td { font-size: 8pt; padding: 1pt 2pt; vertical-align: top; }\n' +
'.col-g { width: 5%; } .col-c { width: 9%; } .col-d { width: 37%; }\n' +
'.col-t { width: 24%; } .col-u { width: 6%; text-align: right; } ' +
'.col-n { width: 19%; text-align: right; }\n' +
'.sched { margin-top: 1pt; }\n' +
'.total-row td { padding-top: 6pt; }\n' +
'</style>\n</head>\n<body>\n' +
'<div class="title">STUDENT\'S STUDY LOAD</div>\n' +
semester + dateRange + dateEnrolled +
'<div class="student">' + studentLine + '</div>\n' +
'<table>\n<thead><tr>' +
'<th>GROUP</th><th>COURSE</th><th>COURSE DESCRIPTION</th><th>TEACHER</th><th>UNITS</th><th>NOTE</th>' +
'</tr></thead>\n<tbody>\n' + rows + '\n' +
'<tr class="total-row"><td colspan="6" style="text-align:right;">' +
escapeHtml(data.totalUnits || '') +
'</td></tr>\n</tbody>\n</table>\n' +
'<div style="text-align:right; margin-top:3pt; font-size:8pt;">' + escapeHtml(printedBy) + '</div>\n' +
'<script>window.onload = function () { window.focus(); window.print(); };</script>\n' +
'</body>\n</html>';
}
return { buildStudyLoadHtml };
});