10 Commits

Author SHA1 Message Date
Zan
86cab01fba Lang fixes 2025-09-15 22:47:04 +02:00
Zan
eb3924f60f Fixes for custom things and mark as done 2025-09-15 22:44:53 +02:00
Zan
8c57152fe4 Use localstorage rather than cookies 2025-09-15 22:17:50 +02:00
Zan
9d877a1d68 Fixed maintenance 2025-09-14 18:17:45 +02:00
Zan
1ca8e24805 Added manual adding for homework 2025-09-14 18:17:17 +02:00
Zan
8a8d81b67f version update 2025-09-10 15:27:49 +02:00
Zan
245142c833 Fix loading remove 2025-09-10 15:27:43 +02:00
Zan
7e1d4cd9a7 Mobile UI fix 2025-09-10 15:27:18 +02:00
Zan
f29f7a2366 Mobile UI fix 2025-09-10 15:27:01 +02:00
Zan
6e0d3b6b7f Link underline remove 2025-09-10 15:26:52 +02:00
30 changed files with 1953 additions and 230 deletions

View File

@@ -139,6 +139,7 @@ body {
}
.dropdown-item:hover {
background:var(--button-secondaryFill);
text-decoration:none;
}
.kreta-main {
flex:1;

View File

@@ -1,11 +1,11 @@
async function collectAbsencesData() {
const basicData = {
schoolInfo: {
name: cookieManager.get("schoolName") || "Iskola",
id: cookieManager.get("schoolCode") || "",
name: await storageManager.get("schoolName", "OM azonosító - Iskola neve"),
id: await storageManager.get("schoolCode", ""),
},
userData: {
name: cookieManager.get("userName") || "Felhasználó",
name: await storageManager.get("userName", "Felhasználónév"),
time:
document.querySelector(".usermenu_timer")?.textContent?.trim() ||
"45:00",
@@ -281,7 +281,7 @@ async function transformAbsencesPage() {
container.className = 'kreta-container';
const headerDiv = document.createElement('div');
const parser = new DOMParser();
const doc = parser.parseFromString(createTemplate.header(), 'text/html');
const doc = parser.parseFromString(await createTemplate.header(), 'text/html');
const tempDiv = doc.body;
while (tempDiv.firstChild) {
headerDiv.appendChild(tempDiv.firstChild);

View File

@@ -219,6 +219,51 @@ h2 {
word-wrap: break-word;
overflow-wrap: break-word;
hyphens: auto;
max-width: 200px;
}
/* Mobile view: author below content */
@media (max-width: 768px) {
.news-item .widget-row {
flex-direction: column;
align-items: stretch;
}
.news-item .widget-meta {
order: 2;
display: flex;
flex-direction: column;
align-items: center;
margin-top: 8px;
}
.news-item .widget-details {
order: 1;
}
.news-author {
align-items: center;
text-align: center;
max-width: 100%;
margin-top: 4px;
}
.widget-date {
order: 1;
}
.news-author {
order: 2;
}
}
/* Desktop view: limit author width and wrap text */
@media (min-width: 769px) {
.news-author {
max-width: 180px;
white-space: normal;
line-height: 1.3;
}
}
.widget-empty {
@@ -346,6 +391,7 @@ h2 {
.dropdown-item:hover {
background-color: var(--accent-15);
text-decoration: none;
}
.dropdown-item svg {

View File

@@ -292,18 +292,22 @@ class DashboardDataManager {
class DashboardRenderer {
constructor(data) {
this.baseData = data;
}
async init() {
this.data = {
...data,
...this.baseData,
schoolInfo: {
name:
cookieManager.get(COOKIE_KEYS.SCHOOL_NAME) || DEFAULT_VALUES.SCHOOL,
id: cookieManager.get(COOKIE_KEYS.SCHOOL_CODE) || "",
await storageManager.get("schoolName", "OM azonosító - Iskola neve"),
id: await storageManager.get("schoolCode", ""),
},
userData: {
name: cookieManager.get(COOKIE_KEYS.USER_NAME) || DEFAULT_VALUES.USER,
name: await storageManager.get("userName", "Felhasználónév"),
time:
document.querySelector(".usermenu_timer")?.textContent?.trim() ||
DEFAULT_VALUES.TIMER,
"45:00",
},
};
this.schoolNameFull = `${this.data.schoolInfo.id} - ${this.data.schoolInfo.name}`;
@@ -475,14 +479,15 @@ class DashboardRenderer {
`;
}
render() {
async render() {
await this.init();
document.body.innerHTML = '';
const kretaContainer = document.createElement('div');
kretaContainer.className = 'kreta-container';
const headerDiv = document.createElement('div');
const parser = new DOMParser();
const headerDoc = parser.parseFromString(createTemplate.header(), 'text/html');
const headerDoc = parser.parseFromString(await createTemplate.header(), 'text/html');
const headerContent = headerDoc.body;
while (headerContent.firstChild) {
headerDiv.appendChild(headerContent.firstChild);
@@ -573,7 +578,7 @@ class DashboardApplication {
const dashboardData = await dataManager.extractAllData();
const renderer = new DashboardRenderer(dashboardData);
renderer.render();
await renderer.render();
} catch (error) {
console.error("Error initializing dashboard:", error);
}

View File

@@ -6,7 +6,8 @@
try {
currentLanguage = language;
cookieManager.set("languagePreference", language);
await storageManager.set("languagePreference", language);
localStorage.setItem("languagePreference", language);
await loadTranslations(language);
@@ -82,20 +83,25 @@
}
async function initializeLanguage() {
const cookieLanguage = cookieManager.get("languagePreference");
const localStorageLanguage = localStorage.getItem("languagePreference");
try {
const storageLanguage = await storageManager.get("languagePreference");
const localStorageLanguage = localStorage.getItem("languagePreference");
const language = storageLanguage || localStorageLanguage || "hu";
const language = cookieLanguage || localStorageLanguage || "hu";
await setLanguage(language);
loadTranslationsForPage();
await setLanguage(language);
loadTranslationsForPage();
if (cookieLanguage !== localStorageLanguage) {
if (cookieLanguage) {
localStorage.setItem("languagePreference", cookieLanguage);
} else if (localStorageLanguage) {
cookieManager.set("languagePreference", localStorageLanguage);
if (storageLanguage !== localStorageLanguage) {
if (storageLanguage) {
localStorage.setItem("languagePreference", storageLanguage);
} else if (localStorageLanguage) {
await storageManager.set("languagePreference", localStorageLanguage);
}
}
} catch (error) {
console.error("Error initializing language:", error);
await setLanguage("hu");
loadTranslationsForPage();
}
}
@@ -121,8 +127,7 @@
function loadTranslationsForPage() {
try {
applyTranslations();
// Figyeljük a DOM változásokat és alkalmazzuk a fordításokat új elemekre
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'childList') {
@@ -142,8 +147,7 @@
}
}
});
// Ha maga az elem is tartalmaz data-i18n attribútumot
if (node.hasAttribute && node.hasAttribute('data-i18n')) {
const key = node.getAttribute('data-i18n');
const translation = getTranslation(key);

View File

@@ -9,12 +9,7 @@ function checkMaintenancePage() {
const maintenanceContent = document.querySelector(".login_content");
const bodyText = document.body ? document.body.textContent : "";
const specificMaintenanceMessage =
"Kedves Felhasználók! A KRÉTA rendszer jelenleg frissítés alatt van, hamarosan újra elérhetővé válik. Köszönjük türelmüket és megértésüket! KRÉTA Csapat";
const hasSpecificMessage =
bodyText.includes("Kedves Felhasználók!") &&
bodyText.includes("A KRÉTA rendszer jelenleg frissítés alatt van") &&
bodyText.includes("KRÉTA Csapat");
const hasSpecificMessage = bodyText.includes("A KRÉTA rendszer jelenleg frissítés alatt van");
const hasGeneralMaintenance =
maintenanceContent &&

View File

@@ -146,6 +146,7 @@
background:var(--hover);
color:var(--accent-accent);
border-radius:8px;
text-decoration:none;
}
@keyframes dropdownShow {
from {

View File

@@ -11,16 +11,16 @@ const DEFAULT_VALUES = {
TIMER: "45:00",
};
function updateHeaderInfo() {
async function updateHeaderInfo() {
const schoolName = document.querySelector(".nav-school-name");
const userName = document.querySelector(".nav-user-name");
const logoutTimer = document.querySelector(".nav-logout-timer");
const userData = {
schoolName:
cookieManager.get(COOKIE_KEYS.SCHOOL_NAME) || DEFAULT_VALUES.SCHOOL,
schoolId: cookieManager.get(COOKIE_KEYS.SCHOOL_CODE) || "",
name: cookieManager.get(COOKIE_KEYS.USER_NAME) || DEFAULT_VALUES.USER,
await storageManager.get("schoolName", DEFAULT_VALUES.SCHOOL),
schoolId: await storageManager.get("schoolCode", ""),
name: await storageManager.get("userName", DEFAULT_VALUES.USER),
time:
document.querySelector(".usermenu_timer")?.textContent?.trim() ||
DEFAULT_VALUES.TIMER,
@@ -59,8 +59,8 @@ function startLogoutTimer(timeString) {
setInterval(updateTimer, 1000);
}
document.addEventListener("DOMContentLoaded", () => {
updateHeaderInfo();
document.addEventListener("DOMContentLoaded", async () => {
await updateHeaderInfo();
});
function setupUserDropdown() {
@@ -169,8 +169,8 @@ function setupMobileNavigation() {
}, 100);
}
document.addEventListener("DOMContentLoaded", () => {
updateHeaderInfo();
document.addEventListener("DOMContentLoaded", async () => {
await updateHeaderInfo();
setupUserDropdown();
setupSettingsButton();
setupMobileNavigation();

View File

@@ -1,10 +1,12 @@
(() => {
function setTheme(theme) {
async function setTheme(theme) {
try {
const actualTheme = theme === "default" ? "light-blue" : theme;
document.documentElement.setAttribute("data-theme", actualTheme);
cookieManager.set("themePreference", actualTheme);
await storageManager.set("themePreference", actualTheme);
localStorage.setItem("themePreference", actualTheme);
chrome.runtime
@@ -104,22 +106,29 @@
}
}
function initializeTheme() {
const cookieTheme = cookieManager.get("themePreference");
const localStorageTheme = localStorage.getItem("themePreference");
async function initializeTheme() {
try {
const storageTheme = await storageManager.get("themePreference");
const localStorageTheme = localStorage.getItem("themePreference");
const theme = cookieTheme || localStorageTheme || "light-green";
const theme = storageTheme || localStorageTheme || "light-green";
setTheme(theme);
setPageTitleAndFavicon();
importFonts();
await setTheme(theme);
setPageTitleAndFavicon();
importFonts();
if (cookieTheme !== localStorageTheme) {
if (cookieTheme) {
localStorage.setItem("themePreference", cookieTheme);
} else if (localStorageTheme) {
cookieManager.set("themePreference", localStorageTheme);
if (storageTheme !== localStorageTheme) {
if (storageTheme) {
localStorage.setItem("themePreference", storageTheme);
} else if (localStorageTheme) {
await storageManager.set("themePreference", localStorageTheme);
}
}
} catch (error) {
console.error("Error initializing theme:", error);
await setTheme("light-green");
setPageTitleAndFavicon();
importFonts();
}
}
@@ -146,17 +155,21 @@
let titleCheckTimeout;
const observer = new MutationObserver((mutations) => {
const observer = new MutationObserver(async (mutations) => {
const currentTheme = document.documentElement.getAttribute("data-theme");
const savedTheme =
cookieManager.get("themePreference") ||
localStorage.getItem("themePreference");
try {
const savedTheme = await storageManager.get("themePreference") ||
localStorage.getItem("themePreference");
if (
(!currentTheme && savedTheme) ||
(currentTheme !== savedTheme && savedTheme)
) {
setTheme(savedTheme);
if (
(!currentTheme && savedTheme) ||
(currentTheme !== savedTheme && savedTheme)
) {
await setTheme(savedTheme);
}
} catch (error) {
console.error("Error checking theme in observer:", error);
}
const titleChanged = mutations.some(

View File

@@ -317,6 +317,7 @@ body {
}
.dropdown-item:hover {
background:var(--button-secondaryFill);
text-decoration:none;
}
.kreta-main {
flex:1;

View File

@@ -11,7 +11,7 @@
window.currentGradesData = gradesData;
document.body.innerHTML = '';
const parser = new DOMParser();
const doc = parser.parseFromString(generatePageHTML(
const doc = parser.parseFromString(await generatePageHTML(
gradesData,
studentAverage,
classAverage,
@@ -61,24 +61,24 @@
}
const data = await response.json();
return processAPIGradesData(data);
return await processAPIGradesData(data);
} catch (error) {
console.error("Error fetching grades from API:", error);
return extractGradesDataFromDOM();
return await extractGradesDataFromDOM();
}
}
function processAPIGradesData(apiData) {
async function processAPIGradesData(apiData) {
const subjects = [];
if (!apiData.Data || !Array.isArray(apiData.Data)) {
return {
schoolInfo: {
id: cookieManager.get("schoolCode") || "",
name: cookieManager.get("schoolName") || "Iskola",
id: await storageManager.get("schoolCode", ""),
name: await storageManager.get("schoolName", "OM azonosító - Iskola neve"),
},
userData: {
name: cookieManager.get("userName") || "Felhasználó",
name: await storageManager.get("userName", "Felhasználónév"),
time:
document.querySelector(".usermenu_timer")?.textContent?.trim() ||
"45:00",
@@ -195,11 +195,11 @@
return {
schoolInfo: {
id: cookieManager.get("schoolCode") || "",
name: cookieManager.get("schoolName") || "Iskola",
id: await storageManager.get("schoolCode", ""),
name: await storageManager.get("schoolName", "Iskola"),
},
userData: {
name: cookieManager.get("userName") || "Felhasználó",
name: await storageManager.get("userName", "Felhasználó"),
time:
document.querySelector(".usermenu_timer")?.textContent?.trim() ||
"45:00",
@@ -208,7 +208,7 @@
};
}
function extractGradesDataFromDOM() {
async function extractGradesDataFromDOM() {
const subjects = [];
const rows = document.querySelectorAll(
"#Osztalyzatok_7895TanuloErtekelesByTanuloGrid tbody tr",
@@ -293,11 +293,11 @@
return {
schoolInfo: {
id: cookieManager.get("schoolCode") || "",
name: cookieManager.get("schoolName") || "Iskola",
id: await storageManager.get("schoolCode", ""),
name: await storageManager.get("schoolName", "Iskola"),
},
userData: {
name: cookieManager.get("userName") || "Felhasználó",
name: await storageManager.get("userName", "Felhasználó"),
time:
document.querySelector(".usermenu_timer")?.textContent?.trim() ||
"45:00",
@@ -376,7 +376,7 @@
return distribution;
}
function generatePageHTML(data, studentAverage, classAverage) {
async function generatePageHTML(data, studentAverage, classAverage) {
const totalGrades = data.subjects.reduce(
(sum, subject) => sum + subject.grades.length,
0,
@@ -393,7 +393,7 @@
return `
<div class="kreta-container">
${createTemplate.header()}
${await createTemplate.header()}
<main class="kreta-main">
<div class="grades-overview">

View File

@@ -169,6 +169,7 @@ body {
.dropdown-item:hover {
background-color: var(--accent-15);
text-decoration: none;
}

View File

@@ -29,11 +29,11 @@ async function collectHomeworkData() {
const basicData = {
schoolInfo: {
name: cookieManager.get("schoolName") || "Iskola",
id: cookieManager.get("schoolCode") || "",
name: await storageManager.get("schoolName", "OM azonosító - Iskola neve"),
id: await storageManager.get("schoolCode", ""),
},
userData: {
name: cookieManager.get("userName") || "Felhasználó",
name: await storageManager.get("userName", "Felhasználónév"),
time:
document.querySelector(".usermenu_timer")?.textContent?.trim() ||
"45:00",
@@ -124,7 +124,7 @@ async function transformHomeworkPage() {
kretaContainer.className = 'kreta-container';
const headerDiv = document.createElement('div');
const parser = new DOMParser();
const headerDoc = parser.parseFromString(createTemplate.header(), 'text/html');
const headerDoc = parser.parseFromString(await createTemplate.header(), 'text/html');
const headerContent = headerDoc.body;
while (headerContent.firstChild) {
headerDiv.appendChild(headerContent.firstChild);
@@ -624,28 +624,28 @@ function updateDateGroupsVisibility() {
});
}
function getHomeworkCompletionStatus(homeworkId) {
const completedHomework = cookieManager.get('completedHomework');
async function getHomeworkCompletionStatus(homeworkId) {
const completedHomework = await storageManager.get('completedHomework');
if (!completedHomework) return false;
try {
const completedList = JSON.parse(completedHomework);
return completedList.includes(homeworkId.toString());
} catch (error) {
console.error('Error parsing completed homework cookie:', error);
console.error('Error parsing completed homework storage:', error);
return false;
}
}
function setHomeworkCompletionStatus(homeworkId, isCompleted) {
let completedHomework = cookieManager.get('completedHomework');
async function setHomeworkCompletionStatus(homeworkId, isCompleted) {
let completedHomework = await storageManager.get('completedHomework');
let completedList = [];
if (completedHomework) {
try {
completedList = JSON.parse(completedHomework);
} catch (error) {
console.error('Error parsing completed homework cookie:', error);
console.error('Error parsing completed homework storage:', error);
completedList = [];
}
}
@@ -660,7 +660,7 @@ function setHomeworkCompletionStatus(homeworkId, isCompleted) {
completedList = completedList.filter(id => id !== homeworkIdStr);
}
cookieManager.set('completedHomework', JSON.stringify(completedList));
await storageManager.set('completedHomework', JSON.stringify(completedList));
}
function setupHomeworkCheckboxes() {

View File

@@ -116,7 +116,36 @@
"thursday": "Thursday",
"friday": "Friday",
"found_current_week": "Found current week",
"open_homework": "Open homework"
"open_homework": "Open homework",
"all_day": "All day",
"special_day": "Special day",
"unknown_subject": "Unknown subject",
"lesson_topic": "Lesson topic",
"homework_completed": "Completed homework",
"homework_mark_completed": "Mark as completed",
"homework_mark_uncompleted": "Completed - click to undo",
"custom_homework": "Custom homework",
"custom_test": "Custom test",
"add_homework_test": "Add homework or test",
"close": "Close",
"add": "Add",
"homework_details_loading": "Loading homework details...",
"homework_details_error": "Error occurred while loading homework details.",
"test_details_loading": "Loading details...",
"test_details_error": "Failed to load test details.",
"test_details_error_general": "Error occurred while loading test details.",
"custom_homework_title": "Custom homework:",
"custom_tests_title": "Custom tests:",
"delete_homework_confirm": "Are you sure you want to delete this homework?",
"delete_test_confirm": "Are you sure you want to delete this test?",
"task_label": "Task:",
"deadline_label": "Deadline:",
"name_label": "Name:",
"type_label": "Type:",
"announce_date_label": "Announcement date:",
"no_name": "No name",
"no_type": "No type specified",
"no_date": "No date"
},
"homework": {
"title": "Homework",
@@ -350,7 +379,27 @@
"error_message": "An error occurred during password reset",
"success_message": "Password reset link sent to your email address",
"invalid_data": "Invalid data",
"invalid_email": "Invalid email address format",
"invalid_email": "Invalid email format",
"recaptcha_required": "Please complete the reCAPTCHA"
},
"modal": {
"add_item_title": "Add new item",
"type_label": "Type:",
"homework_option": "Homework",
"test_option": "Test",
"description_label": "Description:",
"cancel": "Cancel",
"save": "Save"
},
"grades": {
"semester_evaluation": "Semester evaluation"
},
"search": {
"choose_school": "Choose school",
"privacy_policy": "Privacy policy"
},
"icons": {
"cancel": "cancel",
"pending": "pending"
}
}

View File

@@ -75,6 +75,7 @@
"teacher": "Tanár",
"average": "Átlag",
"chart_title": "Jegyek",
"semester_evaluation": "Félévi értékelés",
"semester_evaluations": "Félévi értékelések",
"year_end_evaluations": "Év végi értékelések",
"semester_average": "Félévi átlag",
@@ -116,7 +117,36 @@
"thursday": "Csütörtök",
"friday": "Péntek",
"found_current_week": "Megtalált jelenlegi hét",
"open_homework": "Ugrás a házi feladatokhoz"
"open_homework": "Ugrás a házi feladatokhoz",
"all_day": "Egész nap",
"special_day": "Különleges nap",
"unknown_subject": "Ismeretlen tantárgy",
"lesson_topic": "Óra témája",
"homework_completed": "Megoldott házi feladat",
"homework_mark_completed": "Megoldottként jelöl",
"homework_mark_uncompleted": "Megoldva - kattints a visszavonáshoz",
"custom_homework": "Saját házi feladat",
"custom_test": "Saját számonkérés",
"add_homework_test": "Házi feladat vagy számonkérés hozzáadása",
"close": "Bezárás",
"add": "Hozzáadás",
"homework_details_loading": "Házi feladat részletek betöltése...",
"homework_details_error": "Hiba történt a házi feladat részletek betöltésekor.",
"test_details_loading": "Részletek betöltése...",
"test_details_error": "Nem sikerült betölteni a számonkérés részleteit.",
"test_details_error_general": "Hiba történt a számonkérés részletek betöltése során.",
"custom_homework_title": "Saját házi feladatok:",
"custom_tests_title": "Saját számonkérések:",
"delete_homework_confirm": "Biztosan törölni szeretnéd ezt a házi feladatot?",
"delete_test_confirm": "Biztosan törölni szeretnéd ezt a számonkérést?",
"task_label": "Feladat:",
"deadline_label": "Határidő:",
"name_label": "Megnevezés:",
"type_label": "Típus:",
"announce_date_label": "Bejelentés dátuma:",
"no_name": "Nincs megnevezés",
"no_type": "Nincs típus megadva",
"no_date": "Nincs dátum"
},
"homework": {
"title": "Házi feladatok",
@@ -307,10 +337,6 @@
"november": "november",
"december": "december"
},
"search": {
"title": "Válassz iskolát",
"select_institution": "Kérjük, válasszon egy intézményt a folytatáshoz!"
},
"roleselect": {
"student_book": "Ellenőrzőkönyv",
"student_description": "Jegyek, hiányzások, órarended és egyéb információk megtekintése.",
@@ -352,5 +378,24 @@
"invalid_data": "Hibás adatok",
"invalid_email": "Érvénytelen e-mail cím formátum",
"recaptcha_required": "Kérjük, töltse ki a reCAPTCHA-t"
},
"modal": {
"add_item_title": "Új elem hozzáadása",
"type_label": "Típus:",
"homework_option": "Házi feladat",
"test_option": "Számonkérés",
"description_label": "Leírás:",
"cancel": "Mégse",
"save": "Mentés"
},
"search": {
"choose_school": "Válassz iskolát",
"privacy_policy": "Adatkezelési tájékoztató",
"title": "Válassz iskolát",
"select_institution": "Kérjük, válasszon egy intézményt a folytatáshoz!"
},
"icons": {
"cancel": "cancel",
"pending": "pending"
}
}

1
icons/delete.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 24 24"><g fill="none"><path fill="#A7DC22" d="M9 7h9v11a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2V7z"/><path stroke="#A7DC22" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 7h-2M4 7h2m0 0h12M6 7v11a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V7m-9-.5A2.5 2.5 0 0 1 11.5 4h1A2.5 2.5 0 0 1 15 6.5v0"/></g></svg>

After

Width:  |  Height:  |  Size: 384 B

1
icons/plus.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 24 24"><path fill="none" stroke="#A7DC22" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 12h7m7 0h-7m0 0V5m0 7v7"/></svg>

After

Width:  |  Height:  |  Size: 222 B

View File

@@ -1,10 +1,10 @@
(() => {
function transformLogoutPage() {
async function transformLogoutPage() {
const theme =
cookieManager.get("themePreference") ||
await storageManager.get("themePreference", null) ||
localStorage.getItem("themePreference") ||
"light-green";
const instituteCode = cookieManager.get("schoolSubdomain");
const instituteCode = await storageManager.get("schoolSubdomain", null);
document.documentElement.setAttribute("data-theme", theme);
const newHTML = `
@@ -65,8 +65,18 @@
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", transformLogoutPage);
document.addEventListener("DOMContentLoaded", () => {
setTimeout(() => {
if (typeof loadingScreen !== 'undefined') {
loadingScreen.hide();
}
}, 100);
transformLogoutPage();
});
} else {
if (typeof loadingScreen !== 'undefined') {
loadingScreen.hide();
}
transformLogoutPage();
}
})();

View File

@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "Firxa",
"version": "1.3.2",
"version": "1.3.4",
"description": "KRÉTA webes verziójának újraírása",
"icons": {
"128": "images/firka_logo_128.png"
@@ -12,6 +12,12 @@
"128": "images/firka_logo_128.png"
}
},
"permissions": [
"storage"
],
"background": {
"service_worker": "tools/background.js"
},
"browser_specific_settings": {
"gecko": {
"id": "firxa@zan1456.hu",
@@ -31,7 +37,9 @@
"icons/*.svg",
"grades/chart.js",
"i18n/*.json",
"tools/cookieManager.js"
"tools/cookieManager.js",
"tools/storageManager.js",
"tools/storageTest.js"
],
"matches": [
"<all_urls>"
@@ -58,7 +66,7 @@
"global/language.js",
"global/theme.js",
"tools/loadingScreen.js",
"tools/cookieManager.js",
"tools/storageManager.js",
"tools/helper.js",
"tools/createTemplate.js",
"global/maintenance.js",

View File

@@ -253,10 +253,14 @@ to {
}
.side-roles {
grid-template-columns:1fr;
gap:1rem;
gap:0.75rem;
}
.role-card {
padding:1.5rem;
padding:1rem;
gap:1rem;
}
.role-card[data-role="Ellenorzo"],.role-card[data-role="DKT"],.logout-card {
height:200px;
}
.role-icon {
width:40px;
@@ -267,9 +271,53 @@ to {
height:24px;
}
.role-text {
font-size:1.2rem;
font-size:1.5rem;
}
.role-description {
font-size:1rem;
font-size:1.2rem;
}
.user-name {
font-size:18px;
}
.logout-timer {
font-size:16px;
}
}
@media (max-width:480px) {
.kreta-container {
padding:0.75rem;
}
.kreta-header {
margin-bottom:1.5rem;
}
.side-roles {
gap:0.5rem;
}
.role-card {
padding:0.75rem;
gap:0.75rem;
}
.role-card[data-role="Ellenorzo"],.role-card[data-role="DKT"],.logout-card {
height:160px;
}
.role-text {
font-size:1.6rem;
line-height:1.2;
}
.role-description {
font-size:1.3rem;
line-height:1.3;
}
.user-name {
font-size:20px;
}
.logout-timer {
font-size:18px;
}
.school-details {
font-size:0.9rem;
}
.logo-text {
font-size:1.1rem;
}
}

View File

@@ -120,12 +120,12 @@
userNameEl?.textContent.trim() || LanguageManager.t("common.username");
if (schoolCode && fullSchoolName) {
cookieManager.set("schoolCode", schoolCode);
cookieManager.set("schoolName", fullSchoolName);
cookieManager.set("schoolSubdomain", schoolSubdomain);
await storageManager.set("schoolCode", schoolCode);
await storageManager.set("schoolName", fullSchoolName);
await storageManager.set("schoolSubdomain", schoolSubdomain);
}
if (userName) {
cookieManager.set("userName", userName);
await storageManager.set("userName", userName);
}
document.body.innerHTML = '';
const parser = new DOMParser();

View File

@@ -126,9 +126,11 @@ form {
li.dropdown-item:hover,li.dropdown-item:focus {
background-color:var(--accent-15) !important;
color:var(--text-primary) !important;
text-decoration:none !important;
}
a.dropdown-item:hover,a.dropdown-item:focus {
background-color:#00000000 !important;
text-decoration:none !important;
}
.dropdown-item.active {
background-color:var(--accent-accent) !important;

View File

@@ -20,10 +20,10 @@ if (
setTimeout(initializeTransformation, 1000);
}
function applyFirkaStyling() {
async function applyFirkaStyling() {
try {
const theme =
cookieManager.get("themePreference") ||
await storageManager.get("themePreference") ||
localStorage.getItem("themePreference") ||
"light-green";
document.documentElement.setAttribute("data-theme", theme);

View File

@@ -139,6 +139,7 @@ body {
}
.dropdown-item:hover {
background:var(--button-secondaryFill);
text-decoration:none;
}
.kreta-main {
flex:1;
@@ -783,9 +784,46 @@ body {
border-radius:8px;
transition:all 0.2s ease;
}
.modal-header-buttons {
display: flex;
align-items: center;
gap: 0.5rem;
}
.modal-add-btn {
background: none;
border: none;
color: var(--text-secondary);
cursor: pointer;
padding: 0.5rem;
border-radius: 8px;
transition: all 0.2s ease;
display: flex;
align-items: center;
justify-content: center;
}
.modal-add-btn:hover {
background: var(--background);
color: var(--text-primary);
}
.modal-close {
background: none;
border: none;
color: var(--text-secondary);
cursor: pointer;
padding: 0.5rem;
border-radius: 8px;
transition: all 0.2s ease;
display: flex;
align-items: center;
justify-content: center;
}
.modal-close:hover {
background:var(--background);
color:var(--text-primary);
background: var(--background);
color: var(--text-primary);
}
.modal-body {
padding:1.5rem;
@@ -828,6 +866,352 @@ body {
.test-section h4 {
color:var(--warning-accent);
}
.custom-homework-section h4,
.custom-tests-section h4 {
color: var(--accent-accent);
}
.custom-homework-list,
.custom-tests-list {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.custom-homework-item,
.custom-test-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.75rem;
background: var(--background);
border-radius: 8px;
border: 1px solid var(--background-0);
transition: all 0.2s ease;
}
.custom-homework-item.completed,
.custom-test-item.completed {
opacity: 0.6;
}
.custom-homework-item.completed .homework-text,
.custom-test-item.completed .test-text {
text-decoration: line-through;
}
.homework-text,
.test-text {
flex: 1;
color: var(--text-primary);
font-size: 14px;
line-height: 1.4;
}
.homework-actions,
.test-actions {
display: flex;
align-items: center;
gap: 0.5rem;
}
.homework-complete-btn,
.test-complete-btn,
.homework-delete-btn,
.test-delete-btn {
background: none;
border: none;
cursor: pointer;
padding: 0.25rem;
border-radius: 4px;
transition: all 0.2s ease;
display: flex;
align-items: center;
justify-content: center;
}
.homework-complete-btn:hover,
.test-complete-btn:hover {
background: var(--accent-accent-20);
}
.homework-delete-btn:hover,
.test-delete-btn:hover {
background: var(--error-20);
}
.empty-message {
color: var(--text-secondary);
font-style: italic;
text-align: center;
padding: 1rem;
margin: 0;
}
.add-item-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
display: flex !important;
align-items: center !important;
justify-content: center !important;
z-index: 10001;
opacity: 0;
visibility: hidden;
transition: all 0.3s ease;
}
.add-item-modal.show {
opacity: 1;
visibility: visible;
}
.add-modal-content {
background: var(--button-secondaryFill);
border-radius: 12px;
width: 90%;
max-width: 400px;
max-height: 90vh;
overflow-y: auto;
position: relative;
transform: translateY(20px);
opacity: 0;
transition: all 0.3s ease;
}
.add-item-modal.show .add-modal-content {
transform: translateY(0);
opacity: 1;
}
.add-modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1.5rem;
border-bottom: 1px solid var(--background-0);
}
.add-modal-header h3 {
font-size: 18px;
font-weight: 600;
color: var(--text-primary);
margin: 0;
}
.add-modal-close {
background: none;
border: none;
color: var(--text-secondary);
cursor: pointer;
padding: 0.5rem;
border-radius: 8px;
transition: all 0.2s ease;
display: flex;
align-items: center;
justify-content: center;
}
.add-modal-close:hover {
background: var(--background);
color: var(--text-primary);
}
.add-modal-body {
padding: 1.5rem;
display: flex;
flex-direction: column;
gap: 1rem;
}
.type-selection,
.text-input {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.type-selection label,
.text-input label {
color: var(--text-primary);
font-weight: 500;
font-size: 14px;
}
.type-select {
padding: 0.75rem;
border: 1px solid var(--background-0);
border-radius: 8px;
background: var(--background);
color: var(--text-primary);
font-size: 14px;
transition: all 0.2s ease;
}
.type-select:focus {
outline: none;
border-color: var(--accent-accent);
}
.item-text {
padding: 0.75rem;
border: 1px solid var(--background-0);
border-radius: 8px;
background: var(--background);
color: var(--text-primary);
font-size: 14px;
font-family: inherit;
resize: vertical;
min-height: 80px;
transition: all 0.2s ease;
}
.item-text:focus {
outline: none;
border-color: var(--accent-accent);
}
.item-text::placeholder {
color: var(--text-secondary);
}
.add-modal-actions {
display: flex;
gap: 0.75rem;
justify-content: flex-end;
margin-top: 0.5rem;
}
.cancel-btn,
.save-btn {
padding: 0.75rem 1.5rem;
border: none;
border-radius: 8px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
}
.cancel-btn {
background: var(--background);
color: var(--text-secondary);
border: 1px solid var(--background-0);
}
.cancel-btn:hover {
background: var(--background-0);
color: var(--text-primary);
}
.save-btn {
background: var(--accent-accent);
color: white;
}
.save-btn:hover {
background: var(--accent-accent-80);
}
@media (max-width: 768px) {
.lesson-modal {
z-index: 10000;
}
.add-item-modal {
z-index: 10001;
}
.modal-content {
width: 95%;
max-width: none;
margin: 1rem;
}
.add-modal-content {
width: 95%;
max-width: none;
margin: 1rem;
}
.modal-header,
.add-modal-header {
padding: 1rem;
}
.modal-body,
.add-modal-body {
padding: 1rem;
}
.modal-header-buttons {
gap: 0.25rem;
}
.modal-add-btn,
.modal-close,
.add-modal-close {
padding: 0.375rem;
}
.modal-add-btn img,
.modal-close img,
.add-modal-close img {
width: 20px !important;
height: 20px !important;
}
.custom-homework-item,
.custom-test-item {
padding: 0.5rem;
flex-direction: column;
align-items: flex-start;
gap: 0.5rem;
}
.homework-actions,
.test-actions {
align-self: flex-end;
}
.homework-text,
.test-text {
font-size: 13px;
}
.add-modal-actions {
flex-direction: column;
gap: 0.5rem;
}
.cancel-btn,
.save-btn {
width: 100%;
padding: 0.875rem;
}
}
@media (min-width: 769px) {
.lesson-modal {
z-index: 10000;
}
.add-item-modal {
z-index: 10001;
}
.modal-content {
position: relative;
}
.add-modal-content {
position: relative;
}
}
.tema-section h4 {
color:var(--primary-accent);
}

File diff suppressed because it is too large Load Diff

106
tools/background.js Normal file
View File

@@ -0,0 +1,106 @@
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
(async () => {
try {
switch (request.action) {
case 'storage_set':
await handleStorageSet(request.key, request.value);
sendResponse({ success: true });
break;
case 'storage_get':
const value = await handleStorageGet(request.key, request.defaultValue);
sendResponse({ success: true, value: value });
break;
case 'storage_remove':
await handleStorageRemove(request.key);
sendResponse({ success: true });
break;
case 'storage_clear':
await handleStorageClear();
sendResponse({ success: true });
break;
default:
console.warn('[Background] Unknown action:', request.action);
sendResponse({ success: false, error: 'Unknown action' });
}
} catch (error) {
console.error('[Background] Error handling message:', error);
sendResponse({ success: false, error: error.message });
}
})();
return true;
});
async function handleStorageSet(key, value) {
try {
await chrome.storage.sync.set({ [key]: value });
} catch (error) {
console.error(`[Background] Failed to save ${key}:`, error);
throw error;
}
}
async function handleStorageGet(key, defaultValue = null) {
try {
const result = await chrome.storage.sync.get(key);
const value = result[key];
return value !== undefined ? value : defaultValue;
} catch (error) {
console.error(`[Background] Failed to get ${key}:`, error);
throw error;
}
}
async function handleStorageRemove(key) {
try {
await chrome.storage.sync.remove(key);
} catch (error) {
console.error(`[Background] Failed to remove ${key}:`, error);
throw error;
}
}
async function handleStorageClear() {
try {
const allData = await chrome.storage.sync.get(null);
const firkaKeys = Object.keys(allData).filter(key => key.startsWith('firka_'));
if (firkaKeys.length > 0) {
await chrome.storage.sync.remove(firkaKeys);
}
} catch (error) {
console.error('[Background] Failed to clear storage:', error);
throw error;
}
}
chrome.storage.onChanged.addListener((changes, namespace) => {
if (namespace === 'sync') {
const firkaChanges = Object.keys(changes).filter(key => key.startsWith('firka_'));
if (firkaChanges.length > 0) {
notifyContentScriptsOfChanges(changes);
}
}
});
async function notifyContentScriptsOfChanges(changes) {
try {
const tabs = await chrome.tabs.query({ url: 'https://*.e-kreta.hu/*' });
for (const tab of tabs) {
try {
await chrome.tabs.sendMessage(tab.id, {
action: 'storage_changed',
changes: changes
});
} catch (error) {
console.debug(`[Background] Could not notify tab ${tab.id}:`, error.message);
}
}
} catch (error) {
console.error('[Background] Failed to notify content scripts:', error);
}
}

View File

@@ -1,25 +0,0 @@
const cookieManager = {
get(name) {
const cookieName = `${name}=`;
const decodedCookie = decodeURIComponent(document.cookie);
const cookieArray = decodedCookie.split(";");
for (let i = 0; i < cookieArray.length; i++) {
let cookie = cookieArray[i];
while (cookie.charAt(0) === " ") {
cookie = cookie.substring(1);
}
if (cookie.indexOf(cookieName) === 0) {
return cookie.substring(cookieName.length, cookie.length);
}
}
return null;
},
set(name, value, days = 365) {
const date = new Date();
date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
const expires = `expires=${date.toUTCString()}`;
document.cookie = `${name}=${value}; ${expires}; path=/; domain=.e-kreta.hu`;
},
};

View File

@@ -1,16 +1,15 @@
const createTemplate = {
header() {
async header() {
const data = {
schoolInfo: {
name: cookieManager.get("schoolName") || "Iskola",
id: cookieManager.get("schoolCode") || "",
name: await storageManager.get("schoolName", "OM azonosító - Iskola neve"),
id: await storageManager.get("schoolCode", ""),
},
userData: {
name: cookieManager.get("userName") || "Felhasználó",
name: await storageManager.get("userName", "Felhasználónév"),
time:
document.querySelector(".usermenu_timer")?.textContent?.trim() ||
"45:00",
email: cookieManager.get("userEmail") || "",
},
};

View File

@@ -65,7 +65,13 @@ window.addEventListener("DOMContentLoaded", () => {
});
}
if (urls.some((url) => url.includes(location.pathname))) {
const currentUrl = location.href;
const shouldShowLoading = urls.some((urlPattern) => {
const regex = new RegExp(urlPattern.replace(/\*/g, '.*'));
return regex.test(currentUrl);
});
if (shouldShowLoading) {
loadingScreen.show();
}
});

193
tools/storageManager.js Normal file
View File

@@ -0,0 +1,193 @@
const storageManager = {
isExtensionContext() {
return typeof chrome !== 'undefined' && chrome.runtime && chrome.runtime.id;
},
isContentScript() {
return typeof chrome !== 'undefined' && chrome.runtime && chrome.runtime.sendMessage;
},
async set(key, value) {
const prefixedKey = `firka_${key}`;
try {
if (this.isExtensionContext()) {
await chrome.storage.sync.set({ [prefixedKey]: value });
} else if (this.isContentScript()) {
return new Promise((resolve, reject) => {
chrome.runtime.sendMessage({
action: 'storage_set',
key: prefixedKey,
value: value
}, (response) => {
if (chrome.runtime.lastError) {
reject(chrome.runtime.lastError);
} else if (response && response.success) {
resolve();
} else {
reject(new Error('Failed to save via message passing'));
}
});
});
} else {
localStorage.setItem(prefixedKey, JSON.stringify(value));
}
} catch (error) {
console.warn(`[StorageManager] Primary storage failed for ${key}, falling back to cookie:`, error);
if (typeof cookieManager !== 'undefined') {
cookieManager.set(prefixedKey, JSON.stringify(value));
}
}
},
async get(key, defaultValue = null) {
const prefixedKey = `firka_${key}`;
try {
if (this.isExtensionContext()) {
const result = await chrome.storage.sync.get(prefixedKey);
const value = result[prefixedKey];
return value !== undefined ? value : defaultValue;
} else if (this.isContentScript()) {
return new Promise((resolve, reject) => {
chrome.runtime.sendMessage({
action: 'storage_get',
key: prefixedKey,
defaultValue: defaultValue
}, (response) => {
if (chrome.runtime.lastError) {
reject(chrome.runtime.lastError);
} else if (response && response.hasOwnProperty('value')) {
resolve(response.value);
} else {
reject(new Error('Failed to get via message passing'));
}
});
});
} else {
const value = localStorage.getItem(prefixedKey);
if (value !== null) {
return JSON.parse(value);
}
return defaultValue;
}
} catch (error) {
console.warn(`[StorageManager] Primary storage failed for ${key}, falling back to cookie:`, error);
if (typeof cookieManager !== 'undefined') {
const cookieValue = cookieManager.get(prefixedKey);
if (cookieValue) {
try {
return JSON.parse(cookieValue);
} catch (parseError) {
return cookieValue;
}
}
}
return defaultValue;
}
},
async remove(key) {
const prefixedKey = `firka_${key}`;
try {
if (this.isExtensionContext()) {
await chrome.storage.sync.remove(prefixedKey);
} else if (this.isContentScript()) {
return new Promise((resolve, reject) => {
chrome.runtime.sendMessage({
action: 'storage_remove',
key: prefixedKey
}, (response) => {
if (chrome.runtime.lastError) {
reject(chrome.runtime.lastError);
} else if (response && response.success) {
resolve();
} else {
reject(new Error('Failed to remove via message passing'));
}
});
});
} else {
localStorage.removeItem(prefixedKey);
}
} catch (error) {
console.warn(`[StorageManager] Failed to remove ${key}:`, error);
}
},
async clear() {
try {
if (this.isExtensionContext()) {
const allData = await chrome.storage.sync.get(null);
const firkaKeys = Object.keys(allData).filter(key => key.startsWith('firka_'));
if (firkaKeys.length > 0) {
await chrome.storage.sync.remove(firkaKeys);
}
} else if (this.isContentScript()) {
return new Promise((resolve, reject) => {
chrome.runtime.sendMessage({
action: 'storage_clear'
}, (response) => {
if (chrome.runtime.lastError) {
reject(chrome.runtime.lastError);
} else if (response && response.success) {
resolve();
} else {
reject(new Error('Failed to clear via message passing'));
}
});
});
} else {
const keysToRemove = [];
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
if (key && key.startsWith('firka_')) {
keysToRemove.push(key);
}
}
keysToRemove.forEach(key => localStorage.removeItem(key));
}
} catch (error) {
console.warn('[StorageManager] Failed to clear storage:', error);
}
},
async migrateFromCookies() {
if (typeof cookieManager === 'undefined') {
return;
}
const knownSettings = [
'theme', 'language', 'notifications', 'autoRefresh',
'compactMode', 'showGrades', 'showAbsences'
];
let migratedCount = 0;
for (const setting of knownSettings) {
try {
const cookieValue = cookieManager.get(`firka_${setting}`);
if (cookieValue !== null) {
let value;
try {
value = JSON.parse(cookieValue);
} catch {
value = cookieValue;
}
await this.set(setting, value);
migratedCount++;
}
} catch (error) {
console.warn(`[StorageManager] Failed to migrate ${setting}:`, error);
}
}
}
};
if (typeof document !== 'undefined') {
document.addEventListener('DOMContentLoaded', () => {
storageManager.migrateFromCookies().catch(console.error);
});
}