mirror of
https://github.com/QwIT-Development/firka-extension.git
synced 2026-06-12 03:41:39 +02:00
806 lines
27 KiB
JavaScript
806 lines
27 KiB
JavaScript
(() => {
|
|
let gradesSettings = {
|
|
hideChart: false,
|
|
hideClassAverage: false
|
|
};
|
|
|
|
async function loadGradesSettings() {
|
|
try {
|
|
const settings = await storageManager.get("pageSettings_grades", {});
|
|
gradesSettings = {
|
|
hideChart: settings.hideChart || false,
|
|
hideClassAverage: settings.hideClassAverage || false
|
|
};
|
|
} catch (error) {
|
|
console.error("Error loading grades settings:", error);
|
|
}
|
|
}
|
|
|
|
async function transformGradesPage() {
|
|
try {
|
|
await loadGradesSettings();
|
|
|
|
const tanuloIdElement = document.querySelector("#TanuloId");
|
|
const tanuloId = tanuloIdElement ? tanuloIdElement.value : "772481";
|
|
|
|
const gradesData = await fetchGradesFromAPI(tanuloId);
|
|
const studentAverage = calculateOverallAverage(gradesData.subjects);
|
|
const classAverage = calculateOverallClassAverage(gradesData.subjects);
|
|
|
|
window.currentGradesData = gradesData;
|
|
|
|
const htmlString = await generatePageHTML(
|
|
gradesData,
|
|
studentAverage,
|
|
classAverage,
|
|
);
|
|
|
|
const template = document.createElement('template');
|
|
template.innerHTML = htmlString;
|
|
|
|
helper.clearElement(document.body);
|
|
document.body.appendChild(template.content);
|
|
|
|
|
|
setupUserDropdown();
|
|
|
|
if (!gradesSettings.hideChart) {
|
|
const script = document.createElement("script");
|
|
script.src = chrome.runtime.getURL("grades/chart.js");
|
|
document.head.appendChild(script);
|
|
|
|
script.onload = () => {
|
|
setupGradesChart(gradesData.subjects);
|
|
};
|
|
}
|
|
|
|
setupEventListeners();
|
|
setupGradesListScrolling();
|
|
loadingScreen.hide();
|
|
} catch (error) {
|
|
console.error("Error loading grades:", error);
|
|
loadingScreen.hide();
|
|
}
|
|
}
|
|
|
|
async function fetchGradesFromAPI(tanuloId) {
|
|
try {
|
|
const currentDomain = window.location.origin;
|
|
let apiUrl = `${currentDomain}/api/TanuloErtekelesByTanuloApi/GetTanuloErtekelesByTanuloGridTanuloView?sort=&group=&filter=&data=%7B%22tanuloId%22%3A%22${tanuloId}%22%2C%22oktatasiNevelesiFeladatId%22%3A%227895%22%2C%22isOsztalyAtlagMegjelenik%22%3A%22True%22%7D&_=${Date.now()}`;
|
|
|
|
let response = await fetch(apiUrl, {
|
|
method: "GET",
|
|
credentials: "include",
|
|
headers: {
|
|
Accept: "application/json, text/javascript, */*; q=0.01",
|
|
"X-Requested-With": "XMLHttpRequest",
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
let data = await response.json();
|
|
|
|
if (data.Data && Array.isArray(data.Data) && data.Data.length === 1 && data.Data[0].ID === 0) {
|
|
console.log("Received only ID: 0, retrying with alternative endpoint...");
|
|
apiUrl = `${currentDomain}/api/TanuloErtekelesByTanuloApi/GetTanuloErtekelesByTanuloGridTanuloView?sort=&group=&filter=&data=%7B%22tanuloId%22%3A%22${tanuloId}%22%2C%22oktatasiNevelesiFeladatId%22%3A%221160%22%2C%22isOsztalyAtlagMegjelenik%22%3A%22True%22%7D&_=${Date.now()}`;
|
|
|
|
response = await fetch(apiUrl, {
|
|
method: "GET",
|
|
credentials: "include",
|
|
headers: {
|
|
Accept: "application/json, text/javascript, */*; q=0.01",
|
|
"X-Requested-With": "XMLHttpRequest",
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error on retry! status: ${response.status}`);
|
|
}
|
|
|
|
data = await response.json();
|
|
}
|
|
|
|
return await processAPIGradesData(data);
|
|
} catch (error) {
|
|
console.error("Error fetching grades from API:", error);
|
|
return await extractGradesDataFromDOM();
|
|
}
|
|
}
|
|
|
|
async function processAPIGradesData(apiData) {
|
|
const subjects = [];
|
|
|
|
if (!apiData.Data || !Array.isArray(apiData.Data)) {
|
|
return {
|
|
schoolInfo: {
|
|
id: await storageManager.get("schoolCode", ""),
|
|
name: await storageManager.get("schoolName", "OM azonosító - Iskola neve"),
|
|
},
|
|
userData: {
|
|
name: await storageManager.get("userName", "Felhasználónév"),
|
|
time:
|
|
document.querySelector(".usermenu_timer")?.textContent?.trim() ||
|
|
"45:00",
|
|
},
|
|
subjects: [],
|
|
};
|
|
}
|
|
|
|
apiData.Data.forEach((subject) => {
|
|
if (
|
|
subject.TantargyNev &&
|
|
subject.TantargyNev !== "Magatartás/Szorgalom"
|
|
) {
|
|
const grades = [];
|
|
const monthFields = [
|
|
"Szeptember",
|
|
"Oktober",
|
|
"November",
|
|
"December",
|
|
"JanuarI",
|
|
"I",
|
|
"JanuarII",
|
|
"Februar",
|
|
"Marcius",
|
|
"Aprilis",
|
|
"Majus",
|
|
"Junius",
|
|
"Julius",
|
|
"Augusztus",
|
|
"II",
|
|
];
|
|
|
|
monthFields.forEach((month) => {
|
|
const monthData = subject[month];
|
|
if (monthData && monthData.trim() !== "") {
|
|
const gradeMatches = monthData.match(
|
|
/<span[^>]*data-tanuloertekelesid[^>]*>([^<]+)<\/span>/g,
|
|
);
|
|
if (gradeMatches) {
|
|
gradeMatches.forEach((gradeHtml) => {
|
|
const gradeValue = gradeHtml
|
|
.match(/>([^<]+)<\/span>/)?.[1]
|
|
?.trim();
|
|
if (
|
|
gradeValue &&
|
|
gradeValue !== "-" &&
|
|
!gradeValue.includes("%")
|
|
) {
|
|
const dateMatch = gradeHtml.match(/data-datum='([^']*)'/);
|
|
const typeMatch = gradeHtml.match(/data-tipusmod='([^']*)'/);
|
|
const themeMatch = gradeHtml.match(
|
|
/data-ertekelestema='([^']*)'/,
|
|
);
|
|
const weightMatch = gradeHtml.match(/data-suly='([^']*)'/);
|
|
const teacherMatch = gradeHtml.match(
|
|
/data-ertekelonyomtatasinev='([^']*)'/,
|
|
);
|
|
|
|
const theme = themeMatch
|
|
? themeMatch[1]
|
|
.replace("Téma: ", "")
|
|
.replace(/&#\d+;/g, (match) => {
|
|
const code = match.match(/\d+/)[0];
|
|
return String.fromCharCode(code);
|
|
})
|
|
: "";
|
|
|
|
const teacher = teacherMatch
|
|
? teacherMatch[1].replace(/&#\d+;/g, (match) => {
|
|
const code = match.match(/\d+/)[0];
|
|
return String.fromCharCode(code);
|
|
})
|
|
: "";
|
|
|
|
const type = typeMatch
|
|
? typeMatch[1].replace(/&#\d+;/g, (match) => {
|
|
const code = match.match(/\d+/)[0];
|
|
return String.fromCharCode(code);
|
|
})
|
|
: "";
|
|
|
|
grades.push({
|
|
value: gradeValue,
|
|
date: dateMatch ? dateMatch[1] : "",
|
|
type: type,
|
|
theme: theme,
|
|
weight: weightMatch ? weightMatch[1] : "",
|
|
teacher: teacher,
|
|
isSemesterGrade:
|
|
type.toLowerCase().includes("félévi") ||
|
|
theme.toLowerCase().includes("félévi"),
|
|
isYearEndGrade:
|
|
type.toLowerCase().includes("évvégi") ||
|
|
theme.toLowerCase().includes("évvégi") ||
|
|
type.toLowerCase().includes("év végi") ||
|
|
theme.toLowerCase().includes("év végi"),
|
|
});
|
|
}
|
|
});
|
|
}
|
|
}
|
|
});
|
|
|
|
if (grades.length > 0) {
|
|
subjects.push({
|
|
name: subject.TantargyNev,
|
|
grades: grades,
|
|
average: subject.Atlag || 0,
|
|
classAverage: subject.OsztalyAtlag || 0,
|
|
});
|
|
}
|
|
}
|
|
});
|
|
|
|
return {
|
|
schoolInfo: {
|
|
id: await storageManager.get("schoolCode", ""),
|
|
name: await storageManager.get("schoolName", "Iskola"),
|
|
},
|
|
userData: {
|
|
name: await storageManager.get("userName", "Felhasználó"),
|
|
time:
|
|
document.querySelector(".usermenu_timer")?.textContent?.trim() ||
|
|
"45:00",
|
|
},
|
|
subjects: subjects,
|
|
};
|
|
}
|
|
|
|
async function extractGradesDataFromDOM() {
|
|
const subjects = [];
|
|
const rows = document.querySelectorAll(
|
|
"#Osztalyzatok_7895TanuloErtekelesByTanuloGrid tbody tr",
|
|
);
|
|
|
|
rows.forEach((row) => {
|
|
const cells = row.querySelectorAll("td");
|
|
if (cells.length >= 17) {
|
|
const subjectName = cells[2].textContent.trim();
|
|
if (subjectName && subjectName !== "Magatartás/Szorgalom") {
|
|
const grades = [];
|
|
const months = [
|
|
LanguageManager.t("grades.september"),
|
|
LanguageManager.t("grades.october"),
|
|
LanguageManager.t("grades.november"),
|
|
LanguageManager.t("grades.december"),
|
|
LanguageManager.t("grades.january_1"),
|
|
LanguageManager.t("grades.january_2"),
|
|
LanguageManager.t("grades.february"),
|
|
LanguageManager.t("grades.march"),
|
|
LanguageManager.t("grades.april"),
|
|
LanguageManager.t("grades.may"),
|
|
LanguageManager.t("grades.june_1"),
|
|
LanguageManager.t("grades.june_2"),
|
|
];
|
|
|
|
months.forEach((month, index) => {
|
|
const gradeElements = cells[index + 3].querySelectorAll(
|
|
"span[data-tanuloertekelesid]",
|
|
);
|
|
gradeElements.forEach((element) => {
|
|
const gradeText = element.textContent.trim();
|
|
if (gradeText && gradeText !== "-" && !gradeText.includes("%")) {
|
|
const type = element.getAttribute("data-tipusmod") || "";
|
|
const theme = element.getAttribute("data-ertekelestema") || "";
|
|
const dataType = element.getAttribute("data-tipus") || "";
|
|
|
|
grades.push({
|
|
value: gradeText,
|
|
date: element.getAttribute("data-datum"),
|
|
type: type,
|
|
theme: theme.replace("Téma: ", ""),
|
|
weight: element.getAttribute("data-suly"),
|
|
teacher: element.getAttribute("data-ertekelonyomtatasinev"),
|
|
isSemesterGrade:
|
|
type.toLowerCase().includes("félévi") ||
|
|
theme.toLowerCase().includes("félévi") ||
|
|
dataType.toLowerCase().includes("félévi"),
|
|
isYearEndGrade:
|
|
type.toLowerCase().includes("évvégi") ||
|
|
theme.toLowerCase().includes("évvégi") ||
|
|
type.toLowerCase().includes("év végi") ||
|
|
theme.toLowerCase().includes("év végi") ||
|
|
dataType.toLowerCase().includes("évvégi") ||
|
|
dataType.toLowerCase().includes("év végi"),
|
|
});
|
|
}
|
|
});
|
|
});
|
|
|
|
const avgText = cells[16].textContent.trim();
|
|
const classAvgText = cells[17].textContent.trim();
|
|
|
|
const average =
|
|
avgText !== "-" ? parseFloat(avgText.replace(",", ".")) : 0;
|
|
const classAvg =
|
|
classAvgText !== "-"
|
|
? parseFloat(classAvgText.replace(",", "."))
|
|
: 0;
|
|
|
|
if (grades.length > 0) {
|
|
subjects.push({
|
|
name: subjectName,
|
|
grades: grades,
|
|
average: average || 0,
|
|
classAverage: classAvg || 0,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
return {
|
|
schoolInfo: {
|
|
id: await storageManager.get("schoolCode", ""),
|
|
name: await storageManager.get("schoolName", "Iskola"),
|
|
},
|
|
userData: {
|
|
name: await storageManager.get("userName", "Felhasználó"),
|
|
time:
|
|
document.querySelector(".usermenu_timer")?.textContent?.trim() ||
|
|
"45:00",
|
|
},
|
|
subjects: subjects,
|
|
};
|
|
}
|
|
|
|
function calculateOverallAverage(subjects) {
|
|
const validSubjects = subjects.filter((s) => s.average > 0);
|
|
if (validSubjects.length === 0) return 0;
|
|
|
|
return (
|
|
validSubjects.reduce((sum, s) => sum + s.average, 0) /
|
|
validSubjects.length
|
|
);
|
|
}
|
|
|
|
function calculateOverallClassAverage(subjects) {
|
|
const validSubjects = subjects.filter((s) => s.classAverage > 0);
|
|
if (validSubjects.length === 0) return 0;
|
|
return (
|
|
validSubjects.reduce((sum, s) => sum + s.classAverage, 0) /
|
|
validSubjects.length
|
|
);
|
|
}
|
|
|
|
function shortenEvaluationName(name, maxLength = 30) {
|
|
if (!name) return "";
|
|
if (name.length <= maxLength) return name;
|
|
return name.substring(0, maxLength - 3) + "...";
|
|
}
|
|
|
|
function generateGradeItem(grade) {
|
|
const semesterClass = grade.isSemesterGrade ? "semester-grade" : "";
|
|
const yearEndClass = grade.isYearEndGrade ? "year-end-grade" : "";
|
|
const dateObj = new Date(grade.date);
|
|
const monthNames = [
|
|
LanguageManager.t("months.january"),
|
|
LanguageManager.t("months.february"),
|
|
LanguageManager.t("months.march"),
|
|
LanguageManager.t("months.april"),
|
|
LanguageManager.t("months.may"),
|
|
LanguageManager.t("months.june"),
|
|
LanguageManager.t("months.july"),
|
|
LanguageManager.t("months.august"),
|
|
LanguageManager.t("months.september"),
|
|
LanguageManager.t("months.october"),
|
|
LanguageManager.t("months.november"),
|
|
LanguageManager.t("months.december"),
|
|
];
|
|
const formattedDate = `${monthNames[dateObj.getMonth()]} ${dateObj.getDate()}`;
|
|
const shortenedTheme = shortenEvaluationName(grade.theme);
|
|
return `
|
|
<div class="grade-item grade-${grade.value} ${semesterClass} ${yearEndClass}">
|
|
<div class="grade-value">${grade.value}</div>
|
|
<div class="grade-details">
|
|
<div class="grade-theme" title="${grade.theme}">${shortenedTheme}</div>
|
|
<div class="grade-meta">${grade.type}</div>
|
|
</div>
|
|
<div class="grade-date">${formattedDate}</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
function calculateGradeDistribution(subjects) {
|
|
const distribution = { 1: 0, 2: 0, 3: 0, 4: 0, 5: 0 };
|
|
subjects.forEach((subject) => {
|
|
subject.grades.forEach((grade) => {
|
|
const value = parseInt(grade.value);
|
|
if (value >= 1 && value <= 5 && !grade.value.includes("%")) {
|
|
distribution[value]++;
|
|
}
|
|
});
|
|
});
|
|
return distribution;
|
|
}
|
|
|
|
async function generatePageHTML(data, studentAverage, classAverage) {
|
|
const totalGrades = data.subjects.reduce(
|
|
(sum, subject) => sum + subject.grades.length,
|
|
0,
|
|
);
|
|
const gradeDistribution = calculateGradeDistribution(data.subjects);
|
|
const semesterGrades = extractSemesterGrades(data.subjects);
|
|
const yearEndGrades = extractYearEndGrades(data.subjects);
|
|
|
|
const studentGradeLevel = Math.floor(studentAverage) || 0;
|
|
const classGradeLevel = Math.floor(classAverage) || 0;
|
|
|
|
schoolNameFull = `${data.schoolInfo.id} - ${data.schoolInfo.name}`;
|
|
shortenedSchoolName = helper.shortenSchoolName(schoolNameFull);
|
|
|
|
const showClassAverage = !gradesSettings.hideClassAverage && classAverage > 0;
|
|
const showChart = !gradesSettings.hideChart;
|
|
|
|
return `
|
|
<div class="kreta-container">
|
|
${await createTemplate.header()}
|
|
|
|
<main class="kreta-main">
|
|
<div class="grades-overview">
|
|
${showChart ? `
|
|
<div class="overall-averages card">
|
|
<div class="chart-header">
|
|
<div class="chart-title">${LanguageManager.t("grades.chart_title")} (${totalGrades}db)</div>
|
|
<div class="chart-averages">
|
|
<div class="average-circle my-average" data-grade="${studentGradeLevel}">
|
|
<span class="average-value ${studentAverage < 2 && studentAverage > 0 ? "warning" : ""}">${studentAverage > 0 ? studentAverage.toFixed(2) : "-"}</span>
|
|
</div>
|
|
${
|
|
showClassAverage
|
|
? `
|
|
<div class="average-circle class-average" data-grade="${classGradeLevel}">
|
|
<span class="average-value">${classAverage.toFixed(2)}</span>
|
|
</div>
|
|
`
|
|
: ""
|
|
}
|
|
</div>
|
|
</div>
|
|
<div class="grades-chart">
|
|
<canvas id="gradesChart"></canvas>
|
|
</div>
|
|
<div class="grade-distribution">
|
|
${Object.entries(gradeDistribution)
|
|
.map(
|
|
([grade, count]) => `
|
|
<div class="grade-count grade-${grade}">
|
|
<span class="grade-value">${grade}</span>
|
|
<span class="grade-amount">${count}</span>
|
|
</div>
|
|
`,
|
|
)
|
|
.join("")}
|
|
</div>
|
|
</div>
|
|
` : `
|
|
<div class="overall-averages card">
|
|
<div class="chart-header">
|
|
<div class="chart-title">${LanguageManager.t("grades.chart_title")} (${totalGrades}db)</div>
|
|
<div class="chart-averages">
|
|
<div class="average-circle my-average" data-grade="${studentGradeLevel}">
|
|
<span class="average-value ${studentAverage < 2 && studentAverage > 0 ? "warning" : ""}">${studentAverage > 0 ? studentAverage.toFixed(2) : "-"}</span>
|
|
</div>
|
|
${
|
|
showClassAverage
|
|
? `
|
|
<div class="average-circle class-average" data-grade="${classGradeLevel}">
|
|
<span class="average-value">${classAverage.toFixed(2)}</span>
|
|
</div>
|
|
`
|
|
: ""
|
|
}
|
|
</div>
|
|
</div>
|
|
<div class="grade-distribution centered">
|
|
${Object.entries(gradeDistribution)
|
|
.map(
|
|
([grade, count]) => `
|
|
<div class="grade-count grade-${grade}">
|
|
<span class="grade-value">${grade}</span>
|
|
<span class="grade-amount">${count}</span>
|
|
</div>
|
|
`,
|
|
)
|
|
.join("")}
|
|
</div>
|
|
</div>
|
|
`}
|
|
${
|
|
yearEndGrades.length > 0
|
|
? `
|
|
<div class="year-end-grades card">
|
|
<div class="grades-summary-header">
|
|
<h3>${LanguageManager.t("grades.year_end_evaluations")}</h3>
|
|
</div>
|
|
<div class="year-end-grades-list">
|
|
${yearEndGrades
|
|
.map(
|
|
(grade) => `
|
|
<div class="year-end-grade-item grade-${grade.value}">
|
|
<div class="year-end-grade-value">${grade.value}</div>
|
|
<div class="year-end-grade-subject">${grade.subject}</div>
|
|
</div>
|
|
`,
|
|
)
|
|
.join("")}
|
|
</div>
|
|
</div>
|
|
`
|
|
: ""
|
|
}
|
|
</div>
|
|
<div class="grades-grid">
|
|
${generateSubjectCards(data.subjects)}
|
|
</div>
|
|
</main>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
function extractSemesterGrades(subjects) {
|
|
const semesterGrades = [];
|
|
subjects.forEach((subject) => {
|
|
const semesterGrade = subject.grades.find(
|
|
(grade) => grade.isSemesterGrade,
|
|
);
|
|
if (semesterGrade) {
|
|
semesterGrades.push({
|
|
subject: subject.name,
|
|
value: semesterGrade.value,
|
|
date: semesterGrade.date,
|
|
});
|
|
}
|
|
});
|
|
return semesterGrades;
|
|
}
|
|
|
|
function extractYearEndGrades(subjects) {
|
|
const yearEndGrades = [];
|
|
subjects.forEach((subject) => {
|
|
const yearEndGrade = subject.grades.find((grade) => grade.isYearEndGrade);
|
|
if (yearEndGrade) {
|
|
yearEndGrades.push({
|
|
subject: subject.name,
|
|
value: yearEndGrade.value,
|
|
date: yearEndGrade.date,
|
|
});
|
|
}
|
|
});
|
|
return yearEndGrades;
|
|
}
|
|
|
|
function calculateGradePoints(subjects) {
|
|
const allGrades = [];
|
|
|
|
subjects.forEach((subject) => {
|
|
subject.grades.forEach((grade) => {
|
|
const date = new Date(grade.date);
|
|
const value = parseInt(grade.value);
|
|
const weight = parseInt(grade.weight?.match(/\d+/)?.[0] || "100") / 100;
|
|
if (date && value && weight && !grade.value.includes("%")) {
|
|
allGrades.push({
|
|
date,
|
|
value,
|
|
weight,
|
|
});
|
|
}
|
|
});
|
|
});
|
|
|
|
allGrades.sort((a, b) => a.date - b.date);
|
|
|
|
let totalWeight = 0;
|
|
let weightedSum = 0;
|
|
return allGrades.map((grade) => {
|
|
totalWeight += grade.weight;
|
|
weightedSum += grade.value * grade.weight;
|
|
return {
|
|
date: grade.date.toISOString(),
|
|
grade: grade.value,
|
|
average: weightedSum / totalWeight,
|
|
};
|
|
});
|
|
}
|
|
|
|
function setupGradesChart(subjects) {
|
|
const ctx = document.getElementById("gradesChart");
|
|
if (!ctx) return;
|
|
|
|
const gradePoints = calculateGradePoints(subjects);
|
|
const accentColor = getComputedStyle(document.documentElement)
|
|
.getPropertyValue("--accent-accent")
|
|
.trim();
|
|
|
|
new Chart(ctx, {
|
|
type: "line",
|
|
data: {
|
|
labels: gradePoints.map((_, index) => ""),
|
|
datasets: [
|
|
{
|
|
label: "Átlag",
|
|
data: gradePoints.map((p) => p.average),
|
|
borderWidth: 5,
|
|
borderColor: accentColor,
|
|
tension: 0.5,
|
|
fill: true,
|
|
backgroundColor: function (context) {
|
|
const chart = context.chart;
|
|
const { ctx, chartArea } = chart;
|
|
if (!chartArea) return null;
|
|
|
|
const gradientBg = ctx.createLinearGradient(
|
|
0,
|
|
chartArea.bottom,
|
|
0,
|
|
chartArea.top,
|
|
);
|
|
|
|
gradientBg.addColorStop(0, accentColor + "30");
|
|
gradientBg.addColorStop(1, accentColor + "10");
|
|
|
|
return gradientBg;
|
|
},
|
|
pointBackgroundColor: accentColor,
|
|
pointRadius: 0,
|
|
pointHoverRadius: 0,
|
|
},
|
|
],
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
scales: {
|
|
y: {
|
|
min: 1,
|
|
max: 5,
|
|
ticks: {
|
|
stepSize: 1,
|
|
color: accentColor,
|
|
},
|
|
grid: {
|
|
color: accentColor + "20",
|
|
lineWidth: 1,
|
|
borderDash: [5, 5],
|
|
},
|
|
},
|
|
x: {
|
|
display: false,
|
|
},
|
|
},
|
|
plugins: {
|
|
legend: {
|
|
display: false,
|
|
},
|
|
tooltip: {
|
|
backgroundColor: getComputedStyle(
|
|
document.documentElement,
|
|
).getPropertyValue("--card-card"),
|
|
titleColor: getComputedStyle(
|
|
document.documentElement,
|
|
).getPropertyValue("--text-primary"),
|
|
bodyColor: getComputedStyle(
|
|
document.documentElement,
|
|
).getPropertyValue("--text-primary"),
|
|
borderColor:
|
|
getComputedStyle(document.documentElement).getPropertyValue(
|
|
"--text-teritary",
|
|
) + "20",
|
|
borderWidth: 1,
|
|
padding: 12,
|
|
displayColors: false,
|
|
callbacks: {
|
|
title: () => "",
|
|
label: (context) => `Átlag: ${context.raw.toFixed(2)}`,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
});
|
|
}
|
|
|
|
function generateSubjectCards(subjects) {
|
|
const sortedSubjects = [...subjects].sort(
|
|
(a, b) => a.grades.length - b.grades.length,
|
|
);
|
|
|
|
return sortedSubjects
|
|
.map((subject) => {
|
|
const regularGrades = subject.grades
|
|
.filter((grade) => !grade.isSemesterGrade)
|
|
.reverse();
|
|
const myGrade = Math.floor(subject.average) || 0;
|
|
const classGrade = Math.floor(subject.classAverage) || 0;
|
|
const showClassAvg = !gradesSettings.hideClassAverage && subject.classAverage > 0;
|
|
|
|
return `
|
|
<div class="subject-card card">
|
|
<div class="subject-header">
|
|
<div class="subject-title">
|
|
<h3>${subject.name}</h3>
|
|
</div>
|
|
<div class="subject-averages">
|
|
<div class="average-circle my-average ${subject.average < 2 && subject.average > 0 ? "warning" : ""}" data-grade="${myGrade}">
|
|
<span class="average-value">${subject.average > 0 ? subject.average.toFixed(2) : "-"}</span>
|
|
</div>
|
|
${
|
|
showClassAvg
|
|
? `
|
|
<div class="average-circle class-average" data-grade="${classGrade}">
|
|
<span class="average-value">${subject.classAverage.toFixed(2)}</span>
|
|
</div>
|
|
`
|
|
: ""
|
|
}
|
|
</div>
|
|
</div>
|
|
<div class="grades-list">
|
|
${regularGrades.map(generateGradeItem).join("")}
|
|
</div>
|
|
</div>
|
|
`;
|
|
})
|
|
.join("");
|
|
}
|
|
|
|
function setupEventListeners() {
|
|
const timerEl = document.getElementById("logoutTimer");
|
|
if (timerEl) {
|
|
const startTime = parseInt(
|
|
timerEl.textContent?.match(/\d+/)?.[0] || "45",
|
|
);
|
|
let timeLeft = startTime * 60;
|
|
|
|
const updateTimer = () => {
|
|
const minutes = Math.floor(timeLeft / 60);
|
|
const seconds = timeLeft % 60;
|
|
timerEl.textContent = `${minutes}:${seconds.toString().padStart(2, "0")}`;
|
|
timeLeft--;
|
|
|
|
if (timeLeft < 0) {
|
|
window.location.href = chrome.runtime.getURL("logout/logout.html");
|
|
}
|
|
};
|
|
|
|
setInterval(updateTimer, 1000);
|
|
}
|
|
}
|
|
|
|
function setupGradesListScrolling() {
|
|
const gradesLists = document.querySelectorAll(".grades-list");
|
|
|
|
gradesLists.forEach((list) => {
|
|
const checkScrollable = () => {
|
|
if (list.scrollHeight > list.clientHeight) {
|
|
list.classList.add("scrollable", "has-more");
|
|
|
|
const handleScroll = () => {
|
|
const isAtBottom =
|
|
list.scrollTop + list.clientHeight >= list.scrollHeight - 5;
|
|
if (isAtBottom) {
|
|
list.classList.remove("has-more");
|
|
} else {
|
|
list.classList.add("has-more");
|
|
}
|
|
};
|
|
|
|
list.addEventListener("scroll", handleScroll);
|
|
handleScroll();
|
|
} else {
|
|
list.classList.remove("scrollable", "has-more");
|
|
}
|
|
};
|
|
|
|
checkScrollable();
|
|
});
|
|
}
|
|
|
|
if (window.location.href.includes("/TanuloErtekeles/Osztalyzatok")) {
|
|
transformGradesPage();
|
|
}
|
|
})();
|