您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
See the average grade for each subject.\nSee potential term/annual averages for stipends.\nExclude entry exams.
// ==UserScript== // @name Shkolo++ // @namespace Violentmonkey Scripts // @match https://app.shkolo.bg/diary* // @grant none // @version 1.2.1 // @author Skibidi Rizz // @license Sigma // @description See the average grade for each subject.\nSee potential term/annual averages for stipends.\nExclude entry exams. // ==/UserScript== function calculateGrades() { if(!document.querySelector("#tableGrades")) return false; const localStorageKey = "excludeFirstGradeRows"; function getExcludedRows() { return JSON.parse(localStorage.getItem(localStorageKey)) || []; } function setExcludedRows(rows) { localStorage.setItem(localStorageKey, JSON.stringify(rows)); } function toggleRowExclusion(rowNumber, exclude) { const excludedRows = getExcludedRows(); if (exclude) { if (!excludedRows.includes(rowNumber)) excludedRows.push(rowNumber); } else { const index = excludedRows.indexOf(rowNumber); if (index > -1) excludedRows.splice(index, 1); } setExcludedRows(excludedRows); } function addCheckboxes() { const rows = document.querySelectorAll("#tableGrades > tbody > tr"); const excludedRows = getExcludedRows(); rows.forEach((row, index) => { const rowNumber = index + 1; const cell = row.querySelector("td:nth-child(2)"); if (!cell || cell.querySelector('input[type="checkbox"]')) return; const checkbox = document.createElement("input"); checkbox.type = "checkbox"; checkbox.title = "Exclude first grade of term 1"; checkbox.checked = excludedRows.includes(rowNumber); checkbox.style.marginRight = "8px"; checkbox.style.transform = "scale(1.2)"; checkbox.style.cursor = "pointer"; checkbox.addEventListener("change", (e) => { toggleRowExclusion(rowNumber, e.target.checked); calculateGrades(); }); const label = document.createElement("label"); label.style.marginLeft = "5px"; label.appendChild(checkbox); cell.prepend(label); }); } function calculateTermGrades(term, footerIndex) { const termCells = document.querySelectorAll(`#tableGrades > tbody > tr > td.${term}.solid-left-border`); const grades = []; const excludedRows = getExcludedRows(); let calculated = 0; termCells.forEach((cell, index) => { const rowNumber = index + 1; const gradeCell = document.querySelector(`#tableGrades > tbody > tr:nth-child(${rowNumber}) > td.numVal.${term}`); const existingGrade = gradeCell?.children.length ? parseFloat(gradeCell.innerText) : null; if (existingGrade === null && cell.children.length) { const buttons = Array.from(cell.children); const gradeValues = buttons .map((button, i) => (excludedRows.includes(rowNumber) && i === 0 ? null : parseFloat(button.innerText))) .filter((v) => v !== null); const avg = gradeValues.reduce((a, b) => a + b, 0) / gradeValues.length; if (gradeCell) gradeCell.innerText = avg.toFixed(2); grades.push(avg); calculated++; } else if (existingGrade !== null) { grades.push(existingGrade); } }); if (grades.length) { const avg = grades.reduce((a, b) => a + b, 0) / grades.length; const avgFloor = grades.reduce((a, b) => a + Math.floor(b), 0) / grades.length; const avgRound = grades.reduce((a, b) => a + Math.round(b), 0) / grades.length; const footerCell = document.querySelector(`#tableGrades > tfoot > tr > td:nth-child(${footerIndex})`); footerCell.innerHTML = ` <a class="grade huge bold" title="Average of rounded down grades">${avgFloor.toFixed(2)}</a><br> <a class="grade huge bold" title="Average of grades as they are">${avg.toFixed(2)}</a><br> <a class="grade huge bold" title="Average of rounded grades">${avgRound.toFixed(2)}</a> `; } } function calculateAnnualGrades() { const term1Cells = document.querySelectorAll("#tableGrades > tbody > tr > td.term1.solid-left-border"); const term2Cells = document.querySelectorAll("#tableGrades > tbody > tr > td.term2.solid-left-border"); const grades = []; const excludedRows = getExcludedRows(); let calculated = 0; term1Cells.forEach((cell, index) => { const rowNumber = index + 1; const term1Grade = cell.children.length ? parseFloat(document.querySelector(`#tableGrades > tbody > tr:nth-child(${rowNumber}) > td.numVal.term1`)?.innerText) : null; const term2Grade = term2Cells[index]?.children.length ? parseFloat(document.querySelector(`#tableGrades > tbody > tr:nth-child(${rowNumber}) > td.numVal.term2`)?.innerText) : null; if (term1Grade !== null || term2Grade !== null) { const avg = (term1Grade || 0) + (term2Grade || 0); const count = (term1Grade !== null) + (term2Grade !== null); const finalAvg = avg / count; const gradeCell = document.querySelector(`#tableGrades > tbody > tr:nth-child(${rowNumber}) > td.emptyAnnual.annualAssessment.solid-left-border`); if (gradeCell?.innerText === "") { gradeCell.innerText = finalAvg.toFixed(2); calculated++; } grades.push(finalAvg); } }); if (grades.length) { const avg = grades.reduce((a, b) => a + b, 0) / grades.length; const avgFloor = grades.reduce((a, b) => a + Math.floor(b), 0) / grades.length; const avgRound = grades.reduce((a, b) => a + Math.round(b), 0) / grades.length; const footerCell = document.querySelector(`#tableGrades > tfoot > tr > td:nth-child(8)`); footerCell.innerHTML = ` <a class="grade huge bold" title="Annual average of rounded down grades">${avgFloor.toFixed(2)}</a><br> <a class="grade huge bold" title="Annual average of grades as they are">${avg.toFixed(2)}</a><br> <a class="grade huge bold" title="Annual average of rounded grades">${avgRound.toFixed(2)}</a> `; } } addCheckboxes(); calculateTermGrades("term1", 4); calculateTermGrades("term2", 7); calculateAnnualGrades(); return true; } let attempts = 0; const interval = setInterval(() => { if (calculateGrades() || attempts > 10) { clearInterval(interval); } attempts++; }, 1000);