Genesis What If?

What if you got a 45/50 on that next test? What would your grade be? This extension answers those questions without you having to manually calculate the answer. All grades are editable, and the buttons are self-explanatory. (New Jersey)

K instalaci tototo skriptu si budete muset nainstalovat rozšíření jako Tampermonkey, Greasemonkey nebo Violentmonkey.

You will need to install an extension such as Tampermonkey to install this script.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Userscripts.

You will need to install an extension such as Tampermonkey to install this script.

K instalaci tohoto skriptu si budete muset nainstalovat manažer uživatelských skriptů.

(Už mám manažer uživatelských skriptů, nechte mě ho nainstalovat!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Už mám manažer uživatelských stylů, nechte mě ho nainstalovat!)

// ==UserScript==
// @name         Genesis What If?
// @namespace    http://tampermonkey.net/
// @version      1.35
// @description  What if you got a 45/50 on that next test? What would your grade be? This extension answers those questions without you having to manually calculate the answer. All grades are editable, and the buttons are self-explanatory. (New Jersey)
// @author       You
// @license      MIT
// @match        https://parents.c3.genesisedu.net/*/parents?tab1=studentdata&tab2=gradebook&tab3=coursesummary*
// @icon         https://parents.robbinsville.k12.nj.us//genesis/images/newIcon2.ico
// @grant        none
// ==/UserScript==

(function() {
const fractionPattern = /(\d+(\.\d+)?) \/ (\d+)/;
var numerator = 0;
var denominator = 0;
// const headings = document.querySelectorAll(".listheading")
let specialnumber = -2

var listHeadings = document.querySelectorAll('.listheading');
var listRowEvens = document.querySelectorAll('.listroweven');
var listRowOdds = document.querySelectorAll('.listrowodd');
function HowManyCategories() {
    var secondListHeading = listHeadings[1];
    var thirdListHeading = listHeadings[2];
    var elementsBetweenHeadings = 0;

    // Iterate through the elements between the second and third list headings
    for (let i = 0; i < listRowEvens.length; i++) {
      let element = listRowEvens[i];

      if (element.compareDocumentPosition(secondListHeading) & Node.DOCUMENT_POSITION_PRECEDING &&
          element.compareDocumentPosition(thirdListHeading) & Node.DOCUMENT_POSITION_FOLLOWING) {
        elementsBetweenHeadings++;
      }
    }

    for (let i = 0; i < listRowOdds.length; i++) {
      let element = listRowOdds[i];

      if (element.compareDocumentPosition(secondListHeading) & Node.DOCUMENT_POSITION_PRECEDING &&
          element.compareDocumentPosition(thirdListHeading) & Node.DOCUMENT_POSITION_FOLLOWING) {
        elementsBetweenHeadings++;
      }
    }

    return elementsBetweenHeadings;
  }
var categoryWeightage = {}
var categoryGrades = {}
function AssignWeightage(row){
    let categoryName = row.querySelector('td.cellLeft b').textContent;
  let weightString = row.querySelector('td.cellRight:nth-child(2)').textContent;
  let weight = parseFloat(weightString.replace('%', '')) / 100; // Convert to decimal
    categoryGrades[categoryName] = [0,0]
      categoryWeightage[categoryName] = weight;
    //console.log(categoryGrades)
}
if (listHeadings.length >= 3) {
    var weightage = true;
    var numCategories = HowManyCategories()
    specialnumber -= numCategories
    //console.log(numCategories)
    let rows = document.querySelectorAll('.listroweven, .listrowodd');
    let filteredRows = Array.from(rows).slice(0, -2)
    let catArray = Array.from(filteredRows).slice(filteredRows.length - numCategories, filteredRows.length)
    catArray.forEach(row => AssignWeightage(row))
    //console.log(categoryWeightage)

}

function IdentifyGrade(){
    newGrade.textContent = " "
    newGrade.textContent = "|| " + percentage + "% " + percentageToLetterGrade(percentage)
    originalGrade.insertAdjacentElement('afterend', newGrade)
}


function EditableGrade(row){
    let cells = row.querySelectorAll('.cellLeft')
    let cell = cells[1]

    if(weightage){
        var categoryName2 = cells[0].querySelectorAll('div')[2].textContent.trim()
        //console.log(categoryName)
        var cellLeft = cells[0];

        var existingDiv = cellLeft.querySelector('div[style="font-size: 8pt;font-style: italic;"]');

        // Create a select element
        var selectElement = document.createElement('select');

        // Populate the select element with options from the dictionary
        for (var category in categoryWeightage) {
            var optionElement = document.createElement('option');
            optionElement.value = category;
            optionElement.text = category;
            if (category === existingDiv.textContent.trim()) {
                optionElement.selected = true;
            }
            selectElement.appendChild(optionElement);
        }

        // Add an event listener to the select element
        selectElement.addEventListener('change', function() {
            var selectedCategory = selectElement.options[selectElement.selectedIndex].text;
            var selectedValue = categoryWeightage[selectedCategory];

            // You can do something with the selected value if needed

            // Update the content of the element based on the selected category
            cellLeft.querySelector('input[type="hidden"]').value = selectedCategory;


        });

        // Replace the existing div with the select element
        existingDiv.replaceWith(selectElement);
    }

    let childNodes = cell.childNodes;

    var divElements = cell.getElementsByTagName('div');
    var secondToLastDiv = divElements[divElements.length - 2];
    if (secondToLastDiv !== undefined) {
        var spanElement = secondToLastDiv.querySelector('span');
    }
    if (spanElement && (spanElement.textContent.trim() === 'Absent' || spanElement.textContent.trim() === 'Missing')) {
    return;
    }


    let innerGrade = "";
    for (let i = 0; i < childNodes.length; i++) {
        if (childNodes[i].nodeType === Node.TEXT_NODE && childNodes[i].textContent.indexOf('/') !== -1) { //current issue tha
            innerGrade += childNodes[i].textContent;
            childNodes[i].textContent = " ";
            let spanElement = document.createElement('span');
            spanElement.textContent = innerGrade;
            spanElement.setAttribute('contentEditable', true)
            cell.replaceChild(spanElement, childNodes[i])
            break;
        }
    }
    innerGrade = innerGrade.trim().replace(/\s+/g, " ")
    const [num, denom] = innerGrade.split('/').map(num => parseFloat(num.trim()));
    if(!weightage){
        numerator += num;
        denominator += denom;
    } else{
        categoryGrades[categoryName2][0] += num
        categoryGrades[categoryName2][1] += denom
    }
    //console.log(innerGrade, num, denom)
}


function SelectGrade(row){
    let cells = row.querySelectorAll('.cellLeft')
    let cell = cells[1]

    if(weightage){
        //var categoryName2 = cells[0].querySelectorAll('div')[2].textContent.trim()
        var selectElement = row.querySelector('.cellLeft select');
        var categoryName2 = selectElement.value;
        //console.log(categoryName2);
    }

    var divElements = cell.getElementsByTagName('div');
    var secondToLastDiv = divElements[divElements.length - 2];
    if (secondToLastDiv !== undefined) {
        var spanElement = secondToLastDiv.querySelector('span');
    }
    if (spanElement && (spanElement.textContent.trim() === 'Absent' || spanElement.textContent.trim() === 'Missing')) {
    return;
    }
    //let cell = row.querySelectorAll('.cellLeft')[1]
    const spanElements = cell.querySelectorAll('span')
      let innerGrade = cell.querySelectorAll('span')[spanElements.length - 1].textContent.trim().replace(/\s+/g, " ")
    const [num, denom] = innerGrade.split('/').map(num => parseFloat(num.trim()));
    var percen = 0;
    if(denom != 0){
      percen = ((num / denom) * 100).toFixed(2);
    } else{
      percen = "NaN"
    }

    // Select the bottom div element
    const bottomDivElement = cell.querySelector('div[style="font-weight: bold;"]');

    // Set the percentage as its content
    //console.log(percen)
    if(percen != "NaN"){
    bottomDivElement.textContent = percen + '%';
    }
    if(!weightage){
        numerator += num;
        denominator += denom;
    }else{
        categoryGrades[categoryName2][0] += num
        categoryGrades[categoryName2][1] += denom
    }
    //console.log(innerGrade, num, denom)

}

function SelectAssignments(){
    let rows = document.querySelectorAll('.listroweven, .listrowodd')
    let rowArray = Array.from(rows).slice(0, specialnumber)
    //console.log(rowArray)
    rowArray.forEach(row => EditableGrade(row))
}

function Refresh(){
    numerator = 0;
    denominator = 0;
    for (let category in categoryGrades) {
    if (categoryGrades.hasOwnProperty(category)) {
        categoryGrades[category] = categoryGrades[category].map(value => 0); // Set all values to zero
        }
    }
    let rows = document.querySelectorAll('.listroweven, .listrowodd');
    let filteredRows = Array.from(rows).slice(0, -2)
    let catArray = Array.from(filteredRows).slice(filteredRows.length - numCategories, filteredRows.length)


    let rowArray = Array.from(rows).slice(0, specialnumber)
    //console.log(rowArray)
    rowArray.forEach(row => SelectGrade(row))
    let percentage = 0.000
    if(!weightage){
        percentage = ((numerator/denominator) * 100 )
    } else {
        for (const category in categoryGrades) {
        const categoryPercentage = (categoryGrades[category][0] / categoryGrades[category][1]) * 100;
        percentage += categoryPercentage * categoryWeightage[category];
        }
        catArray.forEach(row => changeCategoryPercentage(row))
    }

    percentage = percentage.toFixed(2)
    newGrade.textContent = "|| " + percentage + "% " + percentageToLetterGrade(percentage)
    console.log(categoryGrades)



}

function changeCategoryPercentage(row){
    let categoryName = row.querySelector('td.cellLeft b').textContent;
    let weightString = row.querySelector('td.cellRight:nth-child(3)').textContent;
    let category = row.querySelector('td.cellLeft').textContent
    let categoryPercentage = (categoryGrades[category][0] / categoryGrades[category][1]) * 100;
    row.querySelector('td.cellRight:nth-child(3)').textContent = categoryPercentage.toFixed(1) + " %";
}

function addRow(){ //CHANGE THIS SO IT DOES NOT RELY ON CLONING, SO IT WORKS WITH JUST ONE ROW
    let row = document.querySelectorAll('.listroweven, .listrowodd')
    let rowArray = Array.from(row).slice(0, specialnumber)
    //const numberOfRows = rowArray.length

    let lastRow = rowArray[rowArray.length - 1];
    let secondToLastRow = rowArray[rowArray.length - 2];

    let clonedRow = secondToLastRow.cloneNode(true);
    clonedRow.querySelector('b').textContent = "Genesis What If"
    clonedRow.querySelector('b').style.color = "Green"

    clonedRow.querySelectorAll('div')[5].textContent = 'N/A'
    clonedRow.querySelectorAll('div')[5].setAttribute('contentEditable', 'true')

    lastRow.parentNode.insertBefore(clonedRow, lastRow.nextSibling);
}


function percentageToLetterGrade(numberGrade){
        let letter;
      if (numberGrade >= 96.5) {
        letter = 'A+';
      } else if (numberGrade >= 92.5) {
        letter = 'A';
        return letter;
      } else if (numberGrade >= 89.5) {
        letter = 'A-';
      } else if (numberGrade >= 86.5) {
        letter = 'B+';
      } else if (numberGrade >= 82.5) {
        letter = 'B';
      } else if (numberGrade >= 79.5) {
        letter = 'B-';
      } else if (numberGrade >= 76.5) {
        letter = 'C+';
      } else if (numberGrade >= 72.5) {
        letter = 'C';
      } else if (numberGrade >= 69.5) {
        letter = 'C-';
      } else if (numberGrade >= 66.5) {
        letter = 'D+';
      } else if (numberGrade >= 59.5) {
        letter = 'D-';
      } else {
        letter = 'F';
      }
      return letter;
    };

function AddButtons(){
    const headerT = document.querySelectorAll('.listheading')[0];
    const parentDiv = headerT//.parentNode
    let refreshButton = document.createElement("button")
    refreshButton.id="refreshButton"
    refreshButton.innerHTML = "Refresh"
    refreshButton.onclick = () => Refresh();
    refreshButton.title = "The keyboard shortcut for refreshButton is shift + R";

    let addRowButton = document.createElement("button")
    addRowButton.innerHTML = "Add Row"
    addRowButton.onclick = () => addRow();
    addRowButton.title = "The keyboard shortcut for addRowButton is shift + T";

    parentDiv.insertAdjacentElement('beforebegin', refreshButton)
    parentDiv.insertAdjacentElement('beforebegin', addRowButton)
}



SelectAssignments();

let originalGrade = document.querySelectorAll('b')[0]
    //console.log(originalGrade.textContent.trim().replace(/\s+/g, ' '))
let percentage = 0.000
if(!weightage){
    percentage = ((numerator/denominator) * 100 )
} else {
    for (const category in categoryGrades) {
    const categoryPercentage = (categoryGrades[category][0] / categoryGrades[category][1]) * 100;
    percentage += categoryPercentage * categoryWeightage[category];
    }
}
percentage = percentage.toFixed(2)
let newGrade = document.createElement('b')
IdentifyGrade();
AddButtons();

// console.log(categoryGrades)

    function doc_keyUp(e) {

    // this would test for whichever key is 40 (down arrow) and the ctrl key at the same time
    if (e.shiftKey && e.key === 'R') {
        // call your function to do the thing
        Refresh();
    }
}
    function doc_keyUp2(e) {

    if (e.shiftKey && e.key === 'R') {

        Refresh();
    }

    if (e.shiftKey && e.key === 'T') {

        addRow();
    }
}

// Add event listeners for keyup event
document.addEventListener('keyup', doc_keyUp2, false);

// register the handler
document.addEventListener('keyup', doc_keyUp, false);



})();