Grade Changer 1

Changes all grades lower than an A-, to an A (91%). Only works for the overview at home.html. Grade Changer 2 will work on the detailed view.

// ==UserScript==
// @name        Grade Changer 1
// @namespace   GitHub
// @match       *://*.powerschool.*/guardian/home.html*
// @grant       GM_getValue
// @grant       GM_setValue
// @version     2.0
// @author      genZrizzCode
// @description Changes all grades lower than an A-, to an A (91%). Only works for the overview at home.html. Grade Changer 2 will work on the detailed view.
// @license     MIT
// ==/UserScript==

// License: MIT License
// Copyright (c) 2025 genZrizzCode

(function() { // This makes the following code happen immediately
    console.log("%cGrade Changer 1 init.", "font-size: 2em; font-weight: bold; color: #39F;") // %c makes it styleable
    'use strict';
    window.addEventListener('load', async() => { // This makes the following code start when the page loads
        let tbody = document.querySelector('table tbody'); // makes tbody = the first <tbody> on the webpage
        if (tbody) { // If there is a <tbody>:
            tbody.id = 'grade-table'; // Changes the <tbody>'s id to 'grade-table
            console.log('ID added to tbody:', tbody);

            let badLetterGrades = ['B+', 'B', 'B-', 'C+', 'C', 'C-', 'D+', 'D', 'D-', 'F'].map(g => g.toUpperCase()); // Makes sure it is uppercase
            let replacementGrade = 'A<br>91';

            let cells = tbody.querySelectorAll('td'); // Selects all table cells in the <tbody>

            cells.forEach(cell => { // Checks each cell
                let aTag = cell.querySelector('a.bold'); // Finds the <a.bold> with grades
                if (aTag) { // if there even is an <a.bold> element
                    // The following code removes whitespace and checks for a match
                    let rawText = aTag.textContent.replace(/\s+/g, '').toUpperCase(); 
                    let match = rawText.match(/^(A\+|A-|A|B\+|B-|B|C\+|C-|D\+|D-|D|F)/);
                    let gradeText = match ? match[0] : '';

                    if (badLetterGrades.includes(gradeText)) { // If the grade is bad:
                        console.log(`Fixing grade inside <a>: ${gradeText} -> ${replacementGrade}`);
                        aTag.innerHTML = replacementGrade; // Replaces grade
                    }
                } else {
                    let rawText = cell.textContent.replace(/\s+/g, '').toUpperCase();
                    let match = rawText.match(/^(A\+|A-|A|B\+|B-|C\+|C-|D\+|D-|D|F)/);
                    let cellText = match ? match[0] : '';

                    if (badLetterGrades.includes(cellText)) {
                        console.log(`Fixing grade in <td>: ${cellText} -> ${replacementGrade}`);
                        cell.innerHTML = replacementGrade;
                    }
                }
            });
        } else {
            console.log('No tbody found.');
        }
        let runCount = await GM_getValue('runCount', 0);
        runCount += 1;
        await GM_setValue('runCount', runCount);
        console.log(`Grade Changer 1 has run ${runCount} time${runCount === 1 ? '' : 's since version 2.0'}.`);    
        console.log("%cGrade Changer 1 fin.", "font-size: 2em; font-weight: bold; color: #39F;")
    });
})();