fix: split multi-segment schedules and expand row height to prevent text overlap

This commit is contained in:
adrianbonpin
2026-08-19 00:44:17 +08:00
parent c75850da2e
commit 52360ab559
2 changed files with 21 additions and 5 deletions
+13 -5
View File
@@ -30,12 +30,18 @@
} }
// Format the raw schedule string to match the official PDF style: // Format the raw schedule string to match the official PDF style:
// comma-separate day codes (M W -> M,W) and trim duplicated room suffixes. // comma-separate day codes, trim duplicated room suffixes, and split
// multiple meeting segments onto separate lines.
function formatSchedule(schedule) { function formatSchedule(schedule) {
let s = String(schedule || '').replace(/\s+/g, ' ').trim(); let s = String(schedule || '').replace(/\s+/g, ' ').trim();
if (!s) return s; if (!s) return s;
// Collapse duplicated TC anywhere in the string.
while (/TC\s+TC/.test(s)) s = s.replace(/TC\s+TC/g, 'TC');
// Join adjacent day codes with commas.
s = s.replace(/\b(M|Tu|T|W|Th|F|Sa|Su)\s+(M|Tu|T|W|Th|F|Sa|Su)\b/g, '$1,$2'); s = s.replace(/\b(M|Tu|T|W|Th|F|Sa|Su)\s+(M|Tu|T|W|Th|F|Sa|Su)\b/g, '$1,$2');
s = s.replace(/TC(?:\s+TC)+$/g, 'TC'); // Split concatenated meeting segments (room ending in TC followed by a
// day code) onto separate lines.
s = s.replace(/(TC)\s+(?=(?:Su|Sa|Th|Tu|M|W|F|T)\b)/g, '$1\n');
return s; return s;
} }
@@ -211,7 +217,7 @@
if (c.key === 'description') { if (c.key === 'description') {
lines = wrapLines(cells.description, font, cellSize, c.w - 6); lines = wrapLines(cells.description, font, cellSize, c.w - 6);
const sched = String(cells.schedule || ''); const sched = String(cells.schedule || '');
if (sched) lines.push(...wrapText(sched, font, cellSize, c.w - 6)); if (sched) lines.push(...wrapLines(sched, font, cellSize, c.w - 6));
} else { } else {
lines = wrapLines(cells[c.key], font, cellSize, c.w - 6); lines = wrapLines(cells[c.key], font, cellSize, c.w - 6);
} }
@@ -256,8 +262,10 @@
} }
// Data rows: fixed 24.5pt baseline-to-baseline spacing. Description + // Data rows: fixed 24.5pt baseline-to-baseline spacing. Description +
// schedule stack with 12pt line spacing. // schedule stack with 12pt line spacing. Expand the row height when
const rowHeight = 24.5; // the schedule or wrapped description needs more lines.
const maxLines = Math.max(...linesPerCol.map((l) => l.length));
const rowHeight = Math.max(24.5, maxLines * lineH + 0.5);
if (y - rowHeight < 50) { if (y - rowHeight < 50) {
page = doc.addPage([612, 792]); page = doc.addPage([612, 792]);
y = 792 - 10; y = 792 - 10;
+8
View File
@@ -65,6 +65,14 @@ test('formatSchedule normalizes schedule text', () => {
assert.strictEqual(formatSchedule('M W 07:30 AM - 10:00 AM LB447TC TC'), 'M,W 07:30 AM - 10:00 AM LB447TC'); assert.strictEqual(formatSchedule('M W 07:30 AM - 10:00 AM LB447TC TC'), 'M,W 07:30 AM - 10:00 AM LB447TC');
assert.strictEqual(formatSchedule('T Th 09:00 AM - 10:30 AM LB443TC TC'), 'T,Th 09:00 AM - 10:30 AM LB443TC'); assert.strictEqual(formatSchedule('T Th 09:00 AM - 10:30 AM LB443TC TC'), 'T,Th 09:00 AM - 10:30 AM LB443TC');
assert.strictEqual(formatSchedule('M,W 03:00 PM - 05:30 PM LB443TC'), 'M,W 03:00 PM - 05:30 PM LB443TC'); assert.strictEqual(formatSchedule('M,W 03:00 PM - 05:30 PM LB443TC'), 'M,W 03:00 PM - 05:30 PM LB443TC');
assert.strictEqual(
formatSchedule('T 07:30 AM - 10:30 AM LB448TC TC Th 07:30 AM - 10:30 AM LB448TC'),
'T 07:30 AM - 10:30 AM LB448TC\nTh 07:30 AM - 10:30 AM LB448TC'
);
assert.strictEqual(
formatSchedule('W 01:30 PM - 04:30 PM LB448TC TC M 01:30 PM - 04:30 PM LB448TC'),
'W 01:30 PM - 04:30 PM LB448TC\nM 01:30 PM - 04:30 PM LB448TC'
);
}); });
test('formatFullName reorders first-last names to last-first', () => { test('formatFullName reorders first-last names to last-first', () => {