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:
// 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) {
let s = String(schedule || '').replace(/\s+/g, ' ').trim();
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(/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;
}
@@ -211,7 +217,7 @@
if (c.key === 'description') {
lines = wrapLines(cells.description, font, cellSize, c.w - 6);
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 {
lines = wrapLines(cells[c.key], font, cellSize, c.w - 6);
}
@@ -256,8 +262,10 @@
}
// Data rows: fixed 24.5pt baseline-to-baseline spacing. Description +
// schedule stack with 12pt line spacing.
const rowHeight = 24.5;
// schedule stack with 12pt line spacing. Expand the row height when
// 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) {
page = doc.addPage([612, 792]);
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('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('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', () => {