diff --git a/index.html b/index.html index 58ad16f..9d53f2a 100644 --- a/index.html +++ b/index.html @@ -445,7 +445,8 @@ function save() { // COMPUTED HELPERS // ══════════════════════════════════════════════════════ function blockMean(blockId) { - const graded = S.courses.filter(c => c.blockId === blockId && c.grade != null && c.grade !== ''); + // passFail courses are excluded from the mean + const graded = S.courses.filter(c => c.blockId === blockId && !c.passFail && c.grade != null && c.grade !== ''); if (!graded.length) return null; const sumWeighted = graded.reduce((s, c) => s + +c.grade * (+c.credits || 0), 0); const sumCoef = graded.reduce((s, c) => s + (+c.credits || 0), 0); @@ -455,6 +456,7 @@ function blockMean(blockId) { // status: 'pass' | 'fail' | 'prog' function status(course) { + if (course.passFail) return 'pass'; // pass/fail courses always count as passed if (course.grade == null || course.grade === '') return 'prog'; if (+course.grade >= 4) return 'pass'; if (course.blockId) { @@ -475,7 +477,8 @@ function gradeClass(g) { return +g >= 5 ? 'g-high' : +g >= 4 ? 'g-mid' : 'g-low'; } -function fmtGrade(g) { +function fmtGrade(g, passFail) { + if (passFail) return 'P/F'; if (g == null || g === '') return '—'; const n = +g; return Number.isInteger(n) ? String(n) : n.toFixed(2).replace(/0+$/, '').replace(/\.$/, ''); @@ -543,11 +546,14 @@ function renderDash() { function dashGlobal() { const all = S.courses; - const graded = all.filter(c => c.grade != null && c.grade !== ''); + // passFail courses excluded from mean, but count for credits/pass rate denominator + const graded = all.filter(c => !c.passFail && c.grade != null && c.grade !== ''); const passed = all.filter(c => status(c) === 'pass'); const totCr = all.reduce((s, c) => s + (+c.credits || 0), 0); const passCr = passed.reduce((s, c) => s + (+c.credits || 0), 0); - const mean = graded.length ? graded.reduce((s, c) => s + +c.grade, 0) / graded.length : null; + const sumW = graded.reduce((s, c) => s + +c.grade * (+c.credits || 0), 0); + const sumC = graded.reduce((s, c) => s + (+c.credits || 0), 0); + const mean = sumC > 0 ? sumW / sumC : null; const passedGraded = graded.filter(c => status(c) === 'pass').length; const rate = graded.length ? Math.round(passedGraded / graded.length * 100) : null; @@ -568,7 +574,7 @@ function dashGlobal() { html += `
${esc(c.name)}
${semName(c.semesterId)}
${c.credits || '—'} - ${fmtGrade(c.grade)} + ${fmtGrade(c.grade, c.passFail)} ${badge(st)} `; }); @@ -636,8 +642,10 @@ function dashSemesters() { const sc = S.courses.filter(c => c.semesterId === sem.id); const totCr = sc.reduce((s, c) => s + (+c.credits || 0), 0); const passCr = sc.filter(c => status(c) === 'pass').reduce((s, c) => s + (+c.credits || 0), 0); - const graded = sc.filter(c => c.grade != null && c.grade !== ''); - const mean = graded.length ? graded.reduce((s, c) => s + +c.grade, 0) / graded.length : null; + const graded = sc.filter(c => !c.passFail && c.grade != null && c.grade !== ''); + const sumW = graded.reduce((s, c) => s + +c.grade * (+c.credits || 0), 0); + const sumC = graded.reduce((s, c) => s + (+c.credits || 0), 0); + const mean = sumC > 0 ? sumW / sumC : null; html += `
${esc(sem.name)} @@ -669,7 +677,7 @@ function coursesMiniTable(courses, showMeta) { rows += `
${esc(c.name)}
${meta ? `
${meta}
` : ''} ${c.credits || '—'} - ${fmtGrade(c.grade)} + ${fmtGrade(c.grade, c.passFail)} ${badge(st)} `; }); @@ -835,6 +843,7 @@ function showCourseModal(id) { const curPlan = c ? (c.planId || '') : ''; const curBlock = c ? (c.blockId || '') : ''; const blockOpts = buildBlockOpts(curPlan, curBlock); + const isPF = c ? !!c.passFail : false; openModal(`