(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 getPDFLib() { return (typeof self !== 'undefined' && self.PDFLib) || (typeof globalThis !== 'undefined' && globalThis.PDFLib); } function wrapText(text, font, size, maxWidth) { const words = String(text).split(/\s+/).filter(Boolean); const lines = []; let line = ''; for (const word of words) { const candidate = line ? line + ' ' + word : word; if (font.widthOfTextAtSize(candidate, size) <= maxWidth) { line = candidate; } else { if (line) lines.push(line); line = word; } } if (line) lines.push(line); return lines.length ? lines : ['']; } async function buildStudyLoadPdf(data) { const PDFLib = getPDFLib(); const { PDFDocument, StandardFonts, rgb } = PDFLib; const header = data.header || {}; const courses = data.courses || []; const doc = await PDFDocument.create(); let page = doc.addPage([612, 792]); // Letter const font = doc.embedStandardFont(StandardFonts.Helvetica); const bold = doc.embedStandardFont(StandardFonts.HelveticaBold); const margin = 50; const contentWidth = 612 - margin * 2; let y = 792 - 50; const black = rgb(0, 0, 0); const gray = rgb(0.3, 0.3, 0.3); function center(text, size, fontToUse, dy) { const w = fontToUse.widthOfTextAtSize(text, size); page.drawText(text, { x: (612 - w) / 2, y: y, size, font: fontToUse, color: black }); y -= dy; } function left(text, size, fontToUse, x, dy) { page.drawText(text, { x, y, size, font: fontToUse, color: black }); y -= dy; } // Header center(header.semester || '', 14, bold, 20); center("STUDENT'S STUDY LOAD", 16, bold, 24); center(header.dateRange || '', 11, font, 18); if (header.dateEnrolled) left('Date Enrolled: ' + header.dateEnrolled, 10, font, margin, 16); y -= 6; if (header.studentId) left('Student ID: ' + header.studentId, 10, font, margin, 14); if (header.fullName) left('Name: ' + header.fullName, 10, font, margin, 14); if (header.program) left('Program: ' + header.program, 10, font, margin, 14); if (header.yearLevel) left('Year Level: ' + header.yearLevel, 10, font, margin, 14); y -= 10; // Table columns: NOTE, UNITS, TEACHER, COURSE DESCRIPTION, COURSE, GROUP const cols = [ { key: 'status', label: 'NOTE', x: margin, w: 50 }, { key: 'units', label: 'UNITS', x: margin + 50, w: 45 }, { key: 'teacher', label: 'TEACHER', x: margin + 95, w: 110 }, { key: 'description', label: 'COURSE DESCRIPTION', x: margin + 205, w: 150 }, { key: 'courseCode', label: 'COURSE', x: margin + 355, w: 70 }, { key: 'groupSchedule', label: 'GROUP', x: margin + 425, w: 87 } ]; const cellSize = 9; const headerSize = 9; function drawRow(cells, isHeader) { const f = isHeader ? bold : font; const size = isHeader ? headerSize : cellSize; const linesPerCol = cols.map((c) => wrapText(cells[c.key] || '', f, size, c.w - 6)); const rowHeight = Math.max(...linesPerCol.map((l) => l.length)) * 11 + 8; if (!isHeader && y - rowHeight < 50) { // Row doesn't fit on the current page: start a new page and re-draw the header. page = doc.addPage([612, 792]); y = 792 - 50; drawHeaderRow(); } if (isHeader) { page.drawRectangle({ x: margin, y: y - rowHeight, width: contentWidth, height: rowHeight, color: rgb(0.85, 0.9, 0.95) }); } page.drawRectangle({ x: margin, y: y - rowHeight, width: contentWidth, height: rowHeight, borderColor: black, borderWidth: 0.5 }); for (const c of cols) { page.drawRectangle({ x: c.x, y: y - rowHeight, width: c.w, height: rowHeight, borderColor: black, borderWidth: 0.5 }); } for (let i = 0; i < cols.length; i++) { const c = cols[i]; const lines = linesPerCol[i]; let ty = y - 10; for (const line of lines) { page.drawText(line, { x: c.x + 3, y: ty, size, font: f, color: black }); ty -= 11; } } y -= rowHeight; return true; } function drawHeaderRow() { const headerCells = {}; cols.forEach((c) => { headerCells[c.key] = c.label; }); drawRow(headerCells, true); } drawHeaderRow(); for (const course of courses) { const cells = { status: course.status, units: course.units, teacher: course.teacher, description: course.description, courseCode: course.courseCode, groupSchedule: (course.group ? course.group + ' ' : '') + (course.schedule || '') }; if (!drawRow(cells, false)) break; } y -= 12; if (data.totalUnits) { page.drawText('Total Units: ' + data.totalUnits, { x: margin, y: y, size: 11, font: bold, color: black }); y -= 16; } const printedBy = 'Printed by: ' + (header.studentId || '') + ' on ' + new Date().toLocaleDateString(); page.drawText(printedBy, { x: margin, y: y, size: 9, font, color: gray }); return doc.save(); // returns Promise } return { buildStudyLoadPdf }; });