29 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
Zan
9fd0190ab8 Elmaradt órák megjelenítése 2025-09-09 22:16:53 +02:00
Zan
94fbc472f6 Mark homework as done (timetable) 2025-09-09 22:10:50 +02:00
Zan
96be6471f0 Homework in timetable site 2025-09-09 21:52:36 +02:00
Zan
10cabc3889 Update login.js 2025-09-09 21:38:04 +02:00
Zan
6cddce142c Profile page rework 2025-09-09 20:05:05 +02:00
Zan
f81d821c56 Óra témája és számonkérés megjelenik a modalban (HW WIP) 2025-09-08 23:21:15 +02:00
Zan
0a5439acfd Mark as done, fixes 2025-09-08 23:09:49 +02:00
Zan
dac927cf7d Data collection, firefox 2025-09-08 21:59:59 +02:00
Zan
b4a270a8d2 Firefox addons fix 2025-09-08 21:51:55 +02:00
Zan
110ba0d4fb Delete KRÉTA Iskolai Alaprendszer.html 2025-09-08 19:42:55 +02:00
Zan
1ba976e06e Update manifest.json 2025-09-08 19:35:32 +02:00
Zan
df8adf65de . 2025-09-08 19:32:05 +02:00
Zan
e96c9e1c83 1.3.0 2025-09-01 19:20:21 +02:00
Zan
a3631d749f Navbar open fix and logo fix in settings 2025-09-01 15:52:08 +02:00
Zan
fa7c773393 Added new icons, fixed day notice on timetables 2025-09-01 15:21:15 +02:00
Zan
a39295ae68 test 2025-08-31 20:53:36 +02:00
Zan1456
d722740bdf New layout for absences 2025-08-06 22:56:12 +02:00
Zan1456
1218d3b905 . 2025-08-06 22:48:21 +02:00
Zan1456
bbe8a4b2b3 Minimal fixes 2025-08-06 14:41:22 +02:00
57 changed files with 11387 additions and 8032 deletions

View File

@@ -1,436 +1,485 @@
* {
box-sizing: border-box;
margin: 0;
padding: 0;
box-sizing:border-box;
margin:0;
padding:0;
}
body {
margin: 0;
padding: 0;
color: var(--text-primary);
background-color: var(--background) !important;
font-family: "Montserrat", serif !important;
min-height: 100vh;
font-size: 16px;
margin:0;
padding:0;
color:var(--text-primary);
background-color:var(--background) !important;
font-family:"Montserrat",serif !important;
min-height:100vh;
font-size:16px;
}
@media (max-width: 768px) {
@media (max-width:768px) {
body {
font-size: 14px;
}
font-size:14px;
}
.kreta-container {
min-height: 100vh;
display: flex;
flex-direction: column;
}.kreta-container {
min-height:100vh;
display:flex;
flex-direction:column;
}
.kreta-header {
padding: clamp(1rem, 3vw, 2rem);
display: grid;
grid-template-columns: minmax(300px, 400px) 1fr minmax(200px, 300px);
align-items: center;
gap: 1rem;
padding:clamp(1rem,3vw,2rem);
display:grid;
grid-template-columns:minmax(300px,400px) 1fr minmax(200px,300px);
align-items:center;
gap:1rem;
}
@media (max-width: 1200px) {
@media (max-width:1200px) {
.kreta-header {
grid-template-columns: minmax(250px, 350px) 1fr minmax(180px, 250px);
}
grid-template-columns:minmax(250px,350px) 1fr minmax(180px,250px);
}
@media (max-width: 768px) {
}@media (max-width:768px) {
.kreta-header {
grid-template-columns: 1fr auto auto;
grid-template-areas:
"school toggle user"
grid-template-columns:1fr auto auto;
grid-template-areas:"school toggle user"
"nav nav nav";
padding: 1rem;
gap: 0.5rem;
}
padding:1rem;
gap:0.5rem;
}
.school-info {
margin: 0;
}.school-info {
margin:0;
}
@media (max-width: 768px) {
@media (max-width:768px) {
.school-info {
grid-area: school;
max-width: none;
display: flex;
align-items: center;
gap: 0.5rem;
}
grid-area:school;
max-width:none;
display:flex;
align-items:center;
gap:0.5rem;
}
.logo-text {
color: var(--text-primary);
font-size: 24px;
font-weight: 600;
margin: 0 0 0.5rem;
display: flex;
align-items: center;
}.logo-text {
color:var(--text-primary);
font-size:24px;
font-weight:600;
margin:0 0 0.5rem;
display:flex;
align-items:center;
}
@media (max-width: 768px) {
@media (max-width:768px) {
.logo-text {
margin: 0;
font-size: 20px;
}
margin:0;
font-size:20px;
}
.logo {
width: 24px;
border-radius: 8px;
margin-right: 0.5rem;
}.logo {
width:24px;
border-radius:8px;
margin-right:0.5rem;
}
.school-details {
color: var(--text-secondary);
font-size: 14px;
color:var(--text-secondary);
font-size:14px;
}
.school-details span {
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 300px;
display:block;
white-space:nowrap;
overflow:hidden;
text-overflow:ellipsis;
max-width:300px;
}
@media (max-width: 768px) {
@media (max-width:768px) {
.school-details span {
max-width: 200px;
}
.school-details {
font-size: 12px;
}
max-width:200px;
}
.user-profile {
position: relative;
justify-self: flex-end;
.school-details {
font-size:12px;
}
@media (max-width: 768px) {
}.user-profile {
position:relative;
justify-self:flex-end;
}
@media (max-width:768px) {
.user-profile {
grid-area: user;
}
grid-area:user;
}
.user-dropdown-btn {
display: flex;
align-items: center;
gap: 1rem;
background: none;
border: none;
cursor: pointer;
padding: 0.5rem;
border-radius: 8px;
transition: background-color 0.2s;
}.user-dropdown-btn {
display:flex;
align-items:center;
gap:1rem;
background:none;
border:none;
cursor:pointer;
padding:0.5rem;
border-radius:8px;
transition:background-color 0.2s;
}
.user-dropdown-btn:hover {
background: var(--card-card);
background:var(--card-card);
}
.user-info {
text-align: right;
text-align:right;
}
.user-dropdown {
position: absolute;
top: 100%;
right: 0;
margin-top: 0.5rem;
background: var(--card-card);
border-radius: 12px;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
width: 200px;
display: none;
z-index: 1000;
position:absolute;
top:100%;
right:0;
margin-top:0.5rem;
background:var(--card-card);
border-radius:12px;
box-shadow:0 4px 6px -1px rgba(0,0,0,0.1);
width:200px;
display:none;
z-index:1000;
}
.user-dropdown.show {
display: block;
animation: dropdownShow 0.2s ease;
display:block;
animation:dropdownShow 0.2s ease;
}
.dropdown-item {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.75rem 1rem;
color: var(--text-primary);
text-decoration: none;
transition: background-color 0.2s;
display:flex;
align-items:center;
gap:0.75rem;
padding:0.75rem 1rem;
color:var(--text-primary);
text-decoration:none;
transition:background-color 0.2s;
}
.dropdown-item:hover {
background: var(--button-secondaryFill);
background:var(--button-secondaryFill);
text-decoration:none;
}
.kreta-main {
flex: 1;
padding: clamp(1rem, 3vw, 2rem);
max-width: 1200px;
margin: 0 auto;
width: 100%;
flex:1;
padding:clamp(1rem,3vw,2rem);
max-width:1200px;
margin:0 auto;
width:100%;
}
.filter-card {
background: var(--card-card);
border-radius: 24px;
padding: 20px;
margin-bottom: 24px;
box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow);
background:var(--card-card);
border-radius:24px;
padding:20px;
margin-bottom:24px;
box-shadow:0px 1px var(--shadow-blur) 0px var(--accent-shadow);
}
.filter-header {
margin-bottom: 16px;
margin-bottom:16px;
}
.filter-header h2 {
font-size: 18px;
font-weight: 600;
color: var(--text-primary);
background-color: var(--card-card);
font-size:18px;
font-weight:600;
color:var(--text-primary);
background-color:var(--card-card);
}
.filter-content {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 16px;
display:grid;
grid-template-columns:repeat(auto-fit,minmax(200px,1fr));
gap:16px;
}
.filter-group {
display: flex;
flex-direction: column;
gap: 8px;
display:flex;
flex-direction:column;
gap:8px;
}
.filter-group label {
display: flex;
align-items: center;
gap: 8px;
color: var(--text-secondary);
font-size: 14px;
display:flex;
align-items:center;
gap:8px;
color:var(--text-secondary);
font-size:14px;
}
.filter-input {
padding: 10px;
border: none;
border-radius: 8px;
background: var(--button-secondaryFill);
color: var(--text-primary);
font-family: inherit;
font-size: 14px;
transition: all 0.2s ease;
padding:10px;
border:none;
border-radius:8px;
background:var(--button-secondaryFill);
color:var(--text-primary);
font-family:inherit;
font-size:14px;
transition:all 0.2s ease;
}
.filter-input:focus {
outline: none;
box-shadow: 0 0 0 2px var(--accent-accent);
outline:none;
box-shadow:0 0 0 2px var(--accent-accent);
}
.stats-overview {
display:grid;
grid-template-columns:repeat(auto-fit,minmax(200px,1fr));
gap:16px;
margin-bottom:24px;
}
.stat-card {
background:var(--card-card);
border-radius:16px;
padding:20px;
text-align:center;
box-shadow:0px 1px var(--shadow-blur) 0px var(--accent-shadow);
transition:transform 0.2s ease;
}
.stat-card:hover {
transform:translateY(-2px);
}
.stat-number {
font-size:32px;
font-weight:700;
color:var(--accent-accent);
margin-bottom:8px;
}
.stat-label {
color:var(--text-secondary);
font-size:14px;
font-weight:500;
}
.absences-container {
display: flex;
flex-direction: column;
gap: 16px;
background:var(--card-card);
border-radius:16px;
overflow:hidden;
box-shadow:0px 1px var(--shadow-blur) 0px var(--accent-shadow);
}
.absence-group {
background: var(--card-card);
border-radius: 24px;
overflow: hidden;
animation: fadeIn 0.3s ease;
box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow);
.absences-table {
width:100%;
border-collapse:collapse;
}
.absence-date {
padding: 16px;
color: var(--text-primary);
font-weight: 600;
display: flex;
align-items: center;
gap: 8px;
.table-header {
background:var(--accent-15);
border-bottom:1px solid var(--accent-30);
}
.absence-count {
margin-left: auto;
background: var(--accent-accent);
color: var(--button-secondaryFill);
padding: 4px 8px;
border-radius: 12px;
font-size: 14px;
.table-header th {
padding:16px;
text-align:left;
font-weight:600;
color:var(--text-primary);
font-size:14px;
text-transform:uppercase;
letter-spacing:0.5px;
}
.absence-list {
padding: 16px;
display: flex;
flex-direction: column;
gap: 12px;
.table-row {
border-bottom:1px solid var(--accent-15);
transition:background-color 0.2s ease;
}
.absence-item {
display: grid;
grid-template-columns: auto 1fr auto;
align-items: center;
gap: 16px;
padding: 12px;
background: var(--accent-15);
border-radius: 12px;
transition: transform 0.2s ease;
.table-row:hover {
background:var(--accent-10);
}
.absence-item:hover {
transform: translateX(4px);
.table-row:last-child {
border-bottom:none;
}
.absence-time {
display: flex;
align-items: center;
gap: 4px;
color: var(--text-secondary);
font-size: 14px;
.table-cell {
padding:16px;
color:var(--text-primary);
vertical-align:middle;
}
.absence-details {
display: flex;
flex-direction: column;
gap: 4px;
.date-cell {
font-weight:600;
color:var(--accent-accent);
}
.lesson-cell {
text-align:center;
font-weight:500;
}
.subject-cell {
font-weight:600;
}
.topic-cell {
color:var(--text-secondary);
font-size:14px;
max-width:200px;
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap;
}
.status-cell {
text-align:center;
}
.status-badge {
display:inline-flex;
align-items:center;
gap:4px;
padding:6px 12px;
border-radius:20px;
font-size:12px;
font-weight:600;
text-transform:uppercase;
letter-spacing:0.5px;
}
.status-badge.justified {
background:var(--grades-4-bg);
color:var(--grades-4);
}
.status-badge.unjustified {
background:var(--grades-1-bg);
color:var(--grades-1);
}
.status-badge.pending {
background:var(--grades-3-bg);
color:var(--grades-3);
}
@media (max-width:768px) {
.absences-table {
font-size:14px;
}
.table-header th,.table-cell {
padding:12px 8px;
}
.topic-cell {
max-width:120px;
}
.stats-overview {
grid-template-columns:repeat(2,1fr);
}
}@media (max-width:480px) {
.absences-table,.table-header,.table-row {
display:block;
}
.table-header {
display:none;
}
.date-group {
margin-bottom:24px;
}
.date-group-header {
background:var(--accent-accent);
color:white;
padding:12px 16px;
border-radius:12px 12px 0 0;
font-weight:600;
font-size:16px;
margin-bottom:0;
}
.date-group-content {
background:var(--card-card);
border:1px solid var(--accent-15);
border-radius:0 0 12px 12px;
overflow:hidden;
}
.table-row {
width:100%;
margin-bottom:0;
border:none;
border-bottom:1px solid var(--accent-15);
border-radius:0;
padding:16px;
background:transparent;
}
.table-row:last-child {
border-bottom:none;
}
.table-cell {
display:flex;
justify-content:space-between;
align-items:flex-start;
padding:6px 0;
border-bottom:1px solid var(--accent-15);
}
.table-cell:last-child {
border-bottom:none;
}
.table-cell::before {
content:attr(data-label);
font-weight:600;
color:var(--text-secondary);
font-size:12px;
text-transform:uppercase;
flex-shrink:0;
}
.topic-cell {
max-width:none;
white-space:normal;
text-overflow:initial;
overflow:visible;
text-align:right;
flex:1;
}
.stats-overview {
grid-template-columns:1fr;
}
}.absence-details {
display:flex;
flex-direction:column;
gap:4px;
}
.absence-subject {
font-weight: 600;
color: var(--text-primary);
font-weight:600;
color:var(--text-primary);
}
.absence-topic {
color: var(--text-secondary);
font-size: 14px;
color:var(--text-secondary);
font-size:14px;
}
.absence-status {
display: flex;
align-items: center;
gap: 4px;
font-size: 14px;
font-weight: 500;
display:flex;
align-items:center;
gap:4px;
font-size:14px;
font-weight:500;
}
.absence-status.justified {
color: var(--grades-4);
color:var(--grades-4);
}
.absence-status.unjustified {
color: var(--grades-1);
color:var(--grades-1);
}
.absence-status.pending {
color: var(--grades-3);
color:var(--grades-3);
}
.loading-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: var(--background);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 9999;
position:fixed;
top:0;
left:0;
width:100%;
height:100%;
background:var(--background);
display:flex;
flex-direction:column;
align-items:center;
justify-content:center;
z-index:9999;
}
.loading-container {
display: flex;
flex-direction: column;
align-items: center;
gap: 1rem;
padding: 2rem;
border-radius: 24px;
display:flex;
flex-direction:column;
align-items:center;
gap:1rem;
padding:2rem;
border-radius:24px;
}
.loading-text {
color: var(--Text-Primary);
text-align: center;
font-family: Montserrat;
font-size: 20px;
font-style: normal;
font-weight: 700;
line-height: normal;
color:var(--Text-Primary);
text-align:center;
font-family:Montserrat;
font-size:20px;
font-style:normal;
font-weight:700;
line-height:normal;
}
.loading-text2 {
align-self: stretch;
color: var(--Text-Secondary);
text-align: center;
font-family: Figtree;
font-size: 16px;
font-style: normal;
font-weight: 500;
line-height: 130%;
align-self:stretch;
color:var(--Text-Secondary);
text-align:center;
font-family:Figtree;
font-size:16px;
font-style:normal;
font-weight:500;
line-height:130%;
}
.loading-logo {
width: 48px;
height: 48px;
margin-bottom: 1rem;
border-radius: 8px;
width:48px;
height:48px;
margin-bottom:1rem;
border-radius:8px;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
opacity:0;
transform:translateY(-10px);
}
@keyframes dropdownShow {
to {
opacity:1;
transform:translateY(0);
}
}@keyframes dropdownShow {
from {
opacity: 0;
transform: translateY(-10px);
}
opacity:0;
transform:translateY(-10px);
}
to {
opacity:1;
transform:translateY(0);
}
}@keyframes spin {
to {
opacity: 1;
transform: translateY(0);
}
transform:rotate(360deg);
}
@keyframes spin {
to { transform: rotate(360deg); }
}
::-webkit-scrollbar {
width: clamp(4px, 1vw, 8px);
height: clamp(4px, 1vw, 8px);
}
::-webkit-scrollbar-track {
background: var(--background);
}
::-webkit-scrollbar-thumb {
background: var(--text-secondary);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--text-primary);
}

View File

@@ -1,25 +1,30 @@
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ó',
time: document.querySelector('.usermenu_timer')?.textContent?.trim() || '45:00'
}
name: await storageManager.get("userName", "Felhasználónév"),
time:
document.querySelector(".usermenu_timer")?.textContent?.trim() ||
"45:00",
},
};
try {
const currentDomain = window.location.hostname;
const response = await fetch(`https://${currentDomain}/api/HianyzasokApi/GetHianyzasGrid?sort=MulasztasDatum-desc&page=1&pageSize=100&group=&filter=&data=%7B%7D&_=${Date.now()}`, {
method: 'GET',
credentials: 'include',
headers: {
'Accept': 'application/json, text/javascript, */*; q=0.01',
'X-Requested-With': 'XMLHttpRequest'
}
});
const response = await fetch(
`https://${currentDomain}/api/HianyzasokApi/GetHianyzasGrid?sort=MulasztasDatum-desc&page=1&pageSize=100&group=&filter=&data=%7B%7D&_=${Date.now()}`,
{
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}`);
@@ -29,33 +34,33 @@ async function collectAbsencesData() {
const absences = [];
if (apiData.Data && Array.isArray(apiData.Data)) {
apiData.Data.forEach(item => {
apiData.Data.forEach((item) => {
const date = new Date(item.MulasztasDatum);
const formattedDate = `${date.getFullYear()}.${(date.getMonth() + 1).toString().padStart(2, '0')}.${date.getDate().toString().padStart(2, '0')}.`;
const formattedDate = `${date.getFullYear()}.${(date.getMonth() + 1).toString().padStart(2, "0")}.${date.getDate().toString().padStart(2, "0")}.`;
let justificationStatus = 'pending';
let justificationStatus = "pending";
if (item.Igazolt_BOOL === true) {
justificationStatus = 'justified';
justificationStatus = "justified";
} else if (item.Igazolt_BOOL === false && item.IgazolasTipus !== null) {
justificationStatus = 'unjustified';
justificationStatus = "unjustified";
}
absences.push({
date: formattedDate,
lesson: item.Oraszam?.toString() || '',
subject: item.Targy || '',
topic: item.Tema || '',
type: item.MulasztasTipus_DNAME || '',
lesson: item.Oraszam?.toString() || "",
subject: item.Targy || "",
topic: item.Tema || "",
type: item.MulasztasTipus_DNAME || "",
justified: item.Igazolt_BOOL === true,
justificationStatus: justificationStatus,
purposeful: item.TanoraiCeluMulasztas_BNAME || '',
justificationType: item.IgazolasTipus_DNAME || ''
purposeful: item.TanoraiCeluMulasztas_BNAME || "",
justificationType: item.IgazolasTipus_DNAME || "",
});
});
}
const groupedAbsences = {};
absences.forEach(absence => {
absences.forEach((absence) => {
if (!groupedAbsences[absence.date]) {
groupedAbsences[absence.date] = [];
}
@@ -64,120 +69,446 @@ async function collectAbsencesData() {
return { basicData, absences, groupedAbsences };
} catch (error) {
console.error('Hiba az API hívás során:', error);
console.error("Hiba az API hívás során:", error);
return { basicData, absences: [], groupedAbsences: {} };
}
}
function createFilterCard(absences) {
const filterCard = document.createElement('div');
filterCard.className = 'filter-card';
const filterHeader = document.createElement('div');
filterHeader.className = 'filter-header';
const h2 = document.createElement('h2');
h2.textContent = LanguageManager.t('absences.filter_title');
filterHeader.appendChild(h2);
const filterContent = document.createElement('div');
filterContent.className = 'filter-content';
const dateGroup = createFilterGroup(
'Calendar.svg',
'Dátum',
LanguageManager.t('absences.date'),
'input',
{ type: 'date', id: 'dateFilter', className: 'filter-input' }
);
filterContent.appendChild(dateGroup);
const subjectGroup = createSubjectFilterGroup(absences);
filterContent.appendChild(subjectGroup);
const justificationGroup = createJustificationFilterGroup();
filterContent.appendChild(justificationGroup);
filterCard.appendChild(filterHeader);
filterCard.appendChild(filterContent);
return filterCard;
}
function createFilterGroup(iconName, altText, labelText, elementType, attributes) {
const group = document.createElement('div');
group.className = 'filter-group';
const label = document.createElement('label');
const img = document.createElement('img');
img.src = chrome.runtime.getURL(`icons/${iconName}`);
img.alt = altText;
img.style.width = '24px';
img.style.height = '24px';
label.appendChild(img);
label.appendChild(document.createTextNode(' ' + labelText));
const element = document.createElement(elementType);
Object.assign(element, attributes);
group.appendChild(label);
group.appendChild(element);
return group;
}
function createSubjectFilterGroup(absences) {
const group = document.createElement('div');
group.className = 'filter-group';
const label = document.createElement('label');
const img = document.createElement('img');
img.src = chrome.runtime.getURL('icons/Subject.svg');
img.alt = 'Tantárgy';
img.style.width = '24px';
img.style.height = '24px';
label.appendChild(img);
label.appendChild(document.createTextNode(' ' + LanguageManager.t('absences.subject')));
const select = document.createElement('select');
select.id = 'subjectFilter';
select.className = 'filter-input';
const defaultOption = document.createElement('option');
defaultOption.value = '';
defaultOption.textContent = LanguageManager.t('absences.all_subjects');
select.appendChild(defaultOption);
const subjects = [...new Set(absences.map(a => a.subject))].sort();
subjects.forEach(subject => {
const option = document.createElement('option');
option.value = subject;
option.textContent = subject;
select.appendChild(option);
});
group.appendChild(label);
group.appendChild(select);
return group;
}
function createJustificationFilterGroup() {
const group = document.createElement('div');
group.className = 'filter-group';
const label = document.createElement('label');
const img = document.createElement('img');
img.src = chrome.runtime.getURL('icons/BadgeCheck.svg');
img.alt = 'Igazolás';
img.style.width = '24px';
img.style.height = '24px';
label.appendChild(img);
label.appendChild(document.createTextNode(' ' + LanguageManager.t('absences.justification')));
const select = document.createElement('select');
select.id = 'justificationFilter';
select.className = 'filter-input';
const options = [
{ value: '', text: LanguageManager.t('absences.all_types') },
{ value: 'justified', text: LanguageManager.t('absences.justified') },
{ value: 'unjustified', text: LanguageManager.t('absences.unjustified') },
{ value: 'pending', text: LanguageManager.t('absences.pending') }
];
options.forEach(optionData => {
const option = document.createElement('option');
option.value = optionData.value;
option.textContent = optionData.text;
select.appendChild(option);
});
group.appendChild(label);
group.appendChild(select);
return group;
}
function createStatsOverview(absences) {
const statsOverview = document.createElement('div');
statsOverview.className = 'stats-overview';
const stats = [
{ number: absences.length, label: LanguageManager.t('absences.total_absences') },
{ number: absences.filter(a => a.justificationStatus === 'justified').length, label: LanguageManager.t('absences.justified') },
{ number: absences.filter(a => a.justificationStatus === 'unjustified').length, label: LanguageManager.t('absences.unjustified') },
{ number: absences.filter(a => a.justificationStatus === 'pending').length, label: LanguageManager.t('absences.pending') }
];
stats.forEach(stat => {
const statCard = document.createElement('div');
statCard.className = 'stat-card';
const statNumber = document.createElement('div');
statNumber.className = 'stat-number';
statNumber.textContent = stat.number;
const statLabel = document.createElement('div');
statLabel.className = 'stat-label';
statLabel.textContent = stat.label;
statCard.appendChild(statNumber);
statCard.appendChild(statLabel);
statsOverview.appendChild(statCard);
});
return statsOverview;
}
function createAbsencesContainer(absences) {
const container = document.createElement('div');
container.className = 'absences-container';
const table = document.createElement('table');
table.className = 'absences-table';
const thead = document.createElement('thead');
thead.className = 'table-header';
const headerRow = document.createElement('tr');
const headers = [
LanguageManager.t('absences.date'),
LanguageManager.t('absences.lesson'),
LanguageManager.t('absences.subject'),
LanguageManager.t('absences.topic'),
LanguageManager.t('absences.status')
];
headers.forEach(headerText => {
const th = document.createElement('th');
th.textContent = headerText;
headerRow.appendChild(th);
});
thead.appendChild(headerRow);
const tbody = document.createElement('tbody');
generateAbsencesRows(absences, tbody);
table.appendChild(thead);
table.appendChild(tbody);
container.appendChild(table);
return container;
}
async function transformAbsencesPage() {
const { basicData, absences, groupedAbsences } = await collectAbsencesData();
document.body.textContent = '';
const container = document.createElement('div');
container.className = 'kreta-container';
const headerDiv = document.createElement('div');
const parser = new DOMParser();
const doc = parser.parseFromString(await createTemplate.header(), 'text/html');
const tempDiv = doc.body;
while (tempDiv.firstChild) {
headerDiv.appendChild(tempDiv.firstChild);
}
container.appendChild(headerDiv);
const main = document.createElement('main');
main.className = 'kreta-main';
const filterCard = createFilterCard(absences);
main.appendChild(filterCard);
const statsOverview = createStatsOverview(absences);
main.appendChild(statsOverview);
const absencesContainer = createAbsencesContainer(absences);
main.appendChild(absencesContainer);
container.appendChild(main);
document.body.appendChild(container);
document.body.innerHTML = `
<div class="kreta-container">
${createTemplate.header()}
<main class="kreta-main">
<div class="filter-card">
<div class="filter-header">
<h2>${LanguageManager.t('absences.filter_title')}</h2>
</div>
<div class="filter-content">
<div class="filter-group">
<label>
<span class="material-icons-round">date_range</span>
${LanguageManager.t('absences.date')}
</label>
<input type="date" id="dateFilter" class="filter-input">
</div>
<div class="filter-group">
<label>
<span class="material-icons-round">school</span>
${LanguageManager.t('absences.subject')}
</label>
<select id="subjectFilter" class="filter-input">
<option value="">${LanguageManager.t('absences.all_subjects')}</option>
${[...new Set(absences.map(a => a.subject))].sort().map(subject =>
`<option value="${subject}">${subject}</option>`
).join('')}
</select>
</div>
<div class="filter-group">
<label>
<span class="material-icons-round">check_circle</span>
${LanguageManager.t('absences.justification')}
</label>
<select id="justificationFilter" class="filter-input">
<option value="">${LanguageManager.t('absences.all_types')}</option>
<option value="justified">${LanguageManager.t('absences.justified')}</option>
<option value="unjustified">${LanguageManager.t('absences.unjustified')}</option>
<option value="pending">${LanguageManager.t('absences.pending')}</option>
</select>
</div>
</div>
</div>
<div class="absences-container">
${Object.entries(groupedAbsences).map(([date, dayAbsences]) => `
<div class="absence-group" data-date="${date}">
<div class="absence-date">
<span class="material-icons-round">event</span>
${date}
<span class="absence-count">${dayAbsences.length} ${LanguageManager.t('absences.hours')}</span>
</div>
<div class="absence-list">
${dayAbsences.map(absence => `
<div class="absence-item"
data-subject="${absence.subject}"
data-justified="${absence.justified}">
<div class="absence-time">
<span class="material-icons-round">schedule</span>
${absence.lesson}. ${LanguageManager.t('absences.lesson').toLowerCase()}
</div>
<div class="absence-details">
<div class="absence-subject">${absence.subject}</div>
<div class="absence-topic">${absence.topic}</div>
</div>
<div class="absence-status ${absence.justificationStatus}">
${absence.justificationStatus === 'justified' ?
`${LanguageManager.t('absences.justified')} <span class="material-icons-round">check_circle</span>` :
absence.justificationStatus === 'unjustified' ?
`${LanguageManager.t('absences.unjustified')} <span class="material-icons-round">cancel</span>` :
`${LanguageManager.t('absences.pending')} <span class="material-icons-round">pending</span>`}
</div>
</div>
`).join('')}
</div>
</div>
`).join('')}
</div>
</main>
</div>
`;
createTemplate.importFonts();
setupUserDropdown();
setupMobileNavigation();
setupEventListeners();
setupFilters();
loadingScreen.hide();
}
function generateAbsencesRows(absences, tbody) {
const groupedByDate = absences.reduce((groups, absence) => {
const date = absence.date;
if (!groups[date]) {
groups[date] = [];
}
groups[date].push(absence);
return groups;
}, {});
const sortedDates = Object.keys(groupedByDate).sort(
(a, b) => new Date(b) - new Date(a),
);
sortedDates.forEach((date) => {
const dateAbsences = groupedByDate[date];
const divider = document.createElement('tr');
divider.className = 'date-group-divider';
divider.style.display = 'none';
tbody.appendChild(divider);
dateAbsences.forEach((absence) => {
const row = document.createElement('tr');
row.className = 'table-row';
row.dataset.subject = absence.subject;
row.dataset.justified = absence.justified;
row.dataset.date = absence.date;
row.dataset.dateGroup = date;
const dateCell = document.createElement('td');
dateCell.className = 'table-cell date-cell';
dateCell.dataset.label = LanguageManager.t('absences.date');
dateCell.textContent = absence.date;
row.appendChild(dateCell);
const lessonCell = document.createElement('td');
lessonCell.className = 'table-cell lesson-cell';
lessonCell.dataset.label = LanguageManager.t('absences.lesson');
lessonCell.textContent = absence.lesson + '.';
row.appendChild(lessonCell);
const subjectCell = document.createElement('td');
subjectCell.className = 'table-cell subject-cell';
subjectCell.dataset.label = LanguageManager.t('absences.subject');
subjectCell.textContent = absence.subject;
row.appendChild(subjectCell);
const topicCell = document.createElement('td');
topicCell.className = 'table-cell topic-cell';
topicCell.dataset.label = LanguageManager.t('absences.topic');
topicCell.title = absence.topic;
topicCell.textContent = absence.topic;
row.appendChild(topicCell);
const statusCell = document.createElement('td');
statusCell.className = 'table-cell status-cell';
statusCell.dataset.label = LanguageManager.t('absences.status');
const statusBadge = document.createElement('span');
statusBadge.className = `status-badge ${absence.justificationStatus}`;
if (absence.justificationStatus === 'justified') {
const img = document.createElement('img');
img.src = chrome.runtime.getURL('icons/BadgeCheck.svg');
img.alt = 'Igazolt';
img.style.width = '16px';
img.style.height = '16px';
statusBadge.appendChild(img);
statusBadge.appendChild(document.createTextNode(' ' + LanguageManager.t('absences.justified')));
} else if (absence.justificationStatus === 'unjustified') {
const span = document.createElement('span');
span.className = 'material-icons-round';
span.textContent = 'cancel';
statusBadge.appendChild(span);
statusBadge.appendChild(document.createTextNode(' ' + LanguageManager.t('absences.unjustified')));
} else {
const span = document.createElement('span');
span.className = 'material-icons-round';
span.textContent = 'pending';
statusBadge.appendChild(span);
statusBadge.appendChild(document.createTextNode(' ' + LanguageManager.t('absences.pending')));
}
statusCell.appendChild(statusBadge);
row.appendChild(statusCell);
tbody.appendChild(row);
});
});
}
function setupEventListeners() {
function setupMobileGrouping() {
if (window.innerWidth <= 480) {
createMobileGroups();
} else {
removeMobileGroups();
}
}
window.addEventListener("resize", setupMobileGrouping);
setupMobileGrouping();
}
function createMobileGroups() {
const tbody = document.querySelector(".absences-table tbody");
if (!tbody) return;
removeMobileGroups();
const rows = Array.from(tbody.querySelectorAll(".table-row"));
const groupedRows = {};
rows.forEach((row) => {
const date = row.dataset.date;
if (!groupedRows[date]) {
groupedRows[date] = [];
}
groupedRows[date].push(row);
});
const sortedDates = Object.keys(groupedRows).sort(
(a, b) => new Date(b) - new Date(a),
);
while (tbody.firstChild) {
tbody.removeChild(tbody.firstChild);
}
sortedDates.forEach((date) => {
const dateRows = groupedRows[date];
const dateGroup = document.createElement("div");
dateGroup.className = "date-group";
const dateHeader = document.createElement("div");
dateHeader.className = "date-group-header";
dateHeader.textContent = date;
const dateContent = document.createElement("div");
dateContent.className = "date-group-content";
dateRows.forEach((row) => {
dateContent.appendChild(row);
});
dateGroup.appendChild(dateHeader);
dateGroup.appendChild(dateContent);
tbody.appendChild(dateGroup);
});
}
function removeMobileGroups() {
const tbody = document.querySelector(".absences-table tbody");
if (!tbody) return;
const dateGroups = tbody.querySelectorAll(".date-group");
if (dateGroups.length === 0) return;
const allRows = [];
dateGroups.forEach((group) => {
const rows = group.querySelectorAll(".table-row");
rows.forEach((row) => allRows.push(row));
});
while (tbody.firstChild) {
tbody.removeChild(tbody.firstChild);
}
allRows.forEach((row) => tbody.appendChild(row));
}
function updateDateGroupsVisibility() {
if (window.innerWidth > 480) return;
const dateGroups = document.querySelectorAll(".date-group");
dateGroups.forEach((group) => {
const visibleRows = group.querySelectorAll(
'.table-row[style=""], .table-row:not([style])',
);
if (visibleRows.length > 0) {
group.style.display = "";
} else {
group.style.display = "none";
}
});
}
function setupFilters() {
try {
const filters = {
dateFilter: document.getElementById('dateFilter'),
subject: document.getElementById('subjectFilter'),
justified: document.getElementById('justificationFilter')
dateFilter: document.getElementById("dateFilter"),
subject: document.getElementById("subjectFilter"),
justified: document.getElementById("justificationFilter"),
};
if (!filters.dateFilter || !filters.subject || !filters.justified) {
console.warn('Some filter elements were not found in the DOM');
console.warn("Some filter elements were not found in the DOM");
return;
}
@@ -188,91 +519,120 @@ function setupFilters() {
const justified = filters.justified.value;
const selectedDate = dateFilterValue ? new Date(dateFilterValue) : null;
document.querySelectorAll('.absence-group').forEach(group => {
const dateStr = group.dataset.date;
const dateParts = dateStr.split('.');
document.querySelectorAll(".table-row").forEach((row) => {
const dateStr = row.dataset.date;
const dateParts = dateStr.split(".");
if (dateParts.length < 3) {
console.error(`Invalid date format: ${dateStr}`);
return;
}
const parsedYear = parseInt(dateParts[0].trim(), 10);
const parsedMonth = parseInt(dateParts[1].trim(), 10) - 1;
const parsedDay = parseInt(dateParts[2].trim(), 10);
if (isNaN(parsedDay) || isNaN(parsedMonth) || isNaN(parsedYear)) {
console.error(`Invalid date components: ${dateStr}`);
return;
}
const groupDate = new Date(parsedYear, parsedMonth, parsedDay);
let showGroup = true;
const rowDate = new Date(parsedYear, parsedMonth, parsedDay);
let showRow = true;
if (selectedDate) {
if (groupDate.getFullYear() !== selectedDate.getFullYear() ||
groupDate.getMonth() !== selectedDate.getMonth() ||
groupDate.getDate() !== selectedDate.getDate()) {
showGroup = false;
if (
rowDate.getFullYear() !== selectedDate.getFullYear() ||
rowDate.getMonth() !== selectedDate.getMonth() ||
rowDate.getDate() !== selectedDate.getDate()
) {
showRow = false;
}
}
const absenceItems = group.querySelectorAll('.absence-item');
let visibleItems = 0;
if (subject && row.dataset.subject !== subject) {
showRow = false;
}
absenceItems.forEach(item => {
let showItem = true;
if (subject && item.dataset.subject !== subject) showItem = false;
if (justified) {
const statusElement = item.querySelector('.absence-status');
const hasStatus = statusElement.classList.contains(justified);
if (!hasStatus) showItem = false;
}
if (justified) {
const statusElement = row.querySelector(".status-badge");
const hasStatus = statusElement.classList.contains(justified);
if (!hasStatus) showRow = false;
}
item.style.display = showItem ? '' : 'none';
if (showItem) visibleItems++;
});
group.style.display = (showGroup && visibleItems > 0) ? '' : 'none';
row.style.display = showRow ? "" : "none";
});
updateDateGroupsVisibility();
updateStatistics();
} catch (err) {
console.error('Error during filtering absences:', err);
console.error("Error during filtering absences:", err);
}
};
Object.values(filters).forEach(filter => {
Object.values(filters).forEach((filter) => {
try {
if (filter) {
filter.addEventListener('change', filterAbsences);
filter.addEventListener("change", filterAbsences);
}
} catch (err) {
if (err.message && err.message.includes('Extension context invalidated')) {
console.warn('Extension context invalidated during event listener setup');
if (
err.message &&
err.message.includes("Extension context invalidated")
) {
console.warn(
"Extension context invalidated during event listener setup",
);
} else {
console.error('Error setting up filter event listener:', err);
console.error("Error setting up filter event listener:", err);
}
}
});
filterAbsences();
} catch (err) {
if (err.message && err.message.includes('Extension context invalidated')) {
console.warn('Extension context invalidated during filter setup');
if (err.message && err.message.includes("Extension context invalidated")) {
console.warn("Extension context invalidated during filter setup");
} else {
console.error('Error setting up filters:', err);
console.error("Error setting up filters:", err);
}
}
}
function updateStatistics() {
try {
const visibleRows = document.querySelectorAll(
'.table-row:not([style*="display: none"])',
);
const totalVisible = visibleRows.length;
const justifiedVisible = Array.from(visibleRows).filter((row) =>
row.querySelector(".status-badge.justified"),
).length;
const unjustifiedVisible = Array.from(visibleRows).filter((row) =>
row.querySelector(".status-badge.unjustified"),
).length;
const pendingVisible = Array.from(visibleRows).filter((row) =>
row.querySelector(".status-badge.pending"),
).length;
if (window.location.href.includes('/Hianyzas/Hianyzasok')) {
transformAbsencesPage().catch(error => {
console.error(LanguageManager.t('absences.page_transform_error'), error);
const statCards = document.querySelectorAll(".stat-card");
if (statCards[0])
statCards[0].querySelector(".stat-number").textContent = totalVisible;
if (statCards[1])
statCards[1].querySelector(".stat-number").textContent = justifiedVisible;
if (statCards[2])
statCards[2].querySelector(".stat-number").textContent =
unjustifiedVisible;
if (statCards[3])
statCards[3].querySelector(".stat-number").textContent = pendingVisible;
} catch (err) {
console.error("Error updating statistics:", err);
}
}
if (window.location.href.includes("/Hianyzas/Hianyzasok")) {
transformAbsencesPage().catch((error) => {
console.error(LanguageManager.t("absences.page_transform_error"), error);
});
}

View File

@@ -140,9 +140,10 @@ h2 {
font-weight: 600;
font-size: 16px;
line-height: 1.3;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
word-wrap: break-word;
overflow-wrap: break-word;
hyphens: auto;
max-width: 100%;
}
.widget-subtitle {
@@ -150,6 +151,8 @@ h2 {
font-weight: 500;
font-size: 14px;
line-height: 1.2;
word-wrap: break-word;
overflow-wrap: break-word;
}
.widget-content {
@@ -186,6 +189,8 @@ h2 {
font-size: 12px;
font-weight: 400;
margin-top: 4px;
word-wrap: break-word;
overflow-wrap: break-word;
}
.grade-date {
@@ -196,20 +201,69 @@ h2 {
text-align: right;
}
.widget-author {
color: var(--text-tertiary);
font-size: 12px;
font-weight: 400;
word-wrap: break-word;
overflow-wrap: break-word;
max-width: 100%;
}
.widget-meta {
.news-author {
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 4px;
text-align: right;
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 {
@@ -236,21 +290,27 @@ h2 {
font-size: 16px;
font-weight: 600;
margin-bottom: 8px;
word-wrap: break-word;
overflow-wrap: break-word;
hyphens: auto;
line-height: 1.4;
}
.news-content {
font-size: 14px;
line-height: 1.4;
color: var(--text-secondary);
word-wrap: break-word;
overflow-wrap: break-word;
hyphens: auto;
}
.exam-type {
color: var(--accent-accent);
font-size: 12px;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.more-link {
margin-top: auto;
display: inline-flex;
@@ -331,6 +391,7 @@ h2 {
.dropdown-item:hover {
background-color: var(--accent-15);
text-decoration: none;
}
.dropdown-item svg {
@@ -349,14 +410,6 @@ h2 {
line-height: 1.4;
color: var(--text-secondary);
}
.exam-type {
color: var(--accent-accent);
font-size: 12px;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.more-link {
margin-top: auto;
display: inline-flex;

View File

@@ -1,44 +1,63 @@
const DashboardUtils = {
formatGradeValue(value) {
const trimmedValue = value?.trim() || '';
if (trimmedValue.toLowerCase() === 'szöveges') {
return 'Sz';
const trimmedValue = value?.trim() || "";
if (trimmedValue.toLowerCase() === "szöveges") {
return "Sz";
}
return trimmedValue;
},
parseDate(dateStr) {
return dateStr?.trim() || '';
return dateStr?.trim() || "";
},
formatHungarianDate(dateStr) {
if (!dateStr) return '';
const dateParts = dateStr.trim().split('.');
if (!dateStr) return "";
const dateParts = dateStr.trim().split(".");
if (dateParts.length < 3) return dateStr;
const month = parseInt(dateParts[1], 10);
const day = parseInt(dateParts[2], 10);
if (isNaN(month) || month < 1 || month > 12) return dateStr;
if (typeof window.LanguageManager !== 'undefined') {
if (typeof window.LanguageManager !== "undefined") {
const monthKeys = [
'months.january', 'months.february', 'months.march', 'months.april',
'months.may', 'months.june', 'months.july', 'months.august',
'months.september', 'months.october', 'months.november', 'months.december'
"months.january",
"months.february",
"months.march",
"months.april",
"months.may",
"months.june",
"months.july",
"months.august",
"months.september",
"months.october",
"months.november",
"months.december",
];
const monthName = window.LanguageManager.t(monthKeys[month - 1]);
return `${monthName} ${day}.`;
}
const monthKeys = [
'months.january', 'months.february', 'months.march', 'months.april', 'months.may', 'months.june',
'months.july', 'months.august', 'months.september', 'months.october', 'months.november', 'months.december'
"months.january",
"months.february",
"months.march",
"months.april",
"months.may",
"months.june",
"months.july",
"months.august",
"months.september",
"months.october",
"months.november",
"months.december",
];
return `${LanguageManager.t(monthKeys[month - 1])} ${day}.`;
}
},
};
class DashboardDataManager {
@@ -48,175 +67,216 @@ class DashboardDataManager {
absences: [],
notes: [],
upcomingExams: [],
news: []
news: [],
};
}
extractGradeData() {
const gradeRows = document.querySelectorAll('#legutobbiErtekelesek tr:not(:first-child)');
this.dashboardData.grades = Array.from(gradeRows).map(row => {
const gradeValue = row.querySelector('span[style*="font-size: 200%"]')?.textContent;
const gradeInfo = row.querySelector('span[style*="float: right"]')?.textContent;
if (!gradeValue || !gradeInfo) return null;
const gradeRows = document.querySelectorAll(
"#legutobbiErtekelesek tr:not(:first-child)",
);
const [fullSubject, date] = gradeInfo.split('\n').map(str => str.trim());
const { subject, type, dateInSubject } = this.parseSubjectInformation(fullSubject);
this.dashboardData.grades = Array.from(gradeRows)
.map((row) => {
const gradeValue = row.querySelector(
'span[style*="font-size: 200%"]',
)?.textContent;
const gradeInfo = row.querySelector(
'span[style*="float: right"]',
)?.textContent;
return {
value: DashboardUtils.formatGradeValue(gradeValue),
subject,
date: DashboardUtils.parseDate(date),
type: type || LanguageManager.t('dashboard.evaluation'),
dateInSubject: dateInSubject || null
};
}).filter(Boolean);
if (!gradeValue || !gradeInfo) return null;
const [fullSubject, date] = gradeInfo
.split("\n")
.map((str) => str.trim());
const { subject, type, dateInSubject } =
this.parseSubjectInformation(fullSubject);
return {
value: DashboardUtils.formatGradeValue(gradeValue),
subject,
date: DashboardUtils.parseDate(date),
type: type || LanguageManager.t("dashboard.evaluation"),
dateInSubject: dateInSubject || null,
};
})
.filter(Boolean);
}
parseSubjectInformation(fullSubject) {
const hungarianMonths = ['január', 'február', 'március', 'április', 'május', 'június',
'július', 'augusztus', 'szeptember', 'október', 'november', 'december'];
const monthPattern = hungarianMonths.join('|');
const datePattern = new RegExp(`(${monthPattern})\\s+(\\d{1,2})\\.?$`, 'i');
const hungarianMonths = [
"január",
"február",
"március",
"április",
"május",
"június",
"július",
"augusztus",
"szeptember",
"október",
"november",
"december",
];
const monthPattern = hungarianMonths.join("|");
const datePattern = new RegExp(`(${monthPattern})\\s+(\\d{1,2})\\.?$`, "i");
const dateMatch = fullSubject.match(datePattern);
if (dateMatch) {
const subjectPart = fullSubject.substring(0, dateMatch.index).trim();
const datePart = dateMatch[0].trim();
return {
subject: subjectPart,
type: '',
dateInSubject: datePart
type: "",
dateInSubject: datePart,
};
}
const months = [
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')
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 fallbackMonthPattern = new RegExp(months.join('|'), 'i');
const fallbackMonthPattern = new RegExp(months.join("|"), "i");
const monthMatch = fullSubject.match(fallbackMonthPattern);
if (monthMatch) {
const monthIndex = fullSubject.lastIndexOf(monthMatch[0]);
return {
subject: fullSubject.substring(0, monthIndex).trim(),
type: fullSubject.substring(monthIndex).trim()
type: fullSubject.substring(monthIndex).trim(),
};
}
return { subject: fullSubject, type: '' };
return { subject: fullSubject, type: "" };
}
extractAbsenceData() {
const absenceRows = document.querySelectorAll('#legutobbiMulasztasok tr:not(:first-child)');
this.dashboardData.absences = Array.from(absenceRows).map(row => {
const spans = row.querySelectorAll('span');
if (spans.length < 4) return null;
const absenceRows = document.querySelectorAll(
"#legutobbiMulasztasok tr:not(:first-child)",
);
return {
date: spans[0]?.textContent?.trim() || '',
day: spans[2]?.textContent?.trim() || '',
type: spans[1]?.textContent?.trim() || '',
count: spans[3]?.textContent?.trim() || ''
};
}).filter(Boolean);
this.dashboardData.absences = Array.from(absenceRows)
.map((row) => {
const spans = row.querySelectorAll("span");
if (spans.length < 4) return null;
return {
date: spans[0]?.textContent?.trim() || "",
day: spans[2]?.textContent?.trim() || "",
type: spans[1]?.textContent?.trim() || "",
count: spans[3]?.textContent?.trim() || "",
};
})
.filter(Boolean);
}
extractNoteData() {
const noteRows = document.querySelectorAll('#legutobbiFeljegyzesek tr:not(:first-child)');
this.dashboardData.notes = Array.from(noteRows).map(row => {
const spans = row.querySelectorAll('span');
if (spans.length < 3) return null;
const noteRows = document.querySelectorAll(
"#legutobbiFeljegyzesek tr:not(:first-child)",
);
return {
title: spans[0]?.textContent?.trim() || '',
author: spans[1]?.textContent?.trim() || '',
date: spans[2]?.textContent?.trim() || ''
};
}).filter(Boolean);
this.dashboardData.notes = Array.from(noteRows)
.map((row) => {
const spans = row.querySelectorAll("span");
if (spans.length < 3) return null;
return {
title: spans[0]?.textContent?.trim() || "",
author: spans[1]?.textContent?.trim() || "",
date: spans[2]?.textContent?.trim() || "",
};
})
.filter(Boolean);
}
extractExamData() {
const examRows = document.querySelectorAll('#legutobbiBejelentettSzamonkeres tr:not(:first-child)');
this.dashboardData.upcomingExams = Array.from(examRows).map(row => {
const spans = row.querySelectorAll('span');
if (spans.length < 4) return null;
const examRows = document.querySelectorAll(
"#legutobbiBejelentettSzamonkeres tr:not(:first-child)",
);
return {
date: spans[0]?.textContent?.trim() || '',
subject: spans[1]?.textContent?.trim() || '',
day: spans[2]?.textContent?.trim() || '',
type: spans[3]?.textContent?.trim() || ''
};
}).filter(Boolean);
this.dashboardData.upcomingExams = Array.from(examRows)
.map((row) => {
const spans = row.querySelectorAll("span");
if (spans.length < 4) return null;
return {
date: spans[0]?.textContent?.trim() || "",
subject: spans[1]?.textContent?.trim() || "",
day: spans[2]?.textContent?.trim() || "",
type: spans[3]?.textContent?.trim() || "",
};
})
.filter(Boolean);
}
async extractNewsData() {
try {
const timestamp = Date.now();
const apiUrl = `https://${window.location.hostname}/Intezmeny/Faliujsag/GetMoreEntries?startindex=0&range=10&_=${timestamp}`;
const response = await fetch(apiUrl, {
method: 'GET',
credentials: 'include',
method: "GET",
credentials: "include",
headers: {
'Accept': 'application/json, text/javascript, */*; q=0.01',
'X-Requested-With': 'XMLHttpRequest'
}
Accept: "application/json, text/javascript, */*; q=0.01",
"X-Requested-With": "XMLHttpRequest",
},
});
if (!response.ok) {
throw new Error(`API request failed with status: ${response.status}`);
}
const data = await response.json();
if (!data.FaliujsagElemek || !Array.isArray(data.FaliujsagElemek)) {
return;
}
data.FaliujsagElemek.forEach((item, index) => {
let formattedDate = '';
let formattedDate = "";
if (item.DatumNap && item.DatumHonap && item.DatumEv) {
formattedDate = `${item.DatumEv}. ${item.DatumHonap} ${item.DatumNap}.`;
} else if (item.Idopont) {
const match = item.Idopont.match(/\/Date\((\d+)\)\//);
const match = item.Idopont.match(/\/Date\((\d+)\)\//);
if (match) {
const timestamp = parseInt(match[1]);
const date = new Date(timestamp);
formattedDate = date.toLocaleDateString('hu-HU');
formattedDate = date.toLocaleDateString("hu-HU");
}
}
if (!formattedDate) {
formattedDate = new Date().toLocaleDateString('hu-HU');
formattedDate = new Date().toLocaleDateString("hu-HU");
}
let cleanContent = item.EsemenySzovege || '';
cleanContent = cleanContent.replace(/<[^>]*>/g, '');
cleanContent = cleanContent.replace(/\r\n/g, ' ');
cleanContent = cleanContent.replace(/\s+/g, ' ').trim();
let cleanContent = item.EsemenySzovege || "";
cleanContent = cleanContent.replace(/<[^>]*>/g, "");
cleanContent = cleanContent.replace(/\r\n/g, " ");
cleanContent = cleanContent.replace(/\s+/g, " ").trim();
const newsItem = {
title: item.EsemenyCime || `Hír ${index + 1}`,
content: cleanContent || 'Nincs elérhető tartalom',
content: cleanContent || "Nincs elérhető tartalom",
date: formattedDate,
author: `${item.Nev || 'Ismeretlen'} (${item.Munkakor || 'Ismeretlen'})`
author: `${item.Nev || "Ismeretlen"} (${item.Munkakor || "Ismeretlen"})`,
};
this.dashboardData.news.push(newsItem);
});
} catch (error) {
console.error('❌ Error fetching news from API:', error);
console.error("❌ Error fetching news from API:", error);
}
}
@@ -232,16 +292,23 @@ 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) || ''
name:
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,
time: document.querySelector('.usermenu_timer')?.textContent?.trim() || DEFAULT_VALUES.TIMER
}
name: await storageManager.get("userName", "Felhasználónév"),
time:
document.querySelector(".usermenu_timer")?.textContent?.trim() ||
"45:00",
},
};
this.schoolNameFull = `${this.data.schoolInfo.id} - ${this.data.schoolInfo.name}`;
this.shortenedSchoolName = helper.shortenSchoolName(this.schoolNameFull);
@@ -261,7 +328,9 @@ class DashboardRenderer {
`;
}
createNewsCard() {
const newsItems = this.data.news.map(news => `
const newsItems = this.data.news
.map(
(news) => `
<div class="widget-item news-item">
<div class="widget-row">
<div class="widget-details news-details">
@@ -269,18 +338,27 @@ class DashboardRenderer {
<div class="widget-content news-content">${news.content}</div>
</div>
<div class="widget-meta">
${news.date ? `<div class="widget-date news-date">${news.date}</div>` : ''}
${news.author ? `<div class="widget-author news-author">${news.author}</div>` : ''}
${news.date ? `<div class="widget-date news-date">${news.date}</div>` : ""}
${news.author ? `<div class="widget-author news-author">${news.author}</div>` : ""}
</div>
</div>
</div>
`).join('');
`,
)
.join("");
return this.createCard(LanguageManager.t('dashboard.news'), newsItems || LanguageManager.t('dashboard.not_supported'), '/Intezmeny/Faliujsag', LanguageManager.t('dashboard.all_news'));
return this.createCard(
LanguageManager.t("dashboard.news"),
newsItems || LanguageManager.t("dashboard.not_supported"),
"/Intezmeny/Faliujsag",
LanguageManager.t("dashboard.all_news"),
);
}
createGradeCard() {
const gradeItems = this.data.grades.map(grade => `
const gradeItems = this.data.grades
.map(
(grade) => `
<div class="widget-item grade-item">
<div class="widget-row grade-row">
<div class="grade grade-${grade.value}">${grade.value}</div>
@@ -288,62 +366,96 @@ class DashboardRenderer {
<div class="widget-title subject-name">${grade.subject}</div>
<div class="grade-type-with-date">
<div class="widget-subtitle grade-type">${grade.type}</div>
${grade.dateInSubject || grade.date ? `<div class="widget-subtitle grade-date">${grade.dateInSubject || grade.date}</div>` : ''}
${grade.dateInSubject || grade.date ? `<div class="widget-subtitle grade-date">${grade.dateInSubject || grade.date}</div>` : ""}
</div>
</div>
</div>
</div>
`).join('');
`,
)
.join("");
return this.createCard(LanguageManager.t('dashboard.grades'), gradeItems, '/TanuloErtekeles/Osztalyzatok', LanguageManager.t('dashboard.all_grades'));
return this.createCard(
LanguageManager.t("dashboard.grades"),
gradeItems,
"/TanuloErtekeles/Osztalyzatok",
LanguageManager.t("dashboard.all_grades"),
);
}
createAbsenceCard() {
const absenceItems = this.data.absences.map(absence => `
const absenceItems = this.data.absences
.map(
(absence) => `
<div class="widget-item absence-item">
<div class="widget-row">
<div class="widget-details absence-details">
<div class="widget-title absence-type">${absence.type}</div>
<div class="widget-subtitle absence-date">${absence.date}</div>
</div>
${absence.day ? `<div class="widget-date">${absence.day}</div>` : ''}
${absence.day ? `<div class="widget-date">${absence.day}</div>` : ""}
</div>
</div>
`).join('');
`,
)
.join("");
return this.createCard(LanguageManager.t('dashboard.absences'), absenceItems, '/Hianyzas/Hianyzasok', LanguageManager.t('dashboard.all_absences'));
return this.createCard(
LanguageManager.t("dashboard.absences"),
absenceItems,
"/Hianyzas/Hianyzasok",
LanguageManager.t("dashboard.all_absences"),
);
}
createNoteCard() {
const noteItems = this.data.notes.map(note => `
const noteItems = this.data.notes
.map(
(note) => `
<div class="widget-item note-item">
<div class="widget-row">
<div class="widget-details note-details">
<div class="widget-title note-title">${note.title}</div>
<div class="widget-subtitle note-date">${note.date}</div>
</div>
${note.author ? `<div class="widget-author note-author">${note.author}</div>` : ''}
${note.author ? `<div class="widget-author note-author">${note.author}</div>` : ""}
</div>
</div>
`).join('');
`,
)
.join("");
return this.createCard(LanguageManager.t('dashboard.notes'), noteItems, '/TanuloErtekeles/InformaciokFeljegyzesek', LanguageManager.t('dashboard.all_messages'));
return this.createCard(
LanguageManager.t("dashboard.notes"),
noteItems,
"/TanuloErtekeles/InformaciokFeljegyzesek",
LanguageManager.t("dashboard.all_messages"),
);
}
createExamCard() {
const examItems = this.data.upcomingExams.map(exam => `
const examItems = this.data.upcomingExams
.map(
(exam) => `
<div class="widget-item exam-item">
<div class="widget-row">
<div class="widget-details exam-details">
<div class="widget-title exam-subject">${exam.subject}</div>
<div class="widget-subtitle exam-type">${exam.type || ''}</div>
<div class="widget-subtitle exam-type">${exam.type || ""}</div>
</div>
<div class="widget-date exam-date">${DashboardUtils.formatHungarianDate(exam.date)}</div>
</div>
</div>
`).join('');
`,
)
.join("");
return this.createCard(LanguageManager.t('dashboard.exams'), examItems, '/Tanulo/TanuloBejelentettSzamonkeresek', LanguageManager.t('dashboard.all_exams'));
return this.createCard(
LanguageManager.t("dashboard.exams"),
examItems,
"/Tanulo/TanuloBejelentettSzamonkeresek",
LanguageManager.t("dashboard.all_exams"),
);
}
createCard(title, content, linkHref, linkText) {
@@ -353,7 +465,7 @@ class DashboardRenderer {
<h2 class="widget-card-title">${title}</h2>
</div>
<div class="widget-content card-content">
${content || `<div class="widget-empty">${LanguageManager.t('dashboard.not_supported')}</div>`}
${content || `<div class="widget-empty">${LanguageManager.t("dashboard.not_supported")}</div>`}
</div>
<div class="widget-footer">
<a href="${linkHref}" class="widget-link more-link">
@@ -367,13 +479,31 @@ class DashboardRenderer {
`;
}
render() {
document.body.innerHTML = `
<div class="kreta-container">
${createTemplate.header()}
${this.generateMainContent()}
</div>
`;
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(await createTemplate.header(), 'text/html');
const headerContent = headerDoc.body;
while (headerContent.firstChild) {
headerDiv.appendChild(headerContent.firstChild);
}
kretaContainer.appendChild(headerDiv);
const mainContentDiv = document.createElement('div');
const parser2 = new DOMParser();
const mainDoc = parser2.parseFromString(this.generateMainContent(), 'text/html');
const mainContent = mainDoc.body;
while (mainContent.firstChild) {
mainContentDiv.appendChild(mainContent.firstChild);
}
kretaContainer.appendChild(mainContentDiv);
document.body.appendChild(kretaContainer);
setupUserDropdown();
setupMobileNavigation();
}
@@ -385,36 +515,40 @@ class DashboardApplication {
}
async init() {
if (!window.location.href.includes('/Intezmeny/Faliujsag')) {
if (!window.location.href.includes("/Intezmeny/Faliujsag")) {
return;
}
while (typeof window.LanguageManager === 'undefined' ||
!window.LanguageManager.t('dashboard.grades') ||
window.LanguageManager.t('dashboard.grades') === 'dashboard.grades') {
await new Promise(resolve => setTimeout(resolve, 50));
while (
typeof window.LanguageManager === "undefined" ||
!window.LanguageManager.t("dashboard.grades") ||
window.LanguageManager.t("dashboard.grades") === "dashboard.grades"
) {
await new Promise((resolve) => setTimeout(resolve, 50));
}
while (!document.querySelector('.faliujsag-lista, #faliujsagLista')) {
await new Promise(resolve => setTimeout(resolve, 100));
while (!document.querySelector(".faliujsag-lista, #faliujsagLista")) {
await new Promise((resolve) => setTimeout(resolve, 100));
}
let newsItemsFound = false;
let attempts = 0;
const maxAttempts = 50;
while (!newsItemsFound && attempts < maxAttempts) {
const newsContainer = document.querySelector('.faliujsag-lista, #faliujsagLista');
const newsContainer = document.querySelector(
".faliujsag-lista, #faliujsagLista",
);
if (newsContainer) {
const possibleSelectors = [
'.nb-item',
'.news-item',
'.faliujsag-item',
'.list-group-item',
'li',
".nb-item",
".news-item",
".faliujsag-item",
".list-group-item",
"li",
'div[class*="item"]',
'div[class*="news"]'
'div[class*="news"]',
];
for (const selector of possibleSelectors) {
const items = newsContainer.querySelectorAll(selector);
if (items.length > 0) {
@@ -422,30 +556,33 @@ class DashboardApplication {
break;
}
}
if (!newsItemsFound) {
if (newsContainer.children.length > 0 || newsContainer.textContent.trim().length > 0) {
if (
newsContainer.children.length > 0 ||
newsContainer.textContent.trim().length > 0
) {
newsItemsFound = true;
}
}
}
if (!newsItemsFound) {
attempts++;
await new Promise(resolve => setTimeout(resolve, 100));
await new Promise((resolve) => setTimeout(resolve, 100));
}
}
try {
const dataManager = new DashboardDataManager();
const dashboardData = await dataManager.extractAllData();
createTemplate.importFonts();
const renderer = new DashboardRenderer(dashboardData);
renderer.render();
await renderer.render();
} catch (error) {
console.error('Error initializing dashboard:', error);
console.error("Error initializing dashboard:", error);
}
}
}
new DashboardApplication();
new DashboardApplication();

BIN
fonts/Icons.woff2 Normal file

Binary file not shown.

View File

@@ -1,292 +1,57 @@
* {
box-sizing: border-box;
margin: 0;
padding: 0;
body.maintenance-mode {
margin:0;
padding:0;
height:100vh;
display:flex;
align-items:center;
justify-content:center;
background-color:var(--background);
color:var(--text-primary);
font-family:'Figtree',sans-serif;
}
body {
margin: 0;
padding: 0;
color: var(--text-primary);
background-color: var(--background) !important;
font-family: "Montserrat", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
min-height: 100vh;
font-size: 16px;
display: flex;
align-items: center;
justify-content: center;
background-color:var(--background) !important;
}
.forgot-container {
width: 90%;
max-width: 500px;
padding: 20px;
margin: 0 auto;
.maintenance-container {
text-align:center;
padding:2rem;
border-radius:8px;
background-color:var(--card-card);
box-shadow:0 var(--shadow-blur) 6px var(--accent-shadow);
max-width:600px;
width:90%;
}
.forgot-card {
background: var(--card-card);
padding: 24px;
margin-bottom: 16px;
border-radius: 24px;
box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow);
.maintenance-logo {
width:128px;
height:128px;
margin:0 auto 2rem;
}
.forgot-header {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
margin: 16px 0;
background: var(--card-card) !important;
border-bottom: 1px solid rgba(0, 0, 0, 0) !important;
.maintenance-title {
font-size:1.5rem;
font-weight:600;
margin-bottom:1rem;
color:var(--accent-accent);
font-family:'Montserrat',sans-serif;
}
.logo-text {
color: var(--text-primary);
text-align: center;
font-family: Montserrat;
font-size: 20px;
font-style: normal;
font-weight: 700;
line-height: normal;
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
.maintenance-message {
font-size:1rem;
line-height:1.5;
margin-bottom:1.5rem;
color:var(--text-primary);
font-family:'Figtree',sans-serif;
}
.logo {
width: 48px;
height: 48px;
border-radius: 12px;
.maintenance-footer {
font-size:0.875rem;
color:var(--text-secondary);
margin-top:2rem;
font-family:'Figtree',sans-serif;
}
.forgot-title {
color: var(--text-primary);
text-align: center;
font-family: Montserrat;
font-size: 24px;
font-style: normal;
font-weight: 700;
line-height: normal;
margin-bottom: 24px;
.maintenance-cactus {
position:fixed;
bottom:0px;
right:20px;
width:120px;
height:120px;
opacity:1;
z-index:1000;
}
.forgot-form {
width: 100%;
=======
.forgot-header {
text-align: center;
margin-bottom: 24px;
}
.logo-text {
color: var(--icon);
font-size: 24px;
font-weight: 600;
margin: 16px 0;
display: flex;
align-items: center;
justify-content: center;
}
.logo {
width: 24px;
border-radius: 8px;
margin-right: 8px;
}
.forgot-card {
background: var(--card);
padding: 24px;
border-radius: 24px;
margin-bottom: 16px;
}
.forgot-title {
font-size: 18px;
font-weight: 600;
color: var(--primary);
margin-bottom: 24px;
text-align: center;
}
.form-group {
margin-bottom: 16px;
}
.form-label {
display: block;
margin-bottom: 8px;
color: var(--text-primary);
font-family: Montserrat;
font-size: 14px;
font-weight: 600;
}
.form-control {
display: flex;
height: 48px;
padding: 0px 14px;
align-items: center;
gap: 10px;
align-self: stretch;
border-radius: 12px;
background: var(--accent-15) !important;
border: 0px solid var(--accent-15) !important;
color: var(--text-primary) !important;
width: 100%;
font-size: 16px;
transition: border-color 0.2s ease;
}
.form-control:focus {
outline: none;
border-color: var(--accent-accent) !important;
}
.form-control::placeholder {
color: var(--text-secondary) !important;
}
.form-control.error {
border-color: var(--error-accent) !important;
background: var(--error-card) !important;
}
.error-message {
color: var(--error-text);
font-size: 14px;
margin-top: 4px;
display: none;
}
.error-message.show {
display: block;
animation: fadeIn 0.2s ease;
border-color: var(--accent);
}
.form-actions {
margin-top: 24px;
display: flex;
flex-direction: column;
gap: 16px;
}
.help-link {
color: var(--text-primary);
font-size: 14px;
font-weight: 500;
text-decoration: none;
transition: color 0.2s ease;
text-align: center;
}
.help-link:hover {
color: var(--text-teritary);
}
.btn-submit {
width: 100%;
padding: 12px;
background: var(--accent-accent);
color: white;
border: none;
border-radius: 12px;
font-size: 16px;
font-weight: 600;
font-family: "Montserrat", serif;
cursor: pointer;
transition: background 0.2s ease;
position: relative;
}
.btn-submit:hover {
background: var(--text-teritary);
}
.btn-submit:disabled {
opacity: 0.7;
cursor: not-allowed;
}
.message {
padding: 12px 16px;
border-radius: 12px;
margin-bottom: 16px;
font-size: 14px;
font-weight: 500;
animation: fadeIn 0.3s ease;
text-align: center;
}
.message.success {
background: var(--success-card);
color: var(--success-text);
border: 1px solid var(--success-accent);
}
.message.error {
background: var(--error-card);
color: var(--error-text);
border: 1px solid var(--error-accent);
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(-4px); }
to { opacity: 1; transform: translateY(0); }
}
@media (max-width: 480px) {
.forgot-container {
padding: 16px;
}
.forgot-card {
padding: 20px;
}
.forgot-header {
margin-bottom: 20px;
}
.logo-text {
font-size: 18px;
}
.forgot-title {
font-size: 20px;
}
.form-control {
height: 44px;
font-size: 14px;
}
.btn-submit {
padding: 10px;
font-size: 14px;
}
.help-link {
font-size: 12px;
}
}
@media (max-width: 600px) {
.forgot-container {
padding: 16px;
}
.forgot-card {
padding: 20px;
}
.form-actions {
flex-direction: column;
gap: 16px;
align-items: stretch;
}
}

View File

@@ -1,53 +1,17 @@
(() => {
const renderRecaptcha = () => {
const container = document.getElementById('recaptcha-container');
if (container && typeof grecaptcha !== 'undefined' && grecaptcha.render) {
try {
grecaptcha.render('recaptcha-container', {
'sitekey': '6LfKURIqAAAAAD5bF2evQ-_Sf6MRrOkUEBwb_mMy',
'theme': 'light'
});
} catch (error) {
console.error('Error rendering reCAPTCHA:', error);
}
}
};
// reCAPTCHA functionality removed for security compliance
const loadDependencies = async () => {
if (typeof cookieManager === 'undefined') {
const cookieScript = document.createElement('script');
cookieScript.src = chrome.runtime.getURL('tools/cookieManager.js');
document.head.appendChild(cookieScript);
await new Promise(resolve => {
cookieScript.onload = resolve;
});
}
if (typeof LanguageManager === 'undefined') {
const langScript = document.createElement('script');
langScript.src = chrome.runtime.getURL('global/language.js');
document.head.appendChild(langScript);
await new Promise(resolve => {
langScript.onload = resolve;
});
await new Promise(resolve => setTimeout(resolve, 100));
}
if (!document.querySelector('script[src*="recaptcha"]')) {
await new Promise((resolve) => {
window.onRecaptchaLoad = resolve;
const script = document.createElement('script');
script.src = 'https://www.google.com/recaptcha/api.js?hl=hu&onload=onRecaptchaLoad&render=explicit';
document.head.appendChild(script);
});
}
// reCAPTCHA functionality removed for security compliance
// Extension now works without external script dependencies
};
const createPageStructure = () => {
document.body.innerHTML = `
// Biztonságos DOM létrehozás innerHTML helyett
document.body.innerHTML = '';
// Biztonságos HTML parsing DOMParser használatával
const parser = new DOMParser();
const doc = parser.parseFromString(`
<div class="forgot-container">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
@@ -64,7 +28,7 @@
<div class="forgot-card">
<header class="forgot-header">
<p class="logo-text">
<img src="${chrome.runtime.getURL('images/firka_logo.png')}" alt="Firka" class="logo">
<img src="${chrome.runtime.getURL("images/firka_logo.png")}" alt="Firka" class="logo">
Firka
</p>
</header>
@@ -88,7 +52,7 @@
<div class="error-message" data-i18n="forgotpassword.email_required">Az e-mail cím megadása kötelező</div>
</div>
<div id="recaptcha-container"></div>
<!-- reCAPTCHA container removed for security compliance -->
<div class="form-actions">
<a href="/Adminisztracio/Login" class="help-link" data-i18n="forgotpassword.back_to_login">
@@ -101,19 +65,31 @@
</form>
</div>
</div>
`;
`, 'text/html');
const tempDiv = doc.body;
// Biztonságos DOM hozzáadás
while (tempDiv.firstChild) {
document.body.appendChild(tempDiv.firstChild);
}
};
const transformForgotPasswordPage = async () => {
await loadDependencies();
const isDarkMode = localStorage.getItem('darkMode') === 'true';
document.documentElement.setAttribute('data-theme', isDarkMode ? 'dark' : 'light');
const isDarkMode = localStorage.getItem("darkMode") === "true";
document.documentElement.setAttribute(
"data-theme",
isDarkMode ? "dark" : "light",
);
chrome.runtime.onMessage.addListener((message) => {
if (message.action === 'toggleTheme') {
document.documentElement.setAttribute('data-theme', message.darkMode ? 'dark' : 'light');
localStorage.setItem('darkMode', message.darkMode);
if (message.action === "toggleTheme") {
document.documentElement.setAttribute(
"data-theme",
message.darkMode ? "dark" : "light",
);
localStorage.setItem("darkMode", message.darkMode);
}
});
@@ -121,34 +97,34 @@
let attempts = 0;
const maxAttempts = 50;
const waitForLanguageManager = () => {
return new Promise((resolve) => {
const checkLanguageManager = () => {
attempts++;
if (typeof LanguageManager !== 'undefined' && LanguageManager.t) {
if (typeof LanguageManager !== "undefined" && LanguageManager.t) {
setTimeout(resolve, 200);
} else if (attempts < maxAttempts) {
setTimeout(checkLanguageManager, 100);
} else {
console.warn('LanguageManager not available, using fallback texts');
console.warn("LanguageManager not available, using fallback texts");
resolve();
}
};
checkLanguageManager();
});
};
await waitForLanguageManager();
if (typeof LanguageManager !== 'undefined' && LanguageManager.t) {
const elements = document.querySelectorAll('[data-i18n]');
elements.forEach(element => {
const key = element.getAttribute('data-i18n');
if (typeof LanguageManager !== "undefined" && LanguageManager.t) {
const elements = document.querySelectorAll("[data-i18n]");
elements.forEach((element) => {
const key = element.getAttribute("data-i18n");
const translation = LanguageManager.t(key);
if (translation && translation !== key) {
const attr = element.getAttribute('data-i18n-attr');
const attr = element.getAttribute("data-i18n-attr");
if (attr) {
element.setAttribute(attr, translation);
} else {
@@ -157,172 +133,158 @@
}
});
}
setTimeout(() => {
renderRecaptcha();
}, 500);
// reCAPTCHA rendering removed for security compliance
setupFormValidation();
};
const setupFormValidation = () => {
const form = document.getElementById('forgotForm');
const inputs = form.querySelectorAll('.form-control');
inputs.forEach(input => {
input.addEventListener('input', () => {
validateInput(input);
});
input.addEventListener('blur', () => {
validateInput(input, true);
});
});
form.addEventListener('submit', handleSubmit);
};
const validateInput = (input, showError = false) => {
const isValid = input.value.trim().length > 0;
const errorElement = input.nextElementSibling;
if (!isValid && showError) {
input.classList.add('error');
errorElement?.classList.add('show');
} else {
input.classList.remove('error');
errorElement?.classList.remove('show');
}
return isValid;
};
const showMessage = (message, isError = false) => {
const existingMessage = document.querySelector('.message');
if (existingMessage) {
existingMessage.remove();
}
const messageDiv = document.createElement('div');
messageDiv.className = `message ${isError ? 'error' : 'success'}`;
messageDiv.textContent = message;
const form = document.getElementById('forgotForm');
form.insertBefore(messageDiv, form.firstChild);
const setupFormValidation = () => {
const form = document.getElementById("forgotForm");
const inputs = form.querySelectorAll(".form-control");
setTimeout(() => {
if (messageDiv.parentNode) {
messageDiv.remove();
}
}, 5000);
};
const validateEmail = (email) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
};
const handleSubmit = async (event) => {
event.preventDefault();
const form = event.target;
const inputs = form.querySelectorAll('.form-control[required]');
let isValid = true;
inputs.forEach(input => {
if (!validateInput(input, true)) {
isValid = false;
}
inputs.forEach((input) => {
input.addEventListener("input", () => {
validateInput(input);
});
const emailInput = form.querySelector('#EmailCim');
if (emailInput.value && !validateEmail(emailInput.value)) {
emailInput.classList.add('error');
const errorElement = emailInput.nextElementSibling;
if (errorElement) {
errorElement.textContent = LanguageManager.t('forgotpassword.invalid_email');
errorElement.classList.add('show');
}
input.addEventListener("blur", () => {
validateInput(input, true);
});
});
form.addEventListener("submit", handleSubmit);
};
const validateInput = (input, showError = false) => {
const isValid = input.value.trim().length > 0;
const errorElement = input.nextElementSibling;
if (!isValid && showError) {
input.classList.add("error");
errorElement?.classList.add("show");
} else {
input.classList.remove("error");
errorElement?.classList.remove("show");
}
return isValid;
};
const showMessage = (message, isError = false) => {
const existingMessage = document.querySelector(".message");
if (existingMessage) {
existingMessage.remove();
}
const messageDiv = document.createElement("div");
messageDiv.className = `message ${isError ? "error" : "success"}`;
messageDiv.textContent = message;
const form = document.getElementById("forgotForm");
form.insertBefore(messageDiv, form.firstChild);
setTimeout(() => {
if (messageDiv.parentNode) {
messageDiv.remove();
}
}, 5000);
};
const validateEmail = (email) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
};
const handleSubmit = async (event) => {
event.preventDefault();
const form = event.target;
const inputs = form.querySelectorAll(".form-control[required]");
let isValid = true;
inputs.forEach((input) => {
if (!validateInput(input, true)) {
isValid = false;
}
});
let recaptchaResponse = '';
if (typeof grecaptcha !== 'undefined') {
recaptchaResponse = grecaptcha.getResponse();
if (!recaptchaResponse) {
showMessage(LanguageManager.t('forgotpassword.recaptcha_required'), true);
isValid = false;
}
} else {
showMessage('reCAPTCHA nem töltődött be. Kérjük, frissítse az oldalt!', true);
isValid = false;
const emailInput = form.querySelector("#EmailCim");
if (emailInput.value && !validateEmail(emailInput.value)) {
emailInput.classList.add("error");
const errorElement = emailInput.nextElementSibling;
if (errorElement) {
errorElement.textContent = LanguageManager.t(
"forgotpassword.invalid_email",
);
errorElement.classList.add("show");
}
isValid = false;
}
if (!isValid) {
return;
}
// reCAPTCHA validation removed for security compliance
const submitButton = form.querySelector('.btn-submit');
const originalText = submitButton.textContent;
submitButton.disabled = true;
submitButton.textContent = LanguageManager.t('loading.text') || 'Küldés...';
if (!isValid) {
return;
}
try {
const formData = new FormData(form);
const submitButton = form.querySelector(".btn-submit");
const originalText = submitButton.textContent;
submitButton.disabled = true;
submitButton.textContent = LanguageManager.t("loading.text") || "Küldés...";
if (typeof grecaptcha !== 'undefined') {
formData.append('ReCaptcha', grecaptcha.getResponse());
}
const response = await fetch('/Adminisztracio/ElfelejtettJelszo/LinkKuldes', {
method: 'POST',
try {
const formData = new FormData(form);
// reCAPTCHA data removed for security compliance
const response = await fetch(
"/Adminisztracio/ElfelejtettJelszo/LinkKuldes",
{
method: "POST",
body: formData,
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
});
"X-Requested-With": "XMLHttpRequest",
},
},
);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
if (result.Success) {
showMessage(LanguageManager.t('forgotpassword.success_message'));
form.reset();
if (typeof grecaptcha !== 'undefined') {
grecaptcha.reset();
}
setTimeout(() => {
window.location.href = '/Adminisztracio/Login';
}, 3000);
} else {
showMessage(result.Message || LanguageManager.t('forgotpassword.error_message'), true);
if (typeof grecaptcha !== 'undefined') {
grecaptcha.reset();
}
}
} catch (error) {
console.error('Password reset error:', error);
showMessage(LanguageManager.t('forgotpassword.error_message'), true);
if (typeof grecaptcha !== 'undefined') {
grecaptcha.reset();
}
} finally {
submitButton.disabled = false;
submitButton.textContent = originalText;
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
};
if (window.location.href.includes('/Adminisztracio/ElfelejtettJelszo')) {
transformForgotPasswordPage().catch(console.error);
const result = await response.json();
if (result.Success) {
showMessage(LanguageManager.t("forgotpassword.success_message"));
form.reset();
// reCAPTCHA reset removed
setTimeout(() => {
window.location.href = "/Adminisztracio/Login";
}, 3000);
} else {
showMessage(
result.Message || LanguageManager.t("forgotpassword.error_message"),
true,
);
// reCAPTCHA reset removed
}
} catch (error) {
console.error("Password reset error:", error);
showMessage(LanguageManager.t("forgotpassword.error_message"), true);
// reCAPTCHA reset removed
} finally {
submitButton.disabled = false;
submitButton.textContent = originalText;
}
})();
};
if (window.location.href.includes("/Adminisztracio/ElfelejtettJelszo")) {
transformForgotPasswordPage().catch(console.error);
}
})();

View File

@@ -1,131 +1,189 @@
(function() {
let currentLanguage = 'hu';
let translations = {};
async function setLanguage(language) {
(function () {
let currentLanguage = "hu";
let translations = {};
async function setLanguage(language) {
try {
currentLanguage = language;
await storageManager.set("languagePreference", language);
localStorage.setItem("languagePreference", language);
await loadTranslations(language);
applyTranslations();
window.dispatchEvent(
new CustomEvent("languageChanged", {
detail: { language: language },
}),
);
chrome.runtime
.sendMessage({
action: "languageChanged",
language: language,
})
.catch(() => {});
} catch (error) {}
}
async function loadTranslations(language) {
try {
const url = chrome.runtime.getURL(`i18n/${language}.json`);
const response = await fetch(url);
if (!response.ok) {
throw new Error(
`Failed to load ${language}.json - Status: ${response.status}`,
);
}
translations = await response.json();
} catch (error) {
if (language !== "hu") {
try {
currentLanguage = language;
cookieManager.set('languagePreference', language);
localStorage.setItem('languagePreference', language);
await loadTranslations(language);
applyTranslations();
window.dispatchEvent(new CustomEvent('languageChanged', {
detail: { language: language }
}));
chrome.runtime.sendMessage({
action: 'languageChanged',
language: language
}).catch(() => {});
} catch (error) {}
const fallbackUrl = chrome.runtime.getURL("i18n/hu.json");
const response = await fetch(fallbackUrl);
translations = await response.json();
} catch (fallbackError) {}
}
}
async function loadTranslations(language) {
try {
const url = chrome.runtime.getURL(`i18n/${language}.json`);
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Failed to load ${language}.json - Status: ${response.status}`);
}
translations = await response.json();
} catch (error) {
if (language !== 'hu') {
try {
const fallbackUrl = chrome.runtime.getURL('i18n/hu.json');
const response = await fetch(fallbackUrl);
translations = await response.json();
} catch (fallbackError) {}
}
}
function applyTranslations() {
const elements = document.querySelectorAll("[data-i18n]");
elements.forEach((element) => {
const key = element.getAttribute("data-i18n");
const translation = getTranslation(key);
if (translation && translation !== key) {
const attr = element.getAttribute("data-i18n-attr");
if (attr) {
element.setAttribute(attr, translation);
} else {
element.textContent = translation;
}
}
function applyTranslations() {
const elements = document.querySelectorAll('[data-i18n]');
elements.forEach(element => {
const key = element.getAttribute('data-i18n');
const translation = getTranslation(key);
if (translation && translation !== key) {
const attr = element.getAttribute('data-i18n-attr');
if (attr) {
element.setAttribute(attr, translation);
} else {
element.textContent = translation;
}
}
});
}
function getTranslation(keyPath, fallback = '') {
const keys = keyPath.split('.');
let value = translations;
for (const key of keys) {
if (value && typeof value === 'object' && key in value) {
value = value[key];
} else {
return fallback || keyPath;
}
}
return typeof value === 'string' ? value : fallback || keyPath;
}
async function initializeLanguage() {
const cookieLanguage = cookieManager.get('languagePreference');
const localStorageLanguage = localStorage.getItem('languagePreference');
const language = cookieLanguage || localStorageLanguage || 'hu';
await setLanguage(language);
if (cookieLanguage !== localStorageLanguage) {
if (cookieLanguage) {
localStorage.setItem('languagePreference', cookieLanguage);
} else if (localStorageLanguage) {
cookieManager.set('languagePreference', localStorageLanguage);
}
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initializeLanguage);
} else {
initializeLanguage();
}
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === 'changeLanguage') {
setLanguage(message.language);
sendResponse({ success: true });
}
if (message.action === 'getLanguage') {
sendResponse({ language: currentLanguage });
}
return true;
}
});
}
window.LanguageManager = {
getCurrentLanguage: () => currentLanguage,
changeLanguage: setLanguage,
t: getTranslation,
getAvailableLanguages: () => [
{ code: 'hu', name: 'Magyar' },
{ code: 'en', name: 'English' }
]
};
})();
function getTranslation(keyPath, fallback = "") {
const keys = keyPath.split(".");
let value = translations;
for (const key of keys) {
if (value && typeof value === "object" && key in value) {
value = value[key];
} else {
return fallback || keyPath;
}
}
return typeof value === "string" ? value : fallback || keyPath;
}
async function initializeLanguage() {
try {
const storageLanguage = await storageManager.get("languagePreference");
const localStorageLanguage = localStorage.getItem("languagePreference");
const language = storageLanguage || localStorageLanguage || "hu";
await setLanguage(language);
loadTranslationsForPage();
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();
}
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initializeLanguage);
} else {
initializeLanguage();
}
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === "changeLanguage") {
setLanguage(message.language);
sendResponse({ success: true });
}
if (message.action === "getLanguage") {
sendResponse({ language: currentLanguage });
}
return true;
});
function loadTranslationsForPage() {
try {
applyTranslations();
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach((node) => {
if (node.nodeType === Node.ELEMENT_NODE) {
const elementsWithI18n = node.querySelectorAll ? node.querySelectorAll('[data-i18n]') : [];
elementsWithI18n.forEach((element) => {
const key = element.getAttribute('data-i18n');
const translation = getTranslation(key);
if (translation && translation !== key) {
const attr = element.getAttribute('data-i18n-attr');
if (attr) {
element.setAttribute(attr, translation);
} else {
element.textContent = translation;
}
}
});
if (node.hasAttribute && node.hasAttribute('data-i18n')) {
const key = node.getAttribute('data-i18n');
const translation = getTranslation(key);
if (translation && translation !== key) {
const attr = node.getAttribute('data-i18n-attr');
if (attr) {
node.setAttribute(attr, translation);
} else {
node.textContent = translation;
}
}
}
}
});
}
});
});
observer.observe(document.body, {
childList: true,
subtree: true
});
} catch (error) {
console.error('Error loading translations for page:', error);
}
}
window.LanguageManager = {
getCurrentLanguage: () => currentLanguage,
changeLanguage: setLanguage,
t: getTranslation,
loadTranslationsForPage: loadTranslationsForPage,
getAvailableLanguages: () => [
{ code: "hu", name: "Magyar" },
{ code: "en", name: "English" },
],
};
})();

View File

@@ -1,89 +1,57 @@
@font-face {
font-family: 'Montserrat';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Montserrat-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'Montserrat';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Montserrat-Medium.woff2') format('woff2');
font-weight: 500;
font-style: normal;
}
@font-face {
font-family: 'Montserrat';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Montserrat-SemiBold.woff2') format('woff2');
font-weight: 600;
font-style: normal;
}
@font-face {
font-family: 'Figtree';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Figtree-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
}
body.maintenance-mode {
margin: 0;
padding: 0;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background-color: var(--background);
color: var(--text-primary);
font-family: 'Figtree', sans-serif;
margin:0;
padding:0;
height:100vh;
display:flex;
align-items:center;
justify-content:center;
background-color:var(--background);
color:var(--text-primary);
font-family:'Figtree',sans-serif;
}
body {
background-color: var(--background) !important;
background-color:var(--background) !important;
}
.maintenance-container {
text-align: center;
padding: 2rem;
border-radius: 8px;
background-color: var(--card-card);
box-shadow: 0 var(--shadow-blur) 6px var(--accent-shadow);
max-width: 600px;
width: 90%;
text-align:center;
padding:2rem;
border-radius:8px;
background-color:var(--card-card);
box-shadow:0 var(--shadow-blur) 6px var(--accent-shadow);
max-width:600px;
width:90%;
}
.maintenance-logo {
width: 128px;
height: 128px;
margin: 0 auto 2rem;
width:128px;
height:128px;
margin:0 auto 2rem;
}
.maintenance-title {
font-size: 1.5rem;
font-weight: 600;
margin-bottom: 1rem;
color: var(--accent-accent);
font-family: 'Montserrat', sans-serif;
font-size:1.5rem;
font-weight:600;
margin-bottom:1rem;
color:var(--accent-accent);
font-family:'Montserrat',sans-serif;
}
.maintenance-message {
font-size: 1rem;
line-height: 1.5;
margin-bottom: 1.5rem;
color: var(--text-primary);
font-family: 'Figtree', sans-serif;
font-size:1rem;
line-height:1.5;
margin-bottom:1.5rem;
color:var(--text-primary);
font-family:'Figtree',sans-serif;
}
.maintenance-footer {
font-size: 0.875rem;
color: var(--text-secondary);
margin-top: 2rem;
font-family: 'Figtree', sans-serif;
font-size:0.875rem;
color:var(--text-secondary);
margin-top:2rem;
font-family:'Figtree',sans-serif;
}
.maintenance-cactus {
position: fixed;
bottom: 0px;
right: 20px;
width: 120px;
height: 120px;
opacity: 1;
z-index: 1000;
}
position:fixed;
bottom:0px;
right:20px;
width:120px;
height:120px;
opacity:1;
z-index:1000;
}

View File

@@ -1,99 +1,106 @@
function loadMaintenanceCSS() {
const maintenanceCSS = document.createElement('link');
maintenanceCSS.rel = 'stylesheet';
maintenanceCSS.href = chrome.runtime.getURL('global/maintenance.css');
document.head.appendChild(maintenanceCSS);
const maintenanceCSS = document.createElement("link");
maintenanceCSS.rel = "stylesheet";
maintenanceCSS.href = chrome.runtime.getURL("global/maintenance.css");
document.head.appendChild(maintenanceCSS);
}
function checkMaintenancePage() {
const maintenanceContent = document.querySelector('.login_content');
const bodyText = document.body ? document.body.textContent : '';
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 &&
(maintenanceContent.textContent.includes('frissítés alatt') ||
maintenanceContent.textContent.includes('under maintenance'));
if (hasSpecificMessage || hasGeneralMaintenance) {
const body = document.body;
const mainLogo = chrome.runtime.getURL('images/firka_logo_128.png');
const cactusImage = chrome.runtime.getURL('images/cactus.png');
const hasGeneralMaintenance =
maintenanceContent &&
(maintenanceContent.textContent.includes("frissítés alatt") ||
maintenanceContent.textContent.includes("under maintenance"));
const removeLoadingElements = () => {
const loadingScreen = document.querySelector('.loading-screen');
if (loadingScreen) loadingScreen.remove();
const kretaProgressBar = document.querySelector('#KretaProgressBar');
if (kretaProgressBar) kretaProgressBar.remove();
const modalBackground = document.querySelector('.modalBckgroundMain');
if (modalBackground) modalBackground.remove();
if (hasSpecificMessage || hasGeneralMaintenance) {
const body = document.body;
const mainLogo = chrome.runtime.getURL("images/firka_logo_128.png");
const cactusImage = chrome.runtime.getURL("images/cactus.png");
const overlays = document.querySelectorAll('.modalBckgroundMain, .loading-screen, #KretaProgressBar');
overlays.forEach(overlay => overlay.remove());
};
removeLoadingElements();
setTimeout(removeLoadingElements, 100);
const removeLoadingElements = () => {
const loadingScreen = document.querySelector(".loading-screen");
if (loadingScreen) loadingScreen.remove();
const existingStyles = document.querySelectorAll('link[rel="stylesheet"], style');
existingStyles.forEach(style => style.remove());
const kretaProgressBar = document.querySelector("#KretaProgressBar");
if (kretaProgressBar) kretaProgressBar.remove();
body.innerHTML = '';
body.classList.add('maintenance-mode');
body.classList.add('theme-enabled');
body.classList.add('loaded');
loadMaintenanceCSS();
const container = document.createElement('div');
container.className = 'maintenance-container';
const logo = document.createElement('img');
logo.src = mainLogo;
logo.alt = 'Firka Logo';
logo.className = 'maintenance-logo';
const title = document.createElement('h1');
title.className = 'maintenance-title';
title.textContent = window.LanguageManager ? window.LanguageManager.t('maintenance.title') : 'Karbantartás';
const messageDiv = document.createElement('div');
messageDiv.className = 'maintenance-message';
const paragraph1 = document.createElement('p');
paragraph1.textContent = window.LanguageManager ? window.LanguageManager.t('maintenance.message1') : 'A KRÉTA rendszer jelenleg frissítés alatt van, hamarosan újra elérhetővé válik.';
const paragraph2 = document.createElement('p');
paragraph2.textContent = window.LanguageManager ? window.LanguageManager.t('maintenance.message2') : 'Köszönjük türelmüket és megértésüket!';
const footer = document.createElement('div');
footer.className = 'maintenance-footer';
footer.textContent = window.LanguageManager ? window.LanguageManager.t('maintenance.team') : 'KRÉTA Csapat';
const modalBackground = document.querySelector(".modalBckgroundMain");
if (modalBackground) modalBackground.remove();
const cactus = document.createElement('img');
cactus.src = cactusImage;
cactus.alt = 'Cactus';
cactus.className = 'maintenance-cactus';
messageDiv.appendChild(paragraph1);
messageDiv.appendChild(paragraph2);
container.appendChild(logo);
container.appendChild(title);
container.appendChild(messageDiv);
container.appendChild(footer);
body.appendChild(container);
body.appendChild(cactus);
}
const overlays = document.querySelectorAll(
".modalBckgroundMain, .loading-screen, #KretaProgressBar",
);
overlays.forEach((overlay) => overlay.remove());
};
removeLoadingElements();
setTimeout(removeLoadingElements, 100);
const existingStyles = document.querySelectorAll(
'link[rel="stylesheet"], style',
);
existingStyles.forEach((style) => style.remove());
body.innerHTML = "";
body.classList.add("maintenance-mode");
body.classList.add("theme-enabled");
body.classList.add("loaded");
loadMaintenanceCSS();
const container = document.createElement("div");
container.className = "maintenance-container";
const logo = document.createElement("img");
logo.src = mainLogo;
logo.alt = "Firka Logo";
logo.className = "maintenance-logo";
const title = document.createElement("h1");
title.className = "maintenance-title";
title.textContent = window.LanguageManager
? window.LanguageManager.t("maintenance.title")
: "Karbantartás";
const messageDiv = document.createElement("div");
messageDiv.className = "maintenance-message";
const paragraph1 = document.createElement("p");
paragraph1.textContent = window.LanguageManager
? window.LanguageManager.t("maintenance.message1")
: "A KRÉTA rendszer jelenleg frissítés alatt van, hamarosan újra elérhetővé válik.";
const paragraph2 = document.createElement("p");
paragraph2.textContent = window.LanguageManager
? window.LanguageManager.t("maintenance.message2")
: "Köszönjük türelmüket és megértésüket!";
const footer = document.createElement("div");
footer.className = "maintenance-footer";
footer.textContent = window.LanguageManager
? window.LanguageManager.t("maintenance.team")
: "KRÉTA Csapat";
const cactus = document.createElement("img");
cactus.src = cactusImage;
cactus.alt = "Cactus";
cactus.className = "maintenance-cactus";
messageDiv.appendChild(paragraph1);
messageDiv.appendChild(paragraph2);
container.appendChild(logo);
container.appendChild(title);
container.appendChild(messageDiv);
container.appendChild(footer);
body.appendChild(container);
body.appendChild(cactus);
}
}
document.addEventListener('DOMContentLoaded', checkMaintenancePage);
document.addEventListener("DOMContentLoaded", checkMaintenancePage);

View File

@@ -1,401 +1,332 @@
.kreta-header {
padding: clamp(1rem, 3vw, 2rem);
display: grid;
grid-template-columns: minmax(300px, 400px) 1fr minmax(200px, 300px);
align-items: center;
gap: 1rem;
background-color: var(--background);
padding:clamp(1rem,3vw,2rem);
display:grid;
grid-template-columns:minmax(300px,400px) 1fr minmax(200px,300px);
align-items:center;
gap:1rem;
background-color:var(--background);
}
.school-info {
margin: 0;
display: flex;
flex-direction: column;
margin:0;
display:flex;
flex-direction:column;
}
.logo-text {
color: var(--text-primary);
font-size: 24px;
font-weight: 600;
margin: 0 0 0.5rem;
display: flex;
align-items: center;
color:var(--text-primary);
font-size:24px;
font-weight:600;
margin:0 0 0.5rem;
display:flex;
align-items:center;
}
.logo {
width: 24px;
height: 24px;
border-radius: 8px;
margin-right: 0.5rem;
width:24px;
height:24px;
border-radius:8px;
margin-right:0.5rem;
}
.school-details {
color: var(--text-secondary);
font-size: 14px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color:var(--text-secondary);
font-size:14px;
white-space:nowrap;
overflow:hidden;
text-overflow:ellipsis;
}
.kreta-nav {
padding: 0 clamp(0.5rem, 3vw, 1.5rem);
position: sticky;
top: 0;
z-index: 100;
display: flex;
justify-content: center;
padding:0 clamp(0.5rem,3vw,1.5rem);
position:sticky;
top:0;
z-index:100;
display:flex;
justify-content:center;
}
.nav-links {
display: flex;
gap: clamp(0.5rem, 2vw, 1rem);
padding: 0.25rem;
align-items: center;
display:flex;
gap:clamp(0.5rem,2vw,1rem);
padding:0.25rem;
align-items:center;
}
.nav-item {
display: flex;
align-items: center;
padding: clamp(0.5rem, 1.5vw, 1rem) 0.5rem;
color: var(--text-secondary);
text-decoration: none;
font-weight: 500;
white-space: nowrap;
border-radius: 8px;
transition: all 0.2s ease;
gap: 0.5rem;
text-decoration: none;
display:flex;
align-items:center;
padding:clamp(0.5rem,1.5vw,1rem) 0.5rem;
color:var(--text-secondary);
text-decoration:none;
font-weight:500;
white-space:nowrap;
border-radius:8px;
transition:all 0.2s ease;
gap:0.5rem;
text-decoration:none;
}
.nav-item.active {
display: flex;
padding: 8px 14px 8px 12px;
align-items: center;
gap: 8px;
border-radius: 20px;
background: var(--button-secondaryFill);
box-shadow: 0px 1px var(--shadow-blur, 2px) 0px var(--accent-shadow);
display:flex;
padding:8px 14px 8px 12px;
align-items:center;
gap:8px;
border-radius:20px;
background:var(--button-secondaryFill);
box-shadow:0px 1px var(--shadow-blur,2px) 0px var(--accent-shadow);
}
.nav-item:hover {
color: var(--text-primary);
background-color: var(--hover);
border-radius: 8px;
text-decoration: none;
color:var(--text-primary);
background-color:var(--hover);
border-radius:8px;
text-decoration:none;
}
.nav-item.active:hover {
color: var(--accent-accent);
background-color: var(--accent-hover);
text-decoration: none;
color:var(--accent-accent);
background-color:var(--accent-hover);
text-decoration:none;
}
.nav-item img,
.nav-item svg {
width: 24px;
height: 24px;
.nav-item img,.nav-item svg {
width:24px;
height:24px;
}
.nav-item.active svg path {
fill: var(--accent-accent);
fill:var(--accent-accent);
}
.user-profile {
position: relative;
justify-self: flex-end;
position:relative;
justify-self:flex-end;
}
.user-dropdown-btn {
display: flex;
align-items: center;
gap: 1rem;
background: none;
border: none;
cursor: pointer;
padding: 0.5rem;
border-radius: 8px;
transition: background-color 0.2s;
display:flex;
align-items:center;
gap:1rem;
background:none;
border:none;
cursor:pointer;
padding:0.5rem;
border-radius:8px;
transition:background-color 0.2s;
}
.user-dropdown-btn:hover {
background: var(--hover);
background:var(--hover);
}
.user-info {
text-align: right;
text-align:right;
}
.user-name {
display: block;
color: var(--text-primary);
font-size: 16px;
display:block;
color:var(--text-primary);
font-size:16px;
}
.nav-logout-timer {
display: block;
color: var(--text-secondary);
font-size: 14px;
display:block;
color:var(--text-secondary);
font-size:14px;
}
.user-dropdown {
position: absolute;
top: 100%;
right: 0;
margin-top: 0.5rem;
background: var(--card-card);
border-radius: 12px;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
width: 200px;
display: none;
z-index: 1000;
position:absolute;
top:100%;
right:0;
margin-top:0.5rem;
background:var(--card-card);
border-radius:12px;
box-shadow:0 4px 6px -1px rgba(0,0,0,0.1);
width:200px;
display:none;
z-index:1000;
}
.user-dropdown.show {
display: block;
animation: dropdownShow 0.2s ease;
display:block;
animation:dropdownShow 0.2s ease;
}
.dropdown-item {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.75rem 1rem;
color: var(--text-primary);
text-decoration: none;
transition: background-color 0.2s;
display:flex;
align-items:center;
gap:0.75rem;
padding:0.75rem 1rem;
color:var(--text-primary);
text-decoration:none;
transition:background-color 0.2s;
}
.dropdown-item:hover {
background: var(--hover);
color: var(--accent-accent);
border-radius: 8px;
background:var(--hover);
color:var(--accent-accent);
border-radius:8px;
text-decoration:none;
}
@keyframes dropdownShow {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
opacity:0;
transform:translateY(-10px);
}
@media (max-width: 1200px) {
to {
opacity:1;
transform:translateY(0);
}
}@media (max-width:1200px) {
.kreta-header {
grid-template-columns: minmax(250px, 350px) 1fr minmax(180px, 250px);
}
grid-template-columns:minmax(250px,350px) 1fr minmax(180px,250px);
}
/* Hamburger menu styles */
}/* Hamburger menu styles */
.nav-toggle {
display: none;
background: none;
border: none;
cursor: pointer;
padding: 0.5rem;
border-radius: 8px;
transition: background-color 0.2s;
display:none;
background:none;
border:none;
cursor:pointer;
padding:0.5rem;
border-radius:8px;
transition:background-color 0.2s;
}
.nav-toggle:hover {
background: var(--hover);
background:var(--hover);
}
.nav-toggle svg {
width: 24px;
height: 24px;
fill: var(--text-primary);
width:24px;
height:24px;
fill:var(--text-primary);
}
@media (max-width: 768px) {
@media (max-width:768px) {
.kreta-header {
grid-template-columns: 1fr auto auto;
grid-template-areas:
"school toggle user"
grid-template-columns:1fr auto auto;
grid-template-areas:"school toggle user"
"nav nav nav";
padding: 1rem;
gap: 0.5rem;
}
.nav-toggle {
display: block;
grid-area: toggle;
}
.school-info {
grid-area: school;
max-width: none;
display: flex;
align-items: center;
gap: 0.5rem;
}
.logo-text {
margin: 0;
font-size: 18px;
}
.school-details {
font-size: 11px;
max-width: 200px;
}
.kreta-nav {
grid-area: nav;
padding: 0;
margin-top: 0.5rem;
display: none;
}
.kreta-nav.show {
display: flex;
animation: slideDown 0.3s ease;
}
.kreta-nav::-webkit-scrollbar {
display: none;
}
.nav-links {
flex-direction: column;
width: 100%;
gap: 0.5rem;
background: var(--card-card);
border-radius: 12px;
padding: 1rem;
box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow);
}
.nav-item {
width: 100%;
justify-content: flex-start;
padding: 0.75rem;
font-size: 14px;
}
.user-profile {
grid-area: user;
}
.user-info {
text-align: right;
max-width: 120px;
}
.user-name {
font-size: 13px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.nav-logout-timer {
font-size: 11px;
}
padding:1rem;
gap:0.5rem;
}
@media (max-width: 480px) {
.nav-toggle {
display:block;
grid-area:toggle;
}
.school-info {
grid-area:school;
max-width:none;
display:flex;
align-items:center;
gap:0.5rem;
}
.logo-text {
margin:0;
font-size:18px;
}
.school-details {
font-size:11px;
max-width:200px;
}
.kreta-nav {
grid-area:nav;
padding:0;
margin-top:0.5rem;
display:none;
}
.kreta-nav.show {
display:flex;
animation:slideDown 0.3s ease;
}
.kreta-nav::-webkit-scrollbar {
display:none;
}
.nav-links {
flex-direction:column;
width:100%;
gap:0.5rem;
background:var(--card-card);
border-radius:12px;
padding:1rem;
box-shadow:0px 1px var(--shadow-blur) 0px var(--accent-shadow);
}
.nav-item {
width:100%;
justify-content:flex-start;
padding:0.75rem;
font-size:14px;
}
.user-profile {
grid-area:user;
}
.user-info {
text-align:right;
max-width:120px;
}
.user-name {
font-size:13px;
white-space:nowrap;
overflow:hidden;
text-overflow:ellipsis;
}
.nav-logout-timer {
font-size:11px;
}
}@media (max-width:480px) {
.kreta-header {
grid-template-columns: 1fr auto auto;
grid-template-areas:
"school toggle user"
grid-template-columns:1fr auto auto;
grid-template-areas:"school toggle user"
"nav nav nav";
padding: 0.75rem;
gap: 0.25rem;
}
.school-info {
min-width: 0;
flex: 1;
}
.logo-text {
font-size: 16px;
}
.school-details {
font-size: 10px;
max-width: 150px;
}
.kreta-nav {
display: none;
}
.kreta-nav.show {
display: flex;
animation: slideDown 0.3s ease;
}
.nav-links {
flex-direction: column;
width: 100%;
gap: 0.5rem;
background: var(--card-card);
border-radius: 12px;
padding: 1rem;
box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow);
}
.nav-item {
width: 100%;
justify-content: flex-start;
padding: 0.75rem;
font-size: 14px;
}
.user-info {
max-width: 100px;
}
.user-name {
font-size: 12px;
}
.nav-logout-timer {
font-size: 10px;
}
padding:0.75rem;
gap:0.25rem;
}
@media (max-width: 360px) {
.kreta-header {
padding: 0.5rem;
}
.logo-text {
font-size: 14px;
}
.school-details {
font-size: 9px;
max-width: 120px;
}
.user-info {
max-width: 80px;
}
.user-name {
font-size: 11px;
}
.nav-logout-timer {
font-size: 9px;
}
.school-info {
min-width:0;
flex:1;
}
@keyframes slideDown {
.logo-text {
font-size:16px;
}
.school-details {
font-size:10px;
max-width:150px;
}
.kreta-nav {
display:none;
}
.kreta-nav.show {
display:flex;
animation:slideDown 0.3s ease;
}
.nav-links {
flex-direction:column;
width:100%;
gap:0.5rem;
background:var(--card-card);
border-radius:12px;
padding:1rem;
box-shadow:0px 1px var(--shadow-blur) 0px var(--accent-shadow);
}
.nav-item {
width:100%;
justify-content:flex-start;
padding:0.75rem;
font-size:14px;
}
.user-info {
max-width:100px;
}
.user-name {
font-size:12px;
}
.nav-logout-timer {
font-size:10px;
}
}@media (max-width:360px) {
.kreta-header {
padding:0.5rem;
}
.logo-text {
font-size:14px;
}
.school-details {
font-size:9px;
max-width:120px;
}
.user-info {
max-width:80px;
}
.user-name {
font-size:11px;
}
.nav-logout-timer {
font-size:9px;
}
}@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
opacity:0;
transform:translateY(-10px);
}
to {
opacity:1;
transform:translateY(0);
}
}

View File

@@ -1,122 +1,177 @@
const COOKIE_KEYS = {
SCHOOL_NAME: 'schoolName',
SCHOOL_CODE: 'schoolCode',
USER_NAME: 'userName',
SCHOOL_SUBDOMAIN: 'schoolSubdomain'
SCHOOL_NAME: "schoolName",
SCHOOL_CODE: "schoolCode",
USER_NAME: "userName",
SCHOOL_SUBDOMAIN: "schoolSubdomain",
};
const DEFAULT_VALUES = {
SCHOOL: LanguageManager.t('navigation.school_default'),
USER: LanguageManager.t('navigation.user_default'),
TIMER: '45:00'
SCHOOL: LanguageManager.t("navigation.school_default"),
USER: LanguageManager.t("navigation.user_default"),
TIMER: "45:00",
};
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,
time: document.querySelector('.usermenu_timer')?.textContent?.trim() || DEFAULT_VALUES.TIMER
};
if (schoolName) {
schoolName.textContent = `${userData.schoolId} - ${userData.schoolName}`;
}
if (userName) {
userName.textContent = userData.name;
}
if (logoutTimer) {
startLogoutTimer(userData.time);
}
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:
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,
};
if (schoolName) {
schoolName.textContent = `${userData.schoolId} - ${userData.schoolName}`;
}
if (userName) {
userName.textContent = userData.name;
}
if (logoutTimer) {
startLogoutTimer(userData.time);
}
}
function startLogoutTimer(timeString) {
const startTime = parseInt(timeString?.match(/\d+/)?.[0] || "45");
let timeLeft = startTime * 60;
const timerElement = document.querySelector('.nav-logout-timer');
const updateTimer = () => {
const minutes = Math.floor(timeLeft / 60);
const seconds = timeLeft % 60;
timerElement.textContent = `${minutes}:${seconds.toString().padStart(2, '0')}`;
if (timeLeft <= 0) {
window.location.href = '/Home/Logout';
}
timeLeft--;
};
const startTime = parseInt(timeString?.match(/\d+/)?.[0] || "45");
let timeLeft = startTime * 60;
const timerElement = document.querySelector(".nav-logout-timer");
updateTimer();
setInterval(updateTimer, 1000);
const updateTimer = () => {
const minutes = Math.floor(timeLeft / 60);
const seconds = timeLeft % 60;
timerElement.textContent = `${minutes}:${seconds.toString().padStart(2, "0")}`;
if (timeLeft <= 0) {
window.location.href = "/Home/Logout";
}
timeLeft--;
};
updateTimer();
setInterval(updateTimer, 1000);
}
document.addEventListener('DOMContentLoaded', () => {
updateHeaderInfo();
document.addEventListener("DOMContentLoaded", async () => {
await updateHeaderInfo();
});
function setupUserDropdown() {
const userBtn = document.querySelector('.user-dropdown-btn');
const userDropdown = document.querySelector('.user-dropdown');
userBtn?.addEventListener('click', (e) => {
e.stopPropagation();
userDropdown?.classList.toggle('show');
});
const userBtn = document.querySelector(".user-dropdown-btn");
const userDropdown = document.querySelector(".user-dropdown");
document.addEventListener('click', () => {
userDropdown?.classList.remove('show');
});
userBtn?.addEventListener("click", (e) => {
e.stopPropagation();
userDropdown?.classList.toggle("show");
});
document.addEventListener("click", () => {
userDropdown?.classList.remove("show");
});
}
function setupSettingsButton() {
document.getElementById('settingsBtn')?.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
const url = chrome.runtime.getURL('settings/index.html');
window.open(url, '_blank', 'width=400,height=600');
});
document.getElementById("settingsBtn")?.addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();
const url = chrome.runtime.getURL("settings/index.html");
window.open(url, "_blank", "width=400,height=600");
});
}
function setupMobileNavigation() {
setTimeout(() => {
const navToggle = document.querySelector('.nav-toggle');
const nav = document.querySelector('.kreta-nav');
setTimeout(() => {
const navToggle = document.querySelector(".nav-toggle");
const nav = document.querySelector(".kreta-nav");
if (!navToggle || !nav) {
return;
}
const isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
if (isFirefox) {
let isNavOpen = false;
navToggle.addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();
if (!navToggle || !nav) {
return;
if (isNavOpen) {
nav.style.display = "none";
nav.classList.remove("show");
isNavOpen = false;
} else {
nav.style.display = "flex";
nav.classList.add("show");
isNavOpen = true;
}
});
navToggle.addEventListener("touchend", (e) => {
e.preventDefault();
e.stopPropagation();
navToggle.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
nav.classList.toggle('show');
if (isNavOpen) {
nav.style.display = "none";
nav.classList.remove("show");
isNavOpen = false;
} else {
nav.style.display = "flex";
nav.classList.add("show");
isNavOpen = true;
}
});
document.addEventListener("click", (e) => {
if (!nav.contains(e.target) && !navToggle.contains(e.target) && isNavOpen) {
nav.style.display = "none";
nav.classList.remove("show");
isNavOpen = false;
}
});
const navItems = document.querySelectorAll(".nav-item");
navItems.forEach((item) => {
item.addEventListener("click", () => {
nav.style.display = "none";
nav.classList.remove("show");
isNavOpen = false;
});
});
} else {
navToggle.addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();
nav.classList.toggle("show");
});
document.addEventListener('click', (e) => {
if (!nav.contains(e.target) && !navToggle.contains(e.target)) {
nav.classList.remove('show');
}
});
document.addEventListener("click", (e) => {
if (!nav.contains(e.target) && !navToggle.contains(e.target)) {
nav.classList.remove("show");
}
});
const navItems = document.querySelectorAll('.nav-item');
navItems.forEach(item => {
item.addEventListener('click', () => {
nav.classList.remove('show');
});
const navItems = document.querySelectorAll(".nav-item");
navItems.forEach((item) => {
item.addEventListener("click", () => {
nav.classList.remove("show");
});
}, 100);
});
}
}, 100);
}
document.addEventListener('DOMContentLoaded', () => {
updateHeaderInfo();
setupUserDropdown();
setupSettingsButton();
setupMobileNavigation();
document.addEventListener("DOMContentLoaded", async () => {
await updateHeaderInfo();
setupUserDropdown();
setupSettingsButton();
setupMobileNavigation();
});

View File

@@ -1,160 +1,163 @@
:root {
--background: #DAE4F7;
--background-0: #dae4f700;
--success: var(--grades-4);
--shadow-blur: 2px;
--text-primary: #050B15;
--text-secondary: #050b15cc;
--text-teritary: #050b1580;
--card-card: #EDF3FF;
--card-translucent: #edf3ff80;
--button-secondaryFill: #FBFCFF;
--accent-accent: #3673EE;
--accent-secondary: #1C469A;
--accent-shadow: #1c469a26;
--accent-15: #3673ee26;
--warning-accent: var(--grades-2);
--warning-text: #8F531B;
--warning-15: #ffa04626;
--warning-card: #FAEBDC;
--error-accent: var(--grades-1);
--error-text: #8F1B4F;
--error-15: #FF54A126;
--error-card: #FADCE9;
--grades-1: #FF54A1;
--grades-2: #FFA046;
--grades-3: #F9CF00;
--grades-4: #92EA3B;
--grades-5: #22CCAD;
--grades-background-1: #FF54A126;
--grades-background-2: #FFA04626;
--grades-background-3: #F9CF0026;
--grades-background-4: #92EA3B26;
--grades-background-5: #22CCAD26;
--background:#DAE4F7;
--background-0:#dae4f700;
--success:var(--grades-4);
--shadow-blur:2px;
--text-primary:#050B15;
--text-secondary:#050b15cc;
--text-teritary:#050b1580;
--card-card:#EDF3FF;
--card-translucent:#edf3ff80;
--button-secondaryFill:#FBFCFF;
--accent-accent:#3673EE;
--accent-secondary:#1C469A;
--accent-shadow:#1c469a26;
--accent-15:#3673ee26;
--warning-accent:var(--grades-2);
--warning-text:#8F531B;
--warning-15:#ffa04626;
--warning-card:#FAEBDC;
--error-accent:var(--grades-1);
--error-text:#8F1B4F;
--error-15:#FF54A126;
--error-card:#FADCE9;
--grades-1:#FF54A1;
--grades-2:#FFA046;
--grades-3:#F9CF00;
--grades-4:#92EA3B;
--grades-5:#22CCAD;
--grades-background-1:#FF54A126;
--grades-background-2:#FFA04626;
--grades-background-3:#F9CF0026;
--grades-background-4:#92EA3B26;
--grades-background-5:#22CCAD26;
}
:root[data-theme="light-green"] {
--background: #FAFFF0;
--background-0: #fafff000;
--success: var(--grades-4);
--shadow-blur: 2px;
--text-primary: #394C0A;
--text-secondary: #394c0acc;
--text-teritary: #394c0a80;
--card-card: #F3FBDE;
--card-translucent: #f3fbde80;
--button-secondaryFill: #FEFFFD;
--accent-accent: #A7DC22;
--accent-secondary: #6E8F1B;
--accent-shadow: #647e2226;
--accent-15: #a7dc2226;
--warning-accent: var(--grades-2);
--warning-text: #8F531B;
--warning-15: #ffa04626;
--warning-card: #FAEBDC;
--error-accent: var(--grades-1);
--error-text: #8F1B4F;
--error-15: #FF54A126;
--error-card: #FADCE9;
--grades-1: #FF54A1;
--grades-2: #FFA046;
--grades-3: #F9CF00;
--grades-4: #92EA3B;
--grades-5: #22CCAD;
--grades-background-1: #FF54A126;
--grades-background-2: #FFA04626;
--grades-background-3: #F9CF0026;
--grades-background-4: #92EA3B26;
--grades-background-5: #22CCAD26;
--background:#FAFFF0;
--background-0:#fafff000;
--success:var(--grades-4);
--shadow-blur:2px;
--text-primary:#394C0A;
--text-secondary:#394c0acc;
--text-teritary:#394c0a80;
--card-card:#F3FBDE;
--card-translucent:#f3fbde80;
--button-secondaryFill:#FEFFFD;
--accent-accent:#A7DC22;
--accent-secondary:#6E8F1B;
--accent-shadow:#647e2226;
--accent-15:#a7dc2226;
--warning-accent:var(--grades-2);
--warning-text:#8F531B;
--warning-15:#ffa04626;
--warning-card:#FAEBDC;
--error-accent:var(--grades-1);
--error-text:#8F1B4F;
--error-15:#FF54A126;
--error-card:#FADCE9;
--grades-1:#FF54A1;
--grades-2:#FFA046;
--grades-3:#F9CF00;
--grades-4:#92EA3B;
--grades-5:#22CCAD;
--grades-background-1:#FF54A126;
--grades-background-2:#FFA04626;
--grades-background-3:#F9CF0026;
--grades-background-4:#92EA3B26;
--grades-background-5:#22CCAD26;
}
:root[data-theme="dark-blue"] {
--background: #070A0E;
--background-0: #070a0e00;
--success: var(--grades-4);
--shadow-blur: 0;
--text-primary: #EBF1FD;
--text-secondary: #ebf1fdcc;
--text-teritary: #ebf1fd80;
--card-card: #0F131B;
--card-translucent: #0f131b80;
--button-secondaryFill: #131822;
--accent-accent: #3673EE;
--accent-secondary: #AEC8FC;
--accent-shadow: #0000;
--accent-15: #3673ee26;
--warning-accent: var(--grades-2);
--warning-text: #f0b37a;
--warning-15: #ffa04626;
--warning-card: #201203;
--error-accent: var(--grades-1);
--error-text: #f59ec5;
--error-15: #ff54a126;
--error-card: #1e030f;
--grades-1: #FF54A1;
--grades-2: #FFA046;
--grades-3: #F9CF00;
--grades-4: #92EA3B;
--grades-5: #22CCAD;
--grades-background-1: #FF54A126;
--grades-background-2: #FFA04626;
--grades-background-3: #F9CF0026;
--grades-background-4: #92EA3B26;
--grades-background-5: #22CCAD26;
--background:#070A0E;
--background-0:#070a0e00;
--success:var(--grades-4);
--shadow-blur:0;
--text-primary:#EBF1FD;
--text-secondary:#ebf1fdcc;
--text-teritary:#ebf1fd80;
--card-card:#0F131B;
--card-translucent:#0f131b80;
--button-secondaryFill:#131822;
--accent-accent:#3673EE;
--accent-secondary:#AEC8FC;
--accent-shadow:#0000;
--accent-15:#3673ee26;
--warning-accent:var(--grades-2);
--warning-text:#f0b37a;
--warning-15:#ffa04626;
--warning-card:#201203;
--error-accent:var(--grades-1);
--error-text:#f59ec5;
--error-15:#ff54a126;
--error-card:#1e030f;
--grades-1:#FF54A1;
--grades-2:#FFA046;
--grades-3:#F9CF00;
--grades-4:#92EA3B;
--grades-5:#22CCAD;
--grades-background-1:#FF54A126;
--grades-background-2:#FFA04626;
--grades-background-3:#F9CF0026;
--grades-background-4:#92EA3B26;
--grades-background-5:#22CCAD26;
}
:root[data-theme="dark-green"] {
--background: #0D1202;
--background-0: #0E130200;
--success: var(--grades-4);
--shadow-blur: 0;
--text-primary: #EAF7CC;
--text-secondary: #EAF7CCCC;
--text-teritary: #EAF7CC80;
--card-card: #141905;
--card-translucent: #14190580;
--button-secondaryFill: #20290b;
--accent-accent: #A7DC22;
--accent-secondary: #CBEE71;
--accent-shadow: #0000;
--accent-15: #a7dc2226;
--warning-accent: var(--grades-2);
--warning-text: #f0b37a;
--warning-15: #ffa04626;
--warning-card: #201203;
--error-accent: var(--grades-1);
--error-text: #f59ec5;
--error-15: #ff54a126;
--error-card: #1e030f;
--grades-1: #FF54A1;
--grades-2: #FFA046;
--grades-3: #F9CF00;
--grades-4: #92EA3B;
--grades-5: #22CCAD;
--grades-background-1: #FF54A126;
--grades-background-2: #FFA04626;
--grades-background-3: #F9CF0026;
--grades-background-4: #92EA3B26;
--grades-background-5: #22CCAD26;
--background:#0D1202;
--background-0:#0E130200;
--success:var(--grades-4);
--shadow-blur:0;
--text-primary:#EAF7CC;
--text-secondary:#EAF7CCCC;
--text-teritary:#EAF7CC80;
--card-card:#141905;
--card-translucent:#14190580;
--button-secondaryFill:#20290b;
--accent-accent:#A7DC22;
--accent-secondary:#CBEE71;
--accent-shadow:#0000;
--accent-15:#a7dc2226;
--warning-accent:var(--grades-2);
--warning-text:#f0b37a;
--warning-15:#ffa04626;
--warning-card:#201203;
--error-accent:var(--grades-1);
--error-text:#f59ec5;
--error-15:#ff54a126;
--error-card:#1e030f;
--grades-1:#FF54A1;
--grades-2:#FFA046;
--grades-3:#F9CF00;
--grades-4:#92EA3B;
--grades-5:#22CCAD;
--grades-background-1:#FF54A126;
--grades-background-2:#FFA04626;
--grades-background-3:#F9CF0026;
--grades-background-4:#92EA3B26;
--grades-background-5:#22CCAD26;
}
html {
background-color: var(--background) !important;
color: var(--text-primary) !important;
background-color:var(--background) !important;
color:var(--text-primary) !important;
}
body {
background-color: var(--background) !important;
color: var(--text-primary) !important;
transition: background-color 0.2s ease, color 0.2s ease;
min-height: 100vh;
background-color:var(--background) !important;
color:var(--text-primary) !important;
transition:background-color 0.2s ease,color 0.2s ease;
min-height:100vh;
}
* {
transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}
transition:background-color 0.2s ease,color 0.2s ease,border-color 0.2s ease;
}
::-webkit-scrollbar {
width:clamp(4px,1vw,8px);
height:clamp(4px,1vw,8px);
}
::-webkit-scrollbar-track {
background:var(--background);
}
::-webkit-scrollbar-thumb {
background:var(--text-secondary);
border-radius:4px;
}
::-webkit-scrollbar-thumb:hover {
background:var(--text-primary);
}

View File

@@ -1,132 +1,215 @@
(() => {
function setTheme(theme) {
try {
const actualTheme = theme === 'default' ? 'light-blue' : theme;
document.documentElement.setAttribute('data-theme', actualTheme);
cookieManager.set('themePreference', actualTheme);
localStorage.setItem('themePreference', actualTheme);
chrome.runtime.sendMessage({
action: 'themeChanged',
theme: actualTheme
}).catch(() => {
async function setTheme(theme) {
try {
const actualTheme = theme === "default" ? "light-blue" : theme;
});
} catch (error) {
console.error('Error setting theme:', error);
}
document.documentElement.setAttribute("data-theme", actualTheme);
await storageManager.set("themePreference", actualTheme);
localStorage.setItem("themePreference", actualTheme);
chrome.runtime
.sendMessage({
action: "themeChanged",
theme: actualTheme,
})
.catch(() => {});
} catch (error) {
console.error("Error setting theme:", error);
}
function setPageTitleAndFavicon() {
try {
document.title = 'Firka - KRÉTA';
}
const existingFavicons = document.querySelectorAll('link[rel="icon"], link[rel="shortcut icon"]');
existingFavicons.forEach(link => link.remove());
if (typeof chrome !== 'undefined' && chrome.runtime && chrome.runtime.getURL) {
const favicon = document.createElement('link');
favicon.rel = 'icon';
favicon.type = 'image/png';
favicon.href = chrome.runtime.getURL('images/firka_logo_128.png');
document.head.appendChild(favicon);
const shortcutIcon = document.createElement('link');
shortcutIcon.rel = 'shortcut icon';
shortcutIcon.type = 'image/png';
shortcutIcon.href = chrome.runtime.getURL('images/firka_logo_128.png');
document.head.appendChild(shortcutIcon);
}
} catch (error) {
console.error('Error setting page title and favicon:', error);
function importFonts() {
try {
const fontFaces = `
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 400;
src: url('${chrome.runtime.getURL('fonts/Montserrat-Regular.woff2')}') format('woff2');
font-display: swap;
}
}
function initializeTheme() {
const cookieTheme = cookieManager.get('themePreference');
const localStorageTheme = localStorage.getItem('themePreference');
const theme = cookieTheme || localStorageTheme || 'light-green';
setTheme(theme);
setPageTitleAndFavicon();
if (cookieTheme !== localStorageTheme) {
if (cookieTheme) {
localStorage.setItem('themePreference', cookieTheme);
} else if (localStorageTheme) {
cookieManager.set('themePreference', localStorageTheme);
}
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 500;
src: url('${chrome.runtime.getURL('fonts/Montserrat-Medium.woff2')}') format('woff2');
font-display: swap;
}
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 600;
src: url('${chrome.runtime.getURL('fonts/Montserrat-SemiBold.woff2')}') format('woff2');
font-display: swap;
}
@font-face {
font-family: 'Figtree';
font-style: normal;
font-weight: 400;
src: url('${chrome.runtime.getURL('fonts/Figtree-Regular.woff2')}') format('woff2');
font-display: swap;
}
`;
const styleElement = document.createElement('style');
styleElement.textContent = fontFaces;
document.head.appendChild(styleElement);
const iconFontFace = `
@font-face {
font-family: 'Material Icons Round';
font-style: normal;
font-weight: 400;
src: url('${chrome.runtime.getURL('fonts/Icons.woff2')}') format('woff2');
font-display: swap;
}
`;
const iconStyleElement = document.createElement('style');
iconStyleElement.textContent = iconFontFace;
document.head.appendChild(iconStyleElement);
} catch (error) {
console.error("Error importing fonts:", error);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initializeTheme);
} else {
initializeTheme();
}
function setPageTitleAndFavicon() {
try {
document.title = "Firka - KRÉTA";
const existingFavicons = document.querySelectorAll(
'link[rel="icon"], link[rel="shortcut icon"]',
);
existingFavicons.forEach((link) => link.remove());
if (
typeof chrome !== "undefined" &&
chrome.runtime &&
chrome.runtime.getURL
) {
const favicon = document.createElement("link");
favicon.rel = "icon";
favicon.type = "image/png";
favicon.href = chrome.runtime.getURL("images/firka_logo_128.png");
document.head.appendChild(favicon);
const shortcutIcon = document.createElement("link");
shortcutIcon.rel = "shortcut icon";
shortcutIcon.type = "image/png";
shortcutIcon.href = chrome.runtime.getURL("images/firka_logo_128.png");
document.head.appendChild(shortcutIcon);
}
} catch (error) {
console.error("Error setting page title and favicon:", error);
}
}
async function initializeTheme() {
try {
const storageTheme = await storageManager.get("themePreference");
const localStorageTheme = localStorage.getItem("themePreference");
const theme = storageTheme || localStorageTheme || "light-green";
await setTheme(theme);
setPageTitleAndFavicon();
importFonts();
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();
}
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initializeTheme);
} else {
initializeTheme();
}
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === "changeTheme") {
setTheme(message.theme);
sendResponse({ success: true });
}
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === 'changeTheme') {
setTheme(message.theme);
sendResponse({ success: true });
}
if (message.action === 'getTheme') {
const currentTheme = document.documentElement.getAttribute('data-theme') || 'light-green';
sendResponse({ theme: currentTheme });
}
if (message.action === "getTheme") {
const currentTheme =
document.documentElement.getAttribute("data-theme") || "light-green";
sendResponse({ theme: currentTheme });
}
return true;
return true;
});
let titleCheckTimeout;
const observer = new MutationObserver(async (mutations) => {
const currentTheme = document.documentElement.getAttribute("data-theme");
try {
const savedTheme = await storageManager.get("themePreference") ||
localStorage.getItem("themePreference");
if (
(!currentTheme && savedTheme) ||
(currentTheme !== savedTheme && savedTheme)
) {
await setTheme(savedTheme);
}
} catch (error) {
console.error("Error checking theme in observer:", error);
}
const titleChanged = mutations.some(
(mutation) =>
mutation.type === "childList" &&
mutation.target === document.head &&
Array.from(mutation.addedNodes).some(
(node) => node.tagName === "TITLE",
),
);
if (titleChanged || document.title !== "Firka - KRÉTA") {
clearTimeout(titleCheckTimeout);
titleCheckTimeout = setTimeout(() => {
if (document.title !== "Firka - KRÉTA") {
setPageTitleAndFavicon();
}
}, 100);
}
});
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", () => {
observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ["data-theme"],
});
observer.observe(document.head, {
childList: true,
subtree: true,
});
});
let titleCheckTimeout;
const observer = new MutationObserver((mutations) => {
const currentTheme = document.documentElement.getAttribute('data-theme');
const savedTheme = cookieManager.get('themePreference') || localStorage.getItem('themePreference');
if ((!currentTheme && savedTheme) || (currentTheme !== savedTheme && savedTheme)) {
setTheme(savedTheme);
}
const titleChanged = mutations.some(mutation =>
mutation.type === 'childList' &&
mutation.target === document.head &&
Array.from(mutation.addedNodes).some(node => node.tagName === 'TITLE')
);
if (titleChanged || document.title !== 'Firka - KRÉTA') {
clearTimeout(titleCheckTimeout);
titleCheckTimeout = setTimeout(() => {
if (document.title !== 'Firka - KRÉTA') {
setPageTitleAndFavicon();
}
}, 100);
}
} else {
observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ["data-theme"],
});
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ['data-theme']
});
observer.observe(document.head, {
childList: true,
subtree: true
});
});
} else {
observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ['data-theme']
});
observer.observe(document.head, {
childList: true,
subtree: true
});
}
})();
observer.observe(document.head, {
childList: true,
subtree: true,
});
}
})();

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -169,6 +169,7 @@ body {
.dropdown-item:hover {
background-color: var(--accent-15);
text-decoration: none;
}
@@ -200,6 +201,108 @@ body {
background-color: var(--card-card);
}
/* Checkbox oszlop stílusai */
.checkbox-header {
width: 50px;
text-align: center;
font-size: 16px;
}
.checkbox-cell {
width: 50px;
text-align: center;
padding: 8px !important;
}
.homework-checkbox {
width: 20px;
height: 20px;
cursor: pointer;
appearance: none;
border: 2px solid var(--accent-30);
border-radius: 4px;
background-color: var(--card-card);
position: relative;
transition: all 0.2s ease;
display: flex;
align-items: center;
justify-content: center;
}
.homework-checkbox:hover {
border-color: var(--accent);
background-color: var(--accent-15);
transform: scale(1.05);
}
.homework-checkbox:checked {
background-color: var(--accent);
border-color: var(--accent);
}
.homework-checkbox:checked::after {
content: '✓';
color: white;
font-size: 14px;
font-weight: bold;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.homework-checkbox:focus {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
.homework-checkbox:active {
transform: scale(0.95);
}
/* Megjelölt házi feladatok stílusai */
.table-row.user-completed {
opacity: 0.6;
background-color: var(--accent-15) !important;
}
.table-row.user-completed .table-cell {
color: var(--text-secondary);
}
.table-row.user-completed .status-badge.completed {
background-color: var(--success);
color: white;
}
/* Mobil nézet checkbox stílusai */
@media (max-width: 768px) {
.checkbox-header {
width: 40px;
font-size: 14px;
}
.checkbox-cell {
width: 40px;
padding: 6px !important;
}
.homework-checkbox {
width: 18px;
height: 18px;
}
.homework-checkbox:checked::after {
font-size: 12px;
}
.table-row.user-completed {
opacity: 0.7;
}
}
.filter-content {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
@@ -269,37 +372,145 @@ body {
opacity: 0.9;
}
.homework-list {
display: flex;
flex-direction: column;
.stats-overview {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 16px;
margin-bottom: 24px;
}
.homework-date-group {
.stat-card {
background: var(--card-card);
border-radius: 16px;
padding: 20px;
text-align: center;
box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow);
transition: transform 0.2s ease;
}
.stat-card:hover {
transform: translateY(-2px);
}
.stat-number {
font-size: 32px;
font-weight: 700;
color: var(--accent-accent);
margin-bottom: 8px;
}
.stat-label {
font-size: 14px;
color: var(--text-secondary);
font-weight: 500;
}
.stat-card.urgent .stat-number {
color: #ff4757;
}
.stat-card.completed .stat-number {
color: #2ed573;
}
.homework-container {
background: var(--card-card);
border-radius: 24px;
overflow: hidden;
animation: fadeIn 0.3s ease;
box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow);
}
.date-header {
padding: 16px;
color: var(--text-primary);
font-weight: 600;
display: flex;
align-items: center;
gap: 8px;
.homework-table {
width: 100%;
border-collapse: collapse;
}
.homework-count {
margin-left: auto;
background: var(--accent-accent);
color: var(--button-secondaryFill);
padding: 4px 8px;
border-radius: 12px;
.table-header {
background: var(--accent-15);
font-weight: 600;
color: var(--text-primary);
}
.table-header th {
padding: 16px;
text-align: left;
font-size: 14px;
border-bottom: 1px solid var(--accent-15);
}
.table-row {
border-bottom: 1px solid var(--accent-15);
transition: background-color 0.2s ease;
}
.table-row:hover {
background-color: var(--accent-15);
}
.table-row.due-tomorrow {
background-color: rgba(255, 71, 87, 0.1);
}
.table-row.due-tomorrow:hover {
background-color: rgba(255, 71, 87, 0.2);
}
.table-cell {
padding: 16px;
vertical-align: top;
border-bottom: 1px solid var(--accent-15);
}
.date-cell {
font-weight: 600;
color: var(--text-primary);
min-width: 120px;
}
.subject-cell {
font-weight: 500;
color: var(--accent-accent);
min-width: 120px;
}
.description-cell {
max-width: 300px;
word-wrap: break-word;
line-height: 1.4;
}
.teacher-cell {
color: var(--text-secondary);
font-style: italic;
min-width: 120px;
}
.status-cell {
text-align: center;
min-width: 100px;
}
.status-badge {
padding: 4px 12px;
border-radius: 12px;
font-size: 12px;
font-weight: 500;
text-transform: uppercase;
}
.status-badge.pending {
background-color: rgba(255, 193, 7, 0.2);
color: #ffc107;
}
.status-badge.urgent {
background-color: rgba(255, 71, 87, 0.2);
color: #ff4757;
}
.status-badge.completed {
background-color: rgba(46, 213, 115, 0.2);
color: #2ed573;
}
.homework-list-items {
@@ -398,6 +609,104 @@ body {
flex-direction: column;
gap: 0.25rem;
}
.stats-overview {
grid-template-columns: repeat(2, 1fr);
}
.table-cell {
padding: 12px;
font-size: 14px;
}
.description-cell {
max-width: 200px;
}
}
@media (max-width: 480px) {
.homework-container {
overflow-x: hidden;
}
.homework-table,
.table-header,
.table-row,
.table-cell {
display: block;
}
.table-header {
display: none;
}
.date-group {
margin-bottom: 24px;
}
.date-group-header {
background: var(--accent-accent);
color: white;
padding: 12px 16px;
font-weight: 600;
font-size: 16px;
border-radius: 12px 12px 0 0;
margin-bottom: 0;
}
.date-group-content {
background: var(--card-card);
border: 1px solid var(--accent-15);
border-radius: 0 0 12px 12px;
overflow: hidden;
}
.table-row {
display: block;
width: 100%;
margin-bottom: 0;
padding: 16px;
border-bottom: 1px solid var(--accent-15);
background: var(--card-card);
}
.table-row:last-child {
border-bottom: none;
}
.table-cell {
display: flex;
justify-content: space-between;
align-items: flex-start;
padding: 8px 0;
border-bottom: 1px solid var(--accent-15);
}
.table-cell:last-child {
border-bottom: none;
}
.table-cell::before {
content: attr(data-label);
font-weight: 600;
color: var(--text-secondary);
font-size: 12px;
text-transform: uppercase;
flex-shrink: 0;
}
.description-cell {
max-width: none;
white-space: normal;
text-overflow: initial;
overflow: visible;
text-align: right;
flex: 1;
}
.stats-overview {
grid-template-columns: 1fr;
}
}
@keyframes fadeIn {

View File

@@ -2,62 +2,64 @@ async function fetchHomeworkData() {
try {
const currentDomain = window.location.hostname;
const apiUrl = `https://${currentDomain}/api/TanuloHaziFeladatApi/GetTanulotHaziFeladatGrid?sort=HaziFeladatHatarido-asc&page=1&pageSize=100&group=&filter=&data=%7B%22RegiHaziFeladatokElrejtese%22%3Afalse%7D&_=${Date.now()}`;
const response = await fetch(apiUrl, {
method: 'GET',
credentials: 'include',
method: "GET",
credentials: "include",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
Accept: "application/json",
"Content-Type": "application/json",
},
});
if (!response.ok) {
throw new Error('Network response was not ok');
throw new Error("Network response was not ok");
}
const data = await response.json();
return data;
} catch (error) {
console.error('Error fetching homework data:', error);
console.error("Error fetching homework data:", error);
return { Data: [], Total: 0 };
}
}
async function collectHomeworkData() {
const apiData = await fetchHomeworkData();
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ó',
time: document.querySelector('.usermenu_timer')?.textContent?.trim() || '45:00'
}
name: await storageManager.get("userName", "Felhasználónév"),
time:
document.querySelector(".usermenu_timer")?.textContent?.trim() ||
"45:00",
},
};
const homeworkItems = [];
if (apiData.Data && Array.isArray(apiData.Data)) {
apiData.Data.forEach(item => {
apiData.Data.forEach((item) => {
homeworkItems.push({
id: item.ID,
subject: item.TantargyNev || '',
teacher: item.TanarNeve || '',
description: item.HaziFeladatSzoveg || '',
subject: item.TantargyNev || "",
teacher: item.TanarNeve || "",
description: item.HaziFeladatSzoveg || "",
createdDate: formatApiDate(item.HaziFeladatRogzitesDatuma),
deadline: formatApiDate(item.HaziFeladatHatarido),
completed: item.MegoldottHF_BOOL || false,
classGroup: item.OsztalyCsoport || ''
classGroup: item.OsztalyCsoport || "",
});
});
}
const groupedHomework = {};
homeworkItems.forEach(homework => {
const deadlineDate = homework.deadline.split(' ')[0];
homeworkItems.forEach((homework) => {
const deadlineDate = homework.deadline.split(" ")[0];
if (!groupedHomework[deadlineDate]) {
groupedHomework[deadlineDate] = [];
}
@@ -68,24 +70,24 @@ async function collectHomeworkData() {
}
function formatApiDate(dateString) {
if (!dateString) return '';
if (!dateString) return "";
try {
const date = new Date(dateString);
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
const dayNames = [
LanguageManager.t('common.sunday'),
LanguageManager.t('common.monday'),
LanguageManager.t('common.tuesday'),
LanguageManager.t('common.wednesday'),
LanguageManager.t('common.thursday'),
LanguageManager.t('common.friday'),
LanguageManager.t('common.saturday')
LanguageManager.t("common.sunday"),
LanguageManager.t("common.monday"),
LanguageManager.t("common.tuesday"),
LanguageManager.t("common.wednesday"),
LanguageManager.t("common.thursday"),
LanguageManager.t("common.friday"),
LanguageManager.t("common.saturday"),
];
const dayName = dayNames[date.getDay()];
return `${month}.${day}. (${dayName})`;
} catch (error) {
return dateString;
@@ -94,341 +96,617 @@ function formatApiDate(dateString) {
function isTomorrow(dateStr) {
if (!dateStr) return false;
const parts = dateStr.split('.');
const parts = dateStr.split(".");
if (parts.length < 3) return false;
const year = parseInt(parts[0].trim());
const month = parseInt(parts[1].trim()) - 1;
const day = parseInt(parts[2].trim());
const homeworkDate = new Date(year, month, day);
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
tomorrow.setHours(0, 0, 0, 0);
const dayAfterTomorrow = new Date(tomorrow);
dayAfterTomorrow.setDate(dayAfterTomorrow.getDate() + 1);
return homeworkDate >= tomorrow && homeworkDate < dayAfterTomorrow;
}
async function transformHomeworkPage() {
const { basicData, homeworkItems, groupedHomework } = await collectHomeworkData();
const { basicData, homeworkItems, groupedHomework } =
await collectHomeworkData();
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(await createTemplate.header(), 'text/html');
const headerContent = headerDoc.body;
while (headerContent.firstChild) {
headerDiv.appendChild(headerContent.firstChild);
}
kretaContainer.appendChild(headerDiv);
const main = document.createElement('main');
main.className = 'kreta-main';
document.body.innerHTML = `
<div class="kreta-container">
${createTemplate.header()}
const filterCard = document.createElement('div');
filterCard.className = 'filter-card';
const filterHeader = document.createElement('div');
filterHeader.className = 'filter-header';
const filterTitle = document.createElement('h2');
filterTitle.textContent = LanguageManager.t('homework.filter_title');
filterHeader.appendChild(filterTitle);
const filterContent = document.createElement('div');
filterContent.className = 'filter-content';
<main class="kreta-main">
<div class="filter-card">
<div class="filter-header">
<h2>${LanguageManager.t('homework.filter_title')}</h2>
</div>
<div class="filter-content">
<div class="filter-group">
<label>
<!--<span class="material-icons-round">subject</span>-->
${LanguageManager.t('homework.subject')}
</label>
<select id="subjectFilter">
<option value="">${LanguageManager.t('homework.all_subjects')}</option>
${[...new Set(homeworkItems.map(item => item.subject))]
.sort()
.map(subject => `<option value="${subject}">${subject}</option>`)
.join('')}
</select>
</div>
<div class="filter-group">
<label>
<!--<span class="material-icons-round">person</span>-->
${LanguageManager.t('homework.teacher')}
</label>
<select id="teacherFilter">
<option value="">${LanguageManager.t('homework.all_teachers')}</option>
${[...new Set(homeworkItems.map(item => item.teacher))]
.sort()
.map(teacher => `<option value="${teacher}">${teacher}</option>`)
.join('')}
</select>
</div>
<div class="filter-group">
<label>
<!--<span class="material-icons-round">date_range</span>-->
${LanguageManager.t('homework.due_date')}
</label>
<select id="deadlineFilter">
<option value="">${LanguageManager.t('homework.all_deadlines')}</option>
<option value="tomorrow">${LanguageManager.t('homework.tomorrow_deadline')}</option>
<option value="thisWeek">${LanguageManager.t('homework.this_week')}</option>
<option value="nextWeek">${LanguageManager.t('homework.next_week')}</option>
</select>
</div>
</div>
</div>
const subjectGroup = document.createElement('div');
subjectGroup.className = 'filter-group';
const subjectLabel = document.createElement('label');
subjectLabel.textContent = LanguageManager.t('homework.subject');
const subjectSelect = document.createElement('select');
subjectSelect.id = 'subjectFilter';
const allSubjectsOption = document.createElement('option');
allSubjectsOption.value = '';
allSubjectsOption.textContent = LanguageManager.t('homework.all_subjects');
subjectSelect.appendChild(allSubjectsOption);
[...new Set(homeworkItems.map((item) => item.subject))]
.sort()
.forEach((subject) => {
const option = document.createElement('option');
option.value = subject;
option.textContent = subject;
subjectSelect.appendChild(option);
});
subjectGroup.appendChild(subjectLabel);
subjectGroup.appendChild(subjectSelect);
<div class="homework-list" id="homeworkList">
${renderHomeworkList(groupedHomework)}
</div>
</main>
</div>
`;
const teacherGroup = document.createElement('div');
teacherGroup.className = 'filter-group';
const teacherLabel = document.createElement('label');
teacherLabel.textContent = LanguageManager.t('homework.teacher');
const teacherSelect = document.createElement('select');
teacherSelect.id = 'teacherFilter';
const allTeachersOption = document.createElement('option');
allTeachersOption.value = '';
allTeachersOption.textContent = LanguageManager.t('homework.all_teachers');
teacherSelect.appendChild(allTeachersOption);
[...new Set(homeworkItems.map((item) => item.teacher))]
.sort()
.forEach((teacher) => {
const option = document.createElement('option');
option.value = teacher;
option.textContent = teacher;
teacherSelect.appendChild(option);
});
teacherGroup.appendChild(teacherLabel);
teacherGroup.appendChild(teacherSelect);
const deadlineGroup = document.createElement('div');
deadlineGroup.className = 'filter-group';
const deadlineLabel = document.createElement('label');
deadlineLabel.textContent = LanguageManager.t('homework.due_date');
const deadlineSelect = document.createElement('select');
deadlineSelect.id = 'deadlineFilter';
const deadlineOptions = [
{ value: '', text: LanguageManager.t('homework.all_deadlines') },
{ value: 'tomorrow', text: LanguageManager.t('homework.tomorrow_deadline') },
{ value: 'thisWeek', text: LanguageManager.t('homework.this_week') },
{ value: 'nextWeek', text: LanguageManager.t('homework.next_week') }
];
deadlineOptions.forEach(({ value, text }) => {
const option = document.createElement('option');
option.value = value;
option.textContent = text;
deadlineSelect.appendChild(option);
});
deadlineGroup.appendChild(deadlineLabel);
deadlineGroup.appendChild(deadlineSelect);
filterContent.appendChild(subjectGroup);
filterContent.appendChild(teacherGroup);
filterContent.appendChild(deadlineGroup);
filterCard.appendChild(filterHeader);
filterCard.appendChild(filterContent);
const statsOverview = document.createElement('div');
statsOverview.className = 'stats-overview';
statsOverview.id = 'statsOverview';
const statCards = [
{ id: 'totalHomework', label: LanguageManager.t('homework.total_homework'), className: '' },
{ id: 'urgentHomework', label: LanguageManager.t('homework.urgent_homework'), className: 'urgent' },
{ id: 'completedHomework', label: LanguageManager.t('homework.completed_homework'), className: 'completed' },
{ id: 'pendingHomework', label: LanguageManager.t('homework.pending_homework'), className: '' }
];
statCards.forEach(({ id, label, className }) => {
const statCard = document.createElement('div');
statCard.className = `stat-card ${className}`.trim();
const statNumber = document.createElement('div');
statNumber.className = 'stat-number';
statNumber.id = id;
statNumber.textContent = '0';
const statLabel = document.createElement('div');
statLabel.className = 'stat-label';
statLabel.textContent = label;
statCard.appendChild(statNumber);
statCard.appendChild(statLabel);
statsOverview.appendChild(statCard);
});
const homeworkContainer = document.createElement('div');
homeworkContainer.className = 'homework-container';
const homeworkTable = document.createElement('table');
homeworkTable.className = 'homework-table';
homeworkTable.id = 'homeworkTable';
const thead = document.createElement('thead');
thead.className = 'table-header';
const headerRow = document.createElement('tr');
const headers = [
'✓',
LanguageManager.t('homework.due_date'),
LanguageManager.t('homework.subject'),
LanguageManager.t('homework.description'),
LanguageManager.t('homework.teacher'),
LanguageManager.t('homework.status')
];
headers.forEach((headerText, index) => {
const th = document.createElement('th');
th.textContent = headerText;
if (index === 0) {
th.className = 'checkbox-header';
}
headerRow.appendChild(th);
});
thead.appendChild(headerRow);
const tbody = document.createElement('tbody');
tbody.id = 'homeworkTableBody';
const homeworkHTML = generateHomeworkHTML(homeworkItems);
if (homeworkHTML.trim()) {
const parser = new DOMParser();
const doc = parser.parseFromString(`<table><tbody>${homeworkHTML}</tbody></table>`, 'text/html');
const tempTbody = doc.querySelector('tbody');
while (tempTbody.firstChild) {
tbody.appendChild(tempTbody.firstChild);
}
} else {
const emptyRow = document.createElement('tr');
const emptyCell = document.createElement('td');
emptyCell.colSpan = 5;
emptyCell.textContent = LanguageManager.t('homework.no_homework') || 'Nincs házi feladat';
emptyCell.style.textAlign = 'center';
emptyCell.style.padding = '20px';
emptyRow.appendChild(emptyCell);
tbody.appendChild(emptyRow);
}
homeworkTable.appendChild(thead);
homeworkTable.appendChild(tbody);
homeworkContainer.appendChild(homeworkTable);
main.appendChild(filterCard);
main.appendChild(statsOverview);
main.appendChild(homeworkContainer);
kretaContainer.appendChild(main);
document.body.appendChild(kretaContainer);
setupFilters(homeworkItems, groupedHomework);
setupUserDropdown();
setupMobileNavigation();
setupMobileGrouping();
updateStatistics();
loadingScreen.hide();
}
function renderHomeworkList(groupedHomework) {
const sortedDates = Object.keys(groupedHomework).sort((a, b) => {
const partsA = a.split('.');
const partsB = b.split('.');
const monthA = parseInt(partsA[0]) - 1;
const dayA = parseInt(partsA[1]);
const monthB = parseInt(partsB[0]) - 1;
const dayB = parseInt(partsB[1]);
const currentYear = new Date().getFullYear();
const currentMonth = new Date().getMonth();
const yearA = monthA < currentMonth ? currentYear + 1 : currentYear;
const yearB = monthB < currentMonth ? currentYear + 1 : currentYear;
const dateA = new Date(yearA, monthA, dayA);
const dateB = new Date(yearB, monthB, dayB);
return dateB - dateA;
function generateHomeworkHTML(homeworkItems) {
const sortedHomework = homeworkItems.sort((a, b) => {
const dateA = new Date(
a.deadline.split(" ")[0].split(".").reverse().join("-"),
);
const dateB = new Date(
b.deadline.split(" ")[0].split(".").reverse().join("-"),
);
return dateA - dateB;
});
if (sortedDates.length === 0) {
return `
<div class="empty-state">
<p>${LanguageManager.t('homework.no_homework')}</p>
</div>
`;
}
return sortedHomework
.map((homework) => {
const isUrgent = isTomorrow(homework.deadline);
const isUserCompleted = getHomeworkCompletionStatus(homework.id);
const status = homework.completed || isUserCompleted
? "completed"
: isUrgent
? "urgent"
: "pending";
const statusText = homework.completed || isUserCompleted
? LanguageManager.t("homework.completed")
: isUrgent
? LanguageManager.t("homework.urgent")
: LanguageManager.t("homework.pending");
return sortedDates.map(date => {
const homeworkItems = groupedHomework[date];
return `
<div class="homework-date-group" data-date="${date}">
<div class="date-header">
<h3>${formatDateHeader(date)}</h3>
<span class="homework-count">${homeworkItems.length} ${LanguageManager.t('homework.items') || 'feladat'}</span>
</div>
<div class="homework-list-items">
${homeworkItems.map(homework => {
const isTomorrowClass = isTomorrow(homework.deadline) ? 'due-tomorrow' : '';
const urgentClass = isTomorrow(homework.deadline) ? 'urgent' : '';
return `
<div class="homework-item ${isTomorrowClass}" data-subject="${homework.subject}" data-teacher="${homework.teacher}">
<div class="homework-details">
<div class="homework-subject">${homework.subject}</div>
<div class="homework-content">${homework.description}</div>
<div class="homework-teacher">${homework.teacher}</div>
</div>
</div>
`;
}).join('')}
</div>
</div>
return `
<tr class="table-row ${isUrgent ? "due-tomorrow" : ""} ${isUserCompleted ? "user-completed" : ""}"
data-subject="${homework.subject}"
data-teacher="${homework.teacher}"
data-deadline="${homework.deadline}"
data-homework-id="${homework.id}">
<td class="table-cell checkbox-cell">
<input type="checkbox" class="homework-checkbox"
data-homework-id="${homework.id}"
${isUserCompleted ? "checked" : ""}
title="${isUserCompleted ? 'Megcsinált házi - kattints a visszaállításhoz' : 'Kattints a megjelöléshez'}">
</td>
<td class="table-cell date-cell" data-label="${LanguageManager.t("homework.due_date")}:">${homework.deadline}</td>
<td class="table-cell subject-cell" data-label="${LanguageManager.t("homework.subject")}:">${homework.subject}</td>
<td class="table-cell description-cell" data-label="${LanguageManager.t("homework.description")}:">${homework.description}</td>
<td class="table-cell teacher-cell" data-label="${LanguageManager.t("homework.teacher")}:">${homework.teacher}</td>
<td class="table-cell status-cell" data-label="${LanguageManager.t("homework.status")}:">
<span class="status-badge ${status}">${statusText}</span>
</td>
</tr>
`;
}).join('');
})
.join("");
}
function formatDateHeader(dateStr) {
if (!dateStr) return '';
if (!dateStr) return "";
const today = new Date();
today.setHours(0, 0, 0, 0);
const tomorrow = new Date(today);
tomorrow.setDate(tomorrow.getDate() + 1);
const parts = dateStr.split('.');
const parts = dateStr.split(".");
if (parts.length < 2) return dateStr;
const month = parseInt(parts[0].trim()) - 1;
const day = parseInt(parts[1].trim());
const currentYear = today.getFullYear();
const date = new Date(currentYear, month, day);
if (date.toDateString() === today.toDateString()) {
return LanguageManager.t('common.today') + ' - ' + dateStr;
return LanguageManager.t("common.today") + " - " + dateStr;
} else if (date.toDateString() === tomorrow.toDateString()) {
return LanguageManager.t('common.tomorrow') + ' - ' + dateStr;
return LanguageManager.t("common.tomorrow") + " - " + dateStr;
}
const weekdays = [
LanguageManager.t('common.sunday'),
LanguageManager.t('common.monday'),
LanguageManager.t('common.tuesday'),
LanguageManager.t('common.wednesday'),
LanguageManager.t('common.thursday'),
LanguageManager.t('common.friday'),
LanguageManager.t('common.saturday')
LanguageManager.t("common.sunday"),
LanguageManager.t("common.monday"),
LanguageManager.t("common.tuesday"),
LanguageManager.t("common.wednesday"),
LanguageManager.t("common.thursday"),
LanguageManager.t("common.friday"),
LanguageManager.t("common.saturday"),
];
return `${weekdays[date.getDay()]} - ${dateStr}`;
}
function formatDate(dateStr) {
if (!dateStr) return '';
if (!dateStr) return "";
return dateStr;
}
function setupFilters(homeworkItems, groupedHomework) {
const subjectFilter = document.getElementById('subjectFilter');
const teacherFilter = document.getElementById('teacherFilter');
const deadlineFilter = document.getElementById('deadlineFilter');
const applyFilterBtn = document.getElementById('applyFilterBtn');
const resetFilterBtn = document.getElementById('resetFilterBtn');
const subjectFilter = document.getElementById("subjectFilter");
const teacherFilter = document.getElementById("teacherFilter");
const deadlineFilter = document.getElementById("deadlineFilter");
const applyFilters = () => {
const selectedSubject = subjectFilter.value;
const selectedTeacher = teacherFilter.value;
const selectedDeadline = deadlineFilter.value;
const homeworkElements = document.querySelectorAll('.homework-item');
const dateGroups = document.querySelectorAll('.homework-date-group');
dateGroups.forEach(group => {
group.style.display = 'none';
});
homeworkElements.forEach(item => {
const subject = item.getAttribute('data-subject');
const teacher = item.getAttribute('data-teacher');
const dateGroup = item.closest('.homework-date-group');
const dateStr = dateGroup.getAttribute('data-date');
let showItem = true;
const tableRows = document.querySelectorAll(".table-row");
tableRows.forEach((row) => {
const subject = row.getAttribute("data-subject");
const teacher = row.getAttribute("data-teacher");
const deadline = row.getAttribute("data-deadline");
let showRow = true;
if (selectedSubject && subject !== selectedSubject) {
showItem = false;
showRow = false;
}
if (selectedTeacher && teacher !== selectedTeacher) {
showItem = false;
showRow = false;
}
if (selectedDeadline) {
const parts = dateStr.split('.');
if (parts.length >= 3) {
const year = parseInt(parts[0].trim());
const month = parseInt(parts[1].trim()) - 1;
const day = parseInt(parts[2].trim());
const date = new Date(year, month, day);
const parts = deadline.split(" ")[0].split(".");
if (parts.length >= 2) {
const month = parseInt(parts[0].trim()) - 1;
const day = parseInt(parts[1].trim());
const currentYear = new Date().getFullYear();
const date = new Date(currentYear, month, day);
const today = new Date();
today.setHours(0, 0, 0, 0);
const tomorrow = new Date(today);
tomorrow.setDate(tomorrow.getDate() + 1);
const startOfWeek = new Date(today);
const dayOfWeek = today.getDay() || 7;
startOfWeek.setDate(today.getDate() - dayOfWeek + 1);
const endOfWeek = new Date(startOfWeek);
endOfWeek.setDate(startOfWeek.getDate() + 6);
const startOfNextWeek = new Date(endOfWeek);
startOfNextWeek.setDate(endOfWeek.getDate() + 1);
const endOfNextWeek = new Date(startOfNextWeek);
endOfNextWeek.setDate(startOfNextWeek.getDate() + 6);
if (selectedDeadline === 'tomorrow' && date.toDateString() !== tomorrow.toDateString()) {
showItem = false;
} else if (selectedDeadline === 'thisWeek' && (date < startOfWeek || date > endOfWeek)) {
showItem = false;
} else if (selectedDeadline === 'nextWeek' && (date < startOfNextWeek || date > endOfNextWeek)) {
showItem = false;
if (
selectedDeadline === "tomorrow" &&
date.toDateString() !== tomorrow.toDateString()
) {
showRow = false;
} else if (
selectedDeadline === "thisWeek" &&
(date < startOfWeek || date > endOfWeek)
) {
showRow = false;
} else if (
selectedDeadline === "nextWeek" &&
(date < startOfNextWeek || date > endOfNextWeek)
) {
showRow = false;
}
}
}
item.style.display = showItem ? 'block' : 'none';
if (showItem) {
dateGroup.style.display = 'block';
}
row.style.display = showRow ? "" : "none";
});
const visibleItems = document.querySelectorAll('.homework-item[style="display: block"]');
const homeworkList = document.getElementById('homeworkList');
let emptyState = homeworkList.querySelector('.empty-state');
if (!emptyState) {
emptyState = document.createElement('div');
emptyState.className = 'empty-state';
emptyState.innerHTML = `<p>${LanguageManager.t('homework.no_matching_homework')}</p>`;
homeworkList.appendChild(emptyState);
}
if (visibleItems.length === 0) {
emptyState.style.display = 'block';
} else {
emptyState.style.display = 'none';
}
updateDateGroupsVisibility();
updateStatistics();
setupHomeworkCheckboxes();
};
const resetFilters = () => {
subjectFilter.value = '';
teacherFilter.value = '';
deadlineFilter.value = '';
document.querySelectorAll('.homework-item').forEach(item => {
item.style.display = 'block';
});
document.querySelectorAll('.homework-date-group').forEach(group => {
group.style.display = 'block';
});
const homeworkList = document.getElementById('homeworkList');
const existingEmptyState = homeworkList.querySelector('.empty-state');
if (existingEmptyState) {
homeworkList.removeChild(existingEmptyState);
}
};
subjectFilter.addEventListener('change', applyFilters);
teacherFilter.addEventListener('change', applyFilters);
deadlineFilter.addEventListener('change', applyFilters);
subjectFilter.addEventListener("change", applyFilters);
teacherFilter.addEventListener("change", applyFilters);
deadlineFilter.addEventListener("change", applyFilters);
}
function updateStatistics() {
const visibleRows = document.querySelectorAll(
'.table-row:not([style*="display: none"])',
);
let totalCount = 0;
let urgentCount = 0;
let completedCount = 0;
let pendingCount = 0;
if (window.location.href.includes('/Tanulo/TanuloHaziFeladat')) {
transformHomeworkPage().catch(error => {
console.error('Error transforming homework page:', error);
visibleRows.forEach((row) => {
totalCount++;
if (row.classList.contains("due-tomorrow")) {
urgentCount++;
}
const statusBadge = row.querySelector(".status-badge");
if (statusBadge) {
if (statusBadge.classList.contains("completed")) {
completedCount++;
} else if (statusBadge.classList.contains("pending")) {
pendingCount++;
}
}
});
}
document.getElementById("totalHomework").textContent = totalCount;
document.getElementById("urgentHomework").textContent = urgentCount;
document.getElementById("completedHomework").textContent = completedCount;
document.getElementById("pendingHomework").textContent = pendingCount;
}
function setupMobileGrouping() {
function handleResize() {
if (window.innerWidth <= 480) {
createMobileGroups();
} else {
removeMobileGroups();
}
}
window.addEventListener("resize", handleResize);
handleResize();
}
function createMobileGroups() {
const tableBody = document.getElementById("homeworkTableBody");
const rows = Array.from(tableBody.querySelectorAll(".table-row"));
if (rows.length === 0) return;
const groupedByDate = {};
rows.forEach((row) => {
const deadline = row.getAttribute("data-deadline");
const dateKey = deadline.split(" ")[0];
if (!groupedByDate[dateKey]) {
groupedByDate[dateKey] = [];
}
groupedByDate[dateKey].push(row);
});
tableBody.innerHTML = "";
Object.keys(groupedByDate)
.sort()
.forEach((date) => {
const dateGroup = document.createElement("div");
dateGroup.className = "date-group";
dateGroup.setAttribute("data-date", date);
const header = document.createElement("div");
header.className = "date-group-header";
header.textContent = formatDateHeader(date);
const content = document.createElement("div");
content.className = "date-group-content";
groupedByDate[date].forEach((row) => {
content.appendChild(row);
});
dateGroup.appendChild(header);
dateGroup.appendChild(content);
tableBody.appendChild(dateGroup);
});
setupHomeworkCheckboxes();
}
function removeMobileGroups() {
const tableBody = document.getElementById("homeworkTableBody");
const dateGroups = tableBody.querySelectorAll(".date-group");
if (dateGroups.length === 0) return;
const allRows = [];
dateGroups.forEach((group) => {
const rows = group.querySelectorAll(".table-row");
rows.forEach((row) => allRows.push(row));
});
tableBody.innerHTML = "";
allRows.forEach((row) => tableBody.appendChild(row));
setupHomeworkCheckboxes();
}
function updateDateGroupsVisibility() {
const dateGroups = document.querySelectorAll(".date-group");
dateGroups.forEach((group) => {
const visibleRows = group.querySelectorAll(
'.table-row:not([style*="display: none"])',
);
group.style.display = visibleRows.length > 0 ? "block" : "none";
});
}
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 storage:', error);
return false;
}
}
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 storage:', error);
completedList = [];
}
}
const homeworkIdStr = homeworkId.toString();
if (isCompleted) {
if (!completedList.includes(homeworkIdStr)) {
completedList.push(homeworkIdStr);
}
} else {
completedList = completedList.filter(id => id !== homeworkIdStr);
}
await storageManager.set('completedHomework', JSON.stringify(completedList));
}
function setupHomeworkCheckboxes() {
const checkboxes = document.querySelectorAll('.homework-checkbox');
checkboxes.forEach(checkbox => {
checkbox.addEventListener('change', function() {
const homeworkId = this.getAttribute('data-homework-id');
const isChecked = this.checked;
const row = this.closest('.table-row');
setHomeworkCompletionStatus(homeworkId, isChecked);
if (isChecked) {
row.classList.add('user-completed');
this.title = 'Megcsinált házi - kattints a visszaállításhoz';
} else {
row.classList.remove('user-completed');
this.title = 'Kattints a megjelöléshez';
}
const statusBadge = row.querySelector('.status-badge');
if (statusBadge) {
if (isChecked) {
statusBadge.className = 'status-badge completed';
statusBadge.textContent = LanguageManager.t('homework.completed');
} else {
const isUrgent = row.classList.contains('due-tomorrow');
if (isUrgent) {
statusBadge.className = 'status-badge urgent';
statusBadge.textContent = LanguageManager.t('homework.urgent');
} else {
statusBadge.className = 'status-badge pending';
statusBadge.textContent = LanguageManager.t('homework.pending');
}
}
}
updateStatistics();
});
});
}
if (window.location.href.includes("/Tanulo/TanuloHaziFeladat")) {
transformHomeworkPage().then(() => {
setupHomeworkCheckboxes();
}).catch((error) => {
console.error("Error transforming homework page:", error);
});
}

View File

@@ -76,6 +76,7 @@
"average": "Average",
"chart_title": "Grades",
"semester_evaluations": "Semester evaluations",
"year_end_evaluations": "End of year tickets",
"semester_average": "Semester average",
"no_grades": "No grades",
"september": "September",
@@ -114,7 +115,37 @@
"wednesday": "Wednesday",
"thursday": "Thursday",
"friday": "Friday",
"found_current_week": "Found current week"
"found_current_week": "Found current week",
"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",
@@ -132,7 +163,15 @@
"no_filtered_homework": "No homework matching the filter criteria.",
"teacher": "Teacher",
"no_matching_homework": "No homework matching the filter criteria.",
"items": "items"
"items": "items",
"status": "Status",
"total_homework": "Total homework",
"urgent_homework": "Urgent homework",
"completed_homework": "Completed homework",
"pending_homework": "Pending homework",
"completed": "Completed",
"urgent": "Urgent",
"pending": "Pending"
},
"absences": {
"title": "Absences",
@@ -154,7 +193,10 @@
"current_month": "Current month",
"last_month": "Last month",
"current_semester": "Current semester",
"last_30_days": "Last 30 days"
"last_30_days": "Last 30 days",
"total_absences": "Total absences",
"topic": "Topic",
"status": "Status"
},
"profile": {
"title": "Profile",
@@ -337,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,7 +75,9 @@
"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",
"no_grades": "Nincsenek jegyek",
"september": "Szeptember",
@@ -114,25 +116,63 @@
"wednesday": "Szerda",
"thursday": "Csütörtök",
"friday": "Péntek",
"found_current_week": "Megtalált jelenlegi hét"
"found_current_week": "Megtalált jelenlegi hét",
"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",
"due_date": "Határidő",
"subject": "Tantárgy",
"description": "Leírás",
"filter_title": "Szűrés",
"all_subjects": "Összes tantárgy",
"all_teachers": "Összes tanár",
"all_deadlines": "Összes határidő",
"filter_title": "Szűrő",
"all_subjects": "Minden tantárgy",
"all_teachers": "Minden tanár",
"all_deadlines": "Minden határidő",
"tomorrow_deadline": "Holnapi határidő",
"this_week": "Ezen a héten",
"next_week": "Jövő héten",
"next_week": "Következő héten",
"no_homework": "Nincs megjeleníthető házi feladat.",
"no_filtered_homework": "Nincs a szűrési feltételeknek megfelelő házi feladat.",
"teacher": "Tanár",
"no_matching_homework": "Nincs a szűrési feltételeknek megfelelő házi feladat.",
"items": "feladat"
"items": "elem",
"status": "Állapot",
"total_homework": "Összes feladat",
"urgent_homework": "Sürgős feladat",
"completed_homework": "Befejezett feladat",
"pending_homework": "Függőben lévő feladat",
"completed": "Befejezve",
"urgent": "Sürgős",
"pending": "Függőben"
},
"absences": {
"title": "Hiányzások",
@@ -154,7 +194,10 @@
"current_month": "Aktuális hónap",
"last_month": "Előző hónap",
"current_semester": "Aktuális félév",
"last_30_days": "Utolsó 30 nap"
"last_30_days": "Utolsó 30 nap",
"total_absences": "Összes hiányzás",
"topic": "Téma",
"status": "Állapot"
},
"profile": {
"title": "Profil",
@@ -294,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.",
@@ -339,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"
}
}

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="M15 19h4m0 0v-4m0 4l-4-4M9 5H5m0 0v4m0-4l4 4m6-4h4m0 0v4m0-4l-4 4M9 19H5m0 0v-4m0 4l4-4"/></svg>

After

Width:  |  Height:  |  Size: 283 B

1
icons/BadgeCheck.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-rule="evenodd" clip-rule="evenodd" d="M10.054 2.344a3 3 0 0 1 3.892 0l1.271 1.084a1 1 0 0 0 .57.236l1.665.133a3 3 0 0 1 2.751 2.751l.133 1.666a1 1 0 0 0 .236.569l1.084 1.271a3 3 0 0 1 0 3.892l-1.084 1.271a1 1 0 0 0-.236.57l-.133 1.665a3 3 0 0 1-2.751 2.751l-1.666.133a1 1 0 0 0-.569.236l-1.271 1.084a3 3 0 0 1-3.892 0l-1.271-1.084a1 1 0 0 0-.57-.236l-1.665-.133a3 3 0 0 1-2.751-2.751l-.133-1.666a1 1 0 0 0-.236-.569l-1.084-1.271a3 3 0 0 1 0-3.892l1.084-1.271a1 1 0 0 0 .236-.57l.133-1.665a3 3 0 0 1 2.751-2.751l1.666-.133a1 1 0 0 0 .569-.236l1.271-1.084zm5.653 8.363a1 1 0 0 0-1.414-1.414L11 12.586l-1.293-1.293a1 1 0 0 0-1.414 1.414l2 2a1 1 0 0 0 1.414 0l4-4z" fill="#A7DC22"/></g></svg>

After

Width:  |  Height:  |  Size: 799 B

1
icons/Calendar.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="M4 7v2h16V7a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2"/><path stroke="#A7DC22" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 5h2a2 2 0 0 1 2 2v2H4V7a2 2 0 0 1 2-2h2m8 0V3m0 2H8m0-2v2M4 9.5V19a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9.5"/></g></svg>

After

Width:  |  Height:  |  Size: 376 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 24 24"><path fill="#A7DC22" fill-rule="evenodd" d="M12 21a9 9 0 1 0 0-18a9 9 0 0 0 0 18m1.707-11.293a1 1 0 0 0-1.414-1.414l-3 3a1 1 0 0 0 0 1.414l3 3a1 1 0 0 0 1.414-1.414L11.414 12z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 289 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 24 24"><path fill="#A7DC22" fill-rule="evenodd" d="M12 21a9 9 0 1 0 0-18a9 9 0 0 0 0 18M10.293 9.707a1 1 0 1 1 1.414-1.414l3 3a1 1 0 0 1 0 1.414l-3 3a1 1 0 0 1-1.414-1.414L12.586 12z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 289 B

1
icons/CloseCircle.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-rule="evenodd" clip-rule="evenodd" d="M2 12C2 6.477 6.477 2 12 2s10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12zm8.207-3.207a1 1 0 0 0-1.414 1.414L10.586 12l-1.793 1.793a1 1 0 1 0 1.414 1.414L12 13.414l1.793 1.793a1 1 0 0 0 1.414-1.414L13.414 12l1.793-1.793a1 1 0 0 0-1.414-1.414L12 10.586l-1.793-1.793z" fill="#A7DC22"/></g></svg>

After

Width:  |  Height:  |  Size: 440 B

1
icons/Subject.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-rule="evenodd" clip-rule="evenodd" d="M11.514 3.126a1 1 0 0 1 .972 0l9 5A1 1 0 0 1 22 9v7a1 1 0 1 1-2 0v-5.3l-1 .555v.004l-6.067 3.016a2 2 0 0 1-1.848-.035L2.357 9.479a1 1 0 0 0-.284-.103a1 1 0 0 1 .441-1.25l9-5zM5 13.199V17a1 1 0 0 0 .553.894l6 3a1 1 0 0 0 .894 0l6-3A1 1 0 0 0 19 17v-3.256l-6.083 2.844a2 2 0 0 1-1.805-.056L5 13.2z" fill="#A7DC22"/></g></svg>

After

Width:  |  Height:  |  Size: 472 B

1
icons/assigment.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 stroke="#FFA046" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 8H9m2 4H9"/><path fill="#FFA046" d="M3 16h8c0 1.333.8 4 4 4a3 3 0 0 0 3-3V4h1a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2h-1v7a3 3 0 0 1-3 3H5a2 2 0 0 1-2-2z"/><path stroke="#FFA046" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 20c-3.2 0-4-2.667-4-4H3v2a2 2 0 0 0 2 2zm0 0a3 3 0 0 0 3-3v-7m0-6H7a2 2 0 0 0-2 2v9.5M18 4h1a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2h-1m0-6v6"/></g></svg>

After

Width:  |  Height:  |  Size: 578 B

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/homework.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-rule="evenodd" clip-rule="evenodd" d="M15.586 3a2 2 0 0 1 2.828 0L21 5.586a2 2 0 0 1 0 2.828L19.414 10L14 4.586L15.586 3zm-3 3l-9 9A2 2 0 0 0 3 16.414V19a2 2 0 0 0 2 2h2.586A2 2 0 0 0 9 20.414l9-9L12.586 6z" fill="#A7DC22"/></g></svg>

After

Width:  |  Height:  |  Size: 345 B

1
icons/pipa.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="#A7DC22"><path d="M19.707 6.293a1 1 0 0 1 0 1.414l-10 10a1 1 0 0 1-1.414 0l-4-4a1 1 0 1 1 1.414-1.414L9 15.586l9.293-9.293a1 1 0 0 1 1.414 0z"/></g></svg>

After

Width:  |  Height:  |  Size: 248 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,360 +1,313 @@
:root {
--icon-invert: 0.1;
--icon-sepia: 0.1;
--icon-saturate: 0.1;
--icon-hue-rotate: 0deg;
--icon-brightness: 0.1;
--icon-invert:0.1;
--icon-sepia:0.1;
--icon-saturate:0.1;
--icon-hue-rotate:0deg;
--icon-brightness:0.1;
}
:root[data-theme="light-green"] {
--icon-invert: 0.1;
--icon-sepia: 0.1;
--icon-saturate: 0.1;
--icon-hue-rotate: 0deg;
--icon-brightness: 0.1;
--icon-invert:0.1;
--icon-sepia:0.1;
--icon-saturate:0.1;
--icon-hue-rotate:0deg;
--icon-brightness:0.1;
}
:root[data-theme="dark-blue"] {
--icon-invert: 0.9;
--icon-sepia: 0.1;
--icon-saturate: 0.1;
--icon-hue-rotate: 0deg;
--icon-brightness: 1;
--icon-invert:0.9;
--icon-sepia:0.1;
--icon-saturate:0.1;
--icon-hue-rotate:0deg;
--icon-brightness:1;
}
:root[data-theme="dark-green"] {
--icon-invert: 0.9;
--icon-sepia: 0.1;
--icon-saturate: 0.1;
--icon-hue-rotate: 0deg;
--icon-brightness: 1;
--icon-invert:0.9;
--icon-sepia:0.1;
--icon-saturate:0.1;
--icon-hue-rotate:0deg;
--icon-brightness:1;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
box-sizing:border-box;
margin:0;
padding:0;
}
body {
margin: 0;
padding: 0;
color: var(--text-primary);
background-color: var(--background) !important;
font-family: "Montserrat", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
min-height: 100vh;
font-size: 16px;
display: flex;
align-items: center;
justify-content: center;
margin:0;
padding:0;
color:var(--text-primary);
background-color:var(--background) !important;
font-family:"Montserrat",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif !important;
min-height:100vh;
font-size:16px;
display:flex;
align-items:center;
justify-content:center;
}
.login-container {
width: 90%;
max-width: 500px;
padding: 20px;
margin: 0 auto;
width:90%;
max-width:500px;
padding:20px;
margin:0 auto;
}
.login-card {
background: var(--card-card);
padding: 24px;
margin-bottom: 16px;
border-radius: 24px;
box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow);
background:var(--card-card);
padding:24px;
margin-bottom:16px;
border-radius:24px;
box-shadow:0px 1px var(--shadow-blur) 0px var(--accent-shadow);
}
.card-header {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
margin: 16px 0;
background: var(--card-card) !important;
border-bottom: 1px solid rgba(0, 0, 0, 0) !important;
display:flex;
flex-direction:column;
align-items:center;
gap:8px;
margin:16px 0;
background:var(--card-card) !important;
border-bottom:1px solid rgba(0,0,0,0) !important;
}
.logo-text {
color: var(--text-primary);
text-align: center;
font-family: Montserrat;
font-size: 20px;
font-style: normal;
font-weight: 700;
line-height: normal;
color:var(--text-primary);
text-align:center;
font-family:Montserrat;
font-size:20px;
font-style:normal;
font-weight:700;
line-height:normal;
}
.logo {
width: 48px;
height: 48px;
border-radius: 12px;
width:48px;
height:48px;
border-radius:12px;
}
.school-name {
color: var(--text-secondary);
text-align: center;
font-family: Figtree;
font-size: 16px;
font-style: normal;
font-weight: 500;
line-height: 130%;
color:var(--text-secondary);
text-align:center;
font-family:Figtree;
font-size:16px;
font-style:normal;
font-weight:500;
line-height:130%;
}
.school-details {
color: var(--text-secondary);
text-align: center;
font-family: Figtree;
font-size: 16px;
font-style: normal;
font-weight: 500;
line-height: 130%;
color:var(--text-secondary);
text-align:center;
font-family:Figtree;
font-size:16px;
font-style:normal;
font-weight:500;
line-height:130%;
}
.login-form {
width: 100%;
width:100%;
}
.form-group {
margin-bottom: 16px;
margin-bottom:16px;
}
.form-control {
display: flex;
height: 48px;
padding: 0px 14px;
align-items: center;
gap: 10px;
align-self: stretch;
border-radius: 12px;
background: var(--accent-15) !important;
border: 0px solid var(--accent-15) !important;
color: var(--text-primary) !important;
display:flex;
height:48px;
padding:0px 14px;
align-items:center;
gap:10px;
align-self:stretch;
border-radius:12px;
background:var(--accent-15) !important;
border:0px solid var(--accent-15) !important;
color:var(--text-primary) !important;
}
.form-control:focus {
outline: none;
border-color: var(--accent-accent) !important;
outline:none;
border-color:var(--accent-accent) !important;
}
.form-control::placeholder {
color: var(--text-secondary) !important;
color:var(--text-secondary) !important;
}
.password-group {
position: relative;
position:relative;
}
.show-password {
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
background: none;
border: none;
padding: 4px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
position:absolute;
right:12px;
top:50%;
transform:translateY(-50%);
background:none;
border:none;
padding:4px;
cursor:pointer;
display:flex;
align-items:center;
justify-content:center;
}
.icon-eye {
width: 20px;
height: 20px;
opacity: 0.6;
transition: opacity 0.2s ease;
filter: invert(var(--icon-invert)) sepia(var(--icon-sepia)) saturate(var(--icon-saturate)) hue-rotate(var(--icon-hue-rotate)) brightness(var(--icon-brightness));
width:20px;
height:20px;
opacity:0.6;
transition:opacity 0.2s ease;
filter:invert(var(--icon-invert)) sepia(var(--icon-sepia)) saturate(var(--icon-saturate)) hue-rotate(var(--icon-hue-rotate)) brightness(var(--icon-brightness));
}
.show-password:hover .icon-eye {
opacity: 1;
opacity:1;
}
.form-actions {
margin-top: 24px;
margin-top:24px;
}
.help-links {
margin-top: 16px;
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
margin-top:16px;
display:flex;
flex-direction:column;
align-items:center;
gap:8px;
}
.help-link {
color: var(--text-primary);
font-size: 14px;
font-weight: 500;
text-decoration: none;
transition: color 0.2s ease;
color:var(--text-primary);
font-size:14px;
font-weight:500;
text-decoration:none;
transition:color 0.2s ease;
}
.help-link:hover {
color: var(--text-teritary);
color:var(--text-teritary);
}
.btn-login {
width: 100%;
padding: 12px;
background: var(--accent-accent);
color: white;
border: none;
border-radius: 12px;
font-size: 16px;
font-weight: 600;
font-family: "Montserrat", serif;
cursor: pointer;
transition: background 0.2s ease;
position: relative;
width:100%;
padding:12px;
background:var(--accent-accent);
color:white;
border:none;
border-radius:12px;
font-size:16px;
font-weight:600;
font-family:"Montserrat",serif;
cursor:pointer;
transition:background 0.2s ease;
position:relative;
}
.btn-login:hover {
background: var(--text-teritary);
background:var(--text-teritary);
}
.btn-login:disabled {
opacity: 0.7;
cursor: not-allowed;
opacity:0.7;
cursor:not-allowed;
}
.btn-text {
color: var(--text-primary);
text-align: center;
font-family: Montserrat;
font-size: 18px;
font-style: normal;
font-weight: 700;
line-height: normal;
letter-spacing: -0.3px;
color:var(--text-primary);
text-align:center;
font-family:Montserrat;
font-size:18px;
font-style:normal;
font-weight:700;
line-height:normal;
letter-spacing:-0.3px;
}
.system-message {
display: flex;
padding: 20px;
flex-direction: column;
align-items: center;
gap: 12px;
align-self: stretch;
border-radius: 24px;
background: var(--card-card);
box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow);
display:flex;
padding:20px;
flex-direction:column;
align-items:center;
gap:12px;
align-self:stretch;
border-radius:24px;
background:var(--card-card);
box-shadow:0px 1px var(--shadow-blur) 0px var(--accent-shadow);
}
.system-message h4 {
color: var(--text-primary);
text-align: center;
font-family: Montserrat;
font-size: 20px;
font-style: normal;
font-weight: 700;
line-height: normal;
color:var(--text-primary);
text-align:center;
font-family:Montserrat;
font-size:20px;
font-style:normal;
font-weight:700;
line-height:normal;
}
.system-message p {
color: var(--text-secondary);
text-align: center;
font-family: Figtree;
font-size: 16px;
font-style: normal;
font-weight: 500;
line-height: 130%;
color:var(--text-secondary);
text-align:center;
font-family:Figtree;
font-size:16px;
font-style:normal;
font-weight:500;
line-height:130%;
}
.login-footer {
align-self: stretch;
color: var(--text-secondary);
text-align: center;
font-family: Figtree;
font-size: 14px;
font-style: normal;
font-weight: 500;
line-height: 130%;
align-self:stretch;
color:var(--text-secondary);
text-align:center;
font-family:Figtree;
font-size:14px;
font-style:normal;
font-weight:500;
line-height:130%;
}
.privacy-link {
align-self: stretch;
color: var(--text-secondary);
text-align: center;
font-family: Figtree;
font-size: 14px;
font-style: normal;
font-weight: 500;
line-height: 130%;
text-decoration: none;
align-self:stretch;
color:var(--text-secondary);
text-align:center;
font-family:Figtree;
font-size:14px;
font-style:normal;
font-weight:500;
line-height:130%;
text-decoration:none;
}
.privacy-link:hover {
color: var(--text-teritary);
color:var(--text-teritary);
}
.form-control.error {
border-color: var(--error-accent) !important;
background: var(--error-card) !important;
border-color:var(--error-accent) !important;
background:var(--error-card) !important;
}
.error-message {
color: var(--error-text);
font-size: 14px;
margin-top: 4px;
display: none;
color:var(--error-text);
font-size:14px;
margin-top:4px;
display:none;
}
.error-message.show {
display: block;
animation: fadeIn 0.2s ease;
display:block;
animation:fadeIn 0.2s ease;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(-4px); }
to { opacity: 1; transform: translateY(0); }
from {
opacity:0;
transform:translateY(-4px);
}
@keyframes spin {
to { transform: translate(-50%, -50%) rotate(360deg); }
to {
opacity:1;
transform:translateY(0);
}
@media (max-width: 480px) {
}@keyframes spin {
to {
transform:translate(-50%,-50%) rotate(360deg);
}
}@media (max-width:480px) {
.login-container {
padding: 16px;
}
.login-card {
padding: 20px;
}
.card-header {
margin-bottom: 20px;
padding-bottom: 16px;
}
.logo-text {
font-size: 20px;
}
.school-name {
font-size: 16px;
}
.school-details {
font-size: 12px;
}
.form-control {
height: 44px;
font-size: 14px;
}
.btn-login {
padding: 10px;
font-size: 14px;
}
.help-link {
font-size: 12px;
}
padding:16px;
}
.login-card {
padding:20px;
}
.card-header {
margin-bottom:20px;
padding-bottom:16px;
}
.logo-text {
font-size:20px;
}
.school-name {
font-size:16px;
}
.school-details {
font-size:12px;
}
.form-control {
height:44px;
font-size:14px;
}
.btn-login {
padding:10px;
font-size:14px;
}
.help-link {
font-size:12px;
}
}

View File

@@ -1,50 +1,59 @@
async function transformLoginPage() {
try {
if (document.readyState !== 'complete') {
await new Promise(resolve => {
window.addEventListener('load', resolve);
if (document.readyState !== "complete") {
await new Promise((resolve) => {
window.addEventListener("load", resolve);
});
}
const existingForm = document.querySelector('form');
const existingForm = document.querySelector("form");
const formData = {
action: existingForm?.getAttribute('action') || '',
returnUrl: document.querySelector('#ReturnUrl')?.value || '',
instituteCode: document.querySelector('#instituteCode')?.value || '',
requestToken: document.querySelector('input[name="__RequestVerificationToken"]')?.value || '',
userName: document.querySelector('#UserName')?.value || '',
password: document.querySelector('#Password')?.value || ''
action: existingForm?.getAttribute("action") || "",
returnUrl: document.querySelector("#ReturnUrl")?.value || "",
instituteCode: document.querySelector("#instituteCode")?.value || "",
requestToken:
document.querySelector('input[name="__RequestVerificationToken"]')
?.value || "",
userName: document.querySelector("#UserName")?.value || "",
password: document.querySelector("#Password")?.value || "",
};
const titleElement = document.querySelector('.page-title');
const titleElement = document.querySelector(".page-title");
const schoolInfo = {
name: titleElement?.querySelector('b')?.textContent?.trim() || '',
kretaId: '',
omCode: ''
name: titleElement?.querySelector("b")?.textContent?.trim() || "",
kretaId: "",
omCode: "",
};
const spanElement = titleElement?.querySelector('span');
const spanElement = titleElement?.querySelector("span");
if (spanElement) {
const lines = spanElement.textContent?.split('\n').map(line => line.trim()) || [];
schoolInfo.kretaId = lines[0] || '';
schoolInfo.omCode = (lines[1] || '').replace(`${LanguageManager.t('login.kreta_id')}: `, '');
const lines =
spanElement.textContent?.split("\n").map((line) => line.trim()) || [];
schoolInfo.kretaId = lines[0] || "";
schoolInfo.omCode = (lines[1] || "").replace(
`${LanguageManager.t("login.kreta_id")}: `,
"",
);
}
const rawSystemMessage = document.querySelector('.alert-primary')?.textContent?.trim() || '';
const systemMessage = rawSystemMessage.replace('Rendszerértesítés', '').trim();
const rawSystemMessage =
document.querySelector(".alert-primary")?.textContent?.trim() || "";
const systemMessage = rawSystemMessage
.replace("Rendszerértesítés", "")
.trim();
const newHTML = `
<div class="login-container">
<div class="login-card">
<div class="card-header">
<p class="logo-text">
<img src=${chrome.runtime.getURL('images/firka_logo.png')} alt="Firka" class="logo">
<img src=${chrome.runtime.getURL("images/firka_logo.png")} alt="Firka" class="logo">
Firka
</p>
<h1 class="school-name">${schoolInfo.name}</h1>
<div class="school-details">
${schoolInfo.kretaId ? `<div>${schoolInfo.kretaId}</div>` : ''}
${schoolInfo.omCode ? `<div>${LanguageManager.t('login.kreta_id')}: ${schoolInfo.omCode}</div>` : ''}
${schoolInfo.kretaId ? `<div>${schoolInfo.kretaId}</div>` : ""}
${schoolInfo.omCode ? `<div>${LanguageManager.t("login.kreta_id")}: ${schoolInfo.omCode}</div>` : ""}
</div>
</div>
@@ -57,133 +66,136 @@ async function transformLoginPage() {
<div class="form-group">
<input class="form-control" type="text" id="UserName" name="UserName"
placeholder="${LanguageManager.t('login.username_placeholder')}" maxlength="256" autocomplete="username" required value="${formData.userName}">
<div class="error-message">${LanguageManager.t('login.username_required')}</div>
placeholder="${LanguageManager.t("login.username_placeholder")}" maxlength="256" autocomplete="username" required value="${formData.userName}">
<div class="error-message">${LanguageManager.t("login.username_required")}</div>
</div>
<div class="form-group password-group">
<input class="form-control" type="password" id="Password" name="Password"
placeholder="${LanguageManager.t('login.password_placeholder')}" maxlength="256" autocomplete="current-password" required value="${formData.password}">
<button type="button" class="show-password" aria-label="${LanguageManager.t('login.show_password')}">
<img src="${chrome.runtime.getURL('icons/eye-off.svg')}" alt="Show password" class="icon-eye">
placeholder="${LanguageManager.t("login.password_placeholder")}" maxlength="256" autocomplete="current-password" required value="${formData.password}">
<button type="button" class="show-password" aria-label="${LanguageManager.t("login.show_password")}">
<img src="${chrome.runtime.getURL("icons/eye-off.svg")}" alt="Show password" class="icon-eye">
</button>
<div class="error-message">${LanguageManager.t('login.password_required')}</div>
<div class="error-message">${LanguageManager.t("login.password_required")}</div>
</div>
<div class="form-actions">
<button type="submit" class="btn-login">
<span class="spinner"></span>
<span class="btn-text">${LanguageManager.t('login.login_button')}</span>
<span class="btn-text">${LanguageManager.t("login.login_button")}</span>
</button>
<div class="help-links">
<a href="https://${schoolInfo.omCode ? `${schoolInfo.omCode}` : ''}.e-kreta.hu/Adminisztracio/ElfelejtettJelszo" class="help-link">${LanguageManager.t('login.forgot_password')}</a>
<a href="https://tudasbazis.ekreta.hu/pages/viewpage.action?pageId=2425086" target="_blank" class="help-link">${LanguageManager.t('login.help_link')}</a>
<a href="https://${schoolInfo.omCode ? `${schoolInfo.omCode}` : ""}.e-kreta.hu/Adminisztracio/ElfelejtettJelszo" class="help-link">${LanguageManager.t("login.forgot_password")}</a>
<a href="https://tudasbazis.ekreta.hu/pages/viewpage.action?pageId=2425086" target="_blank" class="help-link">${LanguageManager.t("login.help_link")}</a>
</div>
</div>
</form>
</div>
${systemMessage ? `
${
systemMessage
? `
<div class="system-message">
<h4>${LanguageManager.t('login.system_message')}</h4>
<h4>${LanguageManager.t("login.system_message")}</h4>
<p>${systemMessage}</p>
</div>
` : ''}
`
: ""
}
<footer class="login-footer">
<a href="https://tudasbazis.ekreta.hu/pages/viewpage.action?pageId=4064926"
target="_blank" class="privacy-link">${LanguageManager.t('login.privacy_policy')}</a>
target="_blank" class="privacy-link">${LanguageManager.t("login.privacy_policy")}</a>
</footer>
</div>
`;
document.body.innerHTML = newHTML;
setupEventListeners();
document.body.innerHTML = '';
const parser = new DOMParser();
const doc = parser.parseFromString(newHTML, 'text/html');
const tempDiv = doc.body;
while (tempDiv.firstChild) {
document.body.appendChild(tempDiv.firstChild);
}
setupEventListeners();
} catch (error) {
console.error('Error transforming page:', error);
console.error("Error transforming page:", error);
}
}
function setupEventListeners() {
const loginForm = document.getElementById('loginForm');
const passwordInput = document.getElementById('Password');
const togglePasswordBtn = document.querySelector('.show-password');
const formInputs = document.querySelectorAll('.form-control');
if (togglePasswordBtn && passwordInput) {
togglePasswordBtn.addEventListener('click', () => {
const isPassword = passwordInput.type === 'password';
passwordInput.type = isPassword ? 'text' : 'password';
const icon = togglePasswordBtn.querySelector('.icon-eye');
icon.src = chrome.runtime.getURL(`icons/${isPassword ? 'eye-on' : 'eye-off'}.svg`);
});
}
const loginForm = document.getElementById("loginForm");
const passwordInput = document.getElementById("Password");
const togglePasswordBtn = document.querySelector(".show-password");
const formInputs = document.querySelectorAll(".form-control");
formInputs.forEach(input => {
input.addEventListener('input', () => {
if (togglePasswordBtn && passwordInput) {
togglePasswordBtn.addEventListener("click", () => {
const isPassword = passwordInput.type === "password";
passwordInput.type = isPassword ? "text" : "password";
const icon = togglePasswordBtn.querySelector(".icon-eye");
icon.src = chrome.runtime.getURL(
`icons/${isPassword ? "eye-on" : "eye-off"}.svg`,
);
});
}
formInputs.forEach((input) => {
input.addEventListener("input", () => {
validateInput(input);
});
input.addEventListener('blur', () => {
input.addEventListener("blur", () => {
validateInput(input, true);
});
});
if (loginForm) {
loginForm.addEventListener('submit', handleSubmit);
loginForm.addEventListener("submit", handleSubmit);
}
}
function validateInput(input, showError = false) {
const isValid = input.value.trim().length > 0;
const errorElement = input.nextElementSibling;
if (!isValid && showError) {
input.classList.add('error');
errorElement?.classList.add('show');
input.classList.add("error");
errorElement?.classList.add("show");
} else {
input.classList.remove('error');
errorElement?.classList.remove('show');
input.classList.remove("error");
errorElement?.classList.remove("show");
}
return isValid;
}
function handleSubmit(event) {
event.preventDefault();
const form = event.target;
const inputs = form.querySelectorAll('.form-control[required]');
const inputs = form.querySelectorAll(".form-control[required]");
let isValid = true;
inputs.forEach(input => {
inputs.forEach((input) => {
if (!validateInput(input, true)) {
isValid = false;
}
});
const submitButton = form.querySelector('.btn-login');
const spinner = submitButton.querySelector('.spinner');
const buttonText = submitButton.querySelector('.btn-text');
const submitButton = form.querySelector(".btn-login");
const spinner = submitButton.querySelector(".spinner");
const buttonText = submitButton.querySelector(".btn-text");
submitButton.disabled = true;
spinner.style.display = 'inline-block';
buttonText.style.opacity = '0';
spinner.style.display = "inline-block";
buttonText.style.opacity = "0";
form.submit();
}
if (window.location.href.includes('idp.e-kreta.hu/Account/Login')) {
transformLoginPage().catch(error => {
console.error('Error:', error);
if (window.location.href.includes("idp.e-kreta.hu/Account/Login")) {
transformLoginPage().catch((error) => {
});
}
}

View File

@@ -1,301 +1,261 @@
:root {
--icon-invert: 0.1;
--icon-sepia: 0.1;
--icon-saturate: 0.1;
--icon-hue-rotate: 0deg;
--icon-brightness: 0.1;
--icon-invert:0.1;
--icon-sepia:0.1;
--icon-saturate:0.1;
--icon-hue-rotate:0deg;
--icon-brightness:0.1;
}
:root[data-theme="light-green"] {
--icon-invert: 0.1;
--icon-sepia: 0.1;
--icon-saturate: 0.1;
--icon-hue-rotate: 0deg;
--icon-brightness: 0.1;
--icon-invert:0.1;
--icon-sepia:0.1;
--icon-saturate:0.1;
--icon-hue-rotate:0deg;
--icon-brightness:0.1;
}
:root[data-theme="dark-blue"] {
--icon-invert: 0.9;
--icon-sepia: 0.1;
--icon-saturate: 0.1;
--icon-hue-rotate: 0deg;
--icon-brightness: 1;
--icon-invert:0.9;
--icon-sepia:0.1;
--icon-saturate:0.1;
--icon-hue-rotate:0deg;
--icon-brightness:1;
}
:root[data-theme="dark-green"] {
--icon-invert: 0.9;
--icon-sepia: 0.1;
--icon-saturate: 0.1;
--icon-hue-rotate: 0deg;
--icon-brightness: 1;
--icon-invert:0.9;
--icon-sepia:0.1;
--icon-saturate:0.1;
--icon-hue-rotate:0deg;
--icon-brightness:1;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
box-sizing:border-box;
margin:0;
padding:0;
}
body {
margin: 0;
padding: 0;
color: var(--text-primary);
background-color: var(--background) !important;
font-family: "Montserrat", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
min-height: 100vh;
font-size: 16px;
display: flex;
align-items: center;
justify-content: center;
margin:0;
padding:0;
color:var(--text-primary);
background-color:var(--background) !important;
font-family:"Montserrat",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif !important;
min-height:100vh;
font-size:16px;
display:flex;
align-items:center;
justify-content:center;
}
.login-container {
width: 90%;
max-width: 500px;
padding: 20px;
margin: 0 auto;
width:90%;
max-width:500px;
padding:20px;
margin:0 auto;
}
.login-card {
background: var(--card-card);
padding: 24px;
margin-bottom: 16px;
border-radius: 24px;
box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow);
background:var(--card-card);
padding:24px;
margin-bottom:16px;
border-radius:24px;
box-shadow:0px 1px var(--shadow-blur) 0px var(--accent-shadow);
}
.card-header {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
margin: 16px 0;
background: var(--card-card) !important;
border-bottom: 1px solid rgba(0, 0, 0, 0) !important;
display:flex;
flex-direction:column;
align-items:center;
gap:8px;
margin:16px 0;
background:var(--card-card) !important;
border-bottom:1px solid rgba(0,0,0,0) !important;
}
.logo-text {
color: var(--text-primary);
text-align: center;
font-family: Montserrat;
font-size: 20px;
font-style: normal;
font-weight: 700;
line-height: normal;
color:var(--text-primary);
text-align:center;
font-family:Montserrat;
font-size:20px;
font-style:normal;
font-weight:700;
line-height:normal;
}
.logo {
width: 48px;
height: 48px;
border-radius: 12px;
width:48px;
height:48px;
border-radius:12px;
}
.twofactor-title {
color: var(--text-primary);
text-align: center;
font-family: Montserrat;
font-size: 24px;
font-style: normal;
font-weight: 600;
line-height: 130%;
margin-bottom: 16px;
color:var(--text-primary);
text-align:center;
font-family:Montserrat;
font-size:24px;
font-style:normal;
font-weight:600;
line-height:130%;
margin-bottom:16px;
}
.twofactor-form {
width: 100%;
width:100%;
}
.form-group {
margin-bottom: 16px;
margin-bottom:16px;
}
.form-control {
display: flex;
height: 48px;
padding: 0px 14px;
align-items: center;
gap: 10px;
align-self: stretch;
border-radius: 12px;
background: var(--accent-15) !important;
border: 0px solid var(--accent-15) !important;
color: var(--text-primary) !important;
display:flex;
height:48px;
padding:0px 14px;
align-items:center;
gap:10px;
align-self:stretch;
border-radius:12px;
background:var(--accent-15) !important;
border:0px solid var(--accent-15) !important;
color:var(--text-primary) !important;
}
.form-control:focus {
outline: none;
border-color: var(--accent-accent) !important;
outline:none;
border-color:var(--accent-accent) !important;
}
.form-control::placeholder {
color: var(--text-secondary) !important;
color:var(--text-secondary) !important;
}
.password-group {
position: relative;
position:relative;
}
.show-password {
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
background: none;
border: none;
padding: 4px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
position:absolute;
right:12px;
top:50%;
transform:translateY(-50%);
background:none;
border:none;
padding:4px;
cursor:pointer;
display:flex;
align-items:center;
justify-content:center;
}
.icon-eye {
width: 20px;
height: 20px;
opacity: 0.6;
transition: opacity 0.2s ease;
filter: invert(var(--icon-invert)) sepia(var(--icon-sepia)) saturate(var(--icon-saturate)) hue-rotate(var(--icon-hue-rotate)) brightness(var(--icon-brightness));
width:20px;
height:20px;
opacity:0.6;
transition:opacity 0.2s ease;
filter:invert(var(--icon-invert)) sepia(var(--icon-sepia)) saturate(var(--icon-saturate)) hue-rotate(var(--icon-hue-rotate)) brightness(var(--icon-brightness));
}
.show-password:hover .icon-eye {
opacity: 1;
opacity:1;
}
.form-check {
display: flex;
align-items: center;
margin-top: 16px;
margin-bottom: 16px;
display:flex;
align-items:center;
margin-top:16px;
margin-bottom:16px;
}
.form-check-input {
width: 20px;
height: 20px;
margin-right: 8px;
border-radius: 6px;
border: 2px solid var(--accent-accent);
background-color: var(--card-card);
cursor: pointer;
width:20px;
height:20px;
margin-right:8px;
border-radius:6px;
border:2px solid var(--accent-accent);
background-color:var(--card-card);
cursor:pointer;
}
.form-check-input:checked {
background-color: var(--accent-accent);
border-color: var(--accent-accent);
background-color:var(--accent-accent);
border-color:var(--accent-accent);
}
.form-check-label {
color: var(--text-primary);
font-family: Figtree;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 130%;
cursor: pointer;
color:var(--text-primary);
font-family:Figtree;
font-size:14px;
font-style:normal;
font-weight:400;
line-height:130%;
cursor:pointer;
}
.btn-kreta {
display: flex;
height: 48px;
padding: 0px 24px;
justify-content: center;
align-items: center;
gap: 8px;
border-radius: 12px;
background: var(--accent-accent);
color: white;
font-family: Montserrat;
font-size: 16px;
font-style: normal;
font-weight: 600;
line-height: normal;
border: none;
cursor: pointer;
transition: background-color 0.2s ease;
display:flex;
height:48px;
padding:0px 24px;
justify-content:center;
align-items:center;
gap:8px;
border-radius:12px;
background:var(--accent-accent);
color:white;
font-family:Montserrat;
font-size:16px;
font-style:normal;
font-weight:600;
line-height:normal;
border:none;
cursor:pointer;
transition:background-color 0.2s ease;
}
.btn-kreta:hover {
background-color: var(--accent-secondary);
background-color:var(--accent-secondary);
}
.btn-link {
background: none;
border: none;
color: var(--accent-accent);
font-family: Figtree;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 130%;
text-decoration: underline;
cursor: pointer;
padding: 0;
background:none;
border:none;
color:var(--accent-accent);
font-family:Figtree;
font-size:14px;
font-style:normal;
font-weight:400;
line-height:130%;
text-decoration:underline;
cursor:pointer;
padding:0;
}
.btn-link:hover {
color: var(--accent-secondary);
color:var(--accent-secondary);
}
.subtext {
color: var(--text-primary);
font-family: Figtree;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 130%;
text-align: center;
color:var(--text-primary);
font-family:Figtree;
font-size:14px;
font-style:normal;
font-weight:400;
line-height:130%;
text-align:center;
}
.login-footer {
margin-top: 24px;
text-align: center;
margin-top:24px;
text-align:center;
}
.privacy-link {
color: var(--text-secondary);
font-family: Figtree;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 130%;
text-decoration: none;
color:var(--text-secondary);
font-family:Figtree;
font-size:14px;
font-style:normal;
font-weight:400;
line-height:130%;
text-decoration:none;
}
.privacy-link:hover {
text-decoration: underline;
text-decoration:underline;
}
.error-message {
display: none;
color: var(--error-text);
font-family: Figtree;
font-size: 12px;
font-style: normal;
font-weight: 400;
line-height: 130%;
margin-top: 4px;
display:none;
color:var(--error-text);
font-family:Figtree;
font-size:12px;
font-style:normal;
font-weight:400;
line-height:130%;
margin-top:4px;
}
.error-message.show {
display: block;
display:block;
}
.form-control.error {
border: 1px solid var(--error-accent) !important;
border:1px solid var(--error-accent) !important;
}
/* Hide original elements */
header, main > .container-fluid, footer {
display: none !important;
header,main > .container-fluid,footer {
display:none !important;
}
/* Responsive adjustments */
@media (max-width: 576px) {
@media (max-width:576px) {
.login-container {
width: 100%;
padding: 16px;
}
.login-card {
padding: 16px;
}
width:100%;
padding:16px;
}
.login-card {
padding:16px;
}
}

View File

@@ -1,35 +1,40 @@
async function transformTwoFactorPage() {
try {
if (document.readyState !== 'complete') {
await new Promise(resolve => {
window.addEventListener('load', resolve);
if (document.readyState !== "complete") {
await new Promise((resolve) => {
window.addEventListener("load", resolve);
});
}
if (typeof loadingScreen !== 'undefined') {
if (typeof loadingScreen !== "undefined") {
loadingScreen.show();
}
const existingForm = document.querySelector('form');
const existingForm = document.querySelector("form");
const formData = {
action: existingForm?.getAttribute('action') || '',
clientId: document.querySelector('#ClientId')?.value || '',
rememberLogin: document.querySelector('#RememberLogin')?.value || 'False',
returnUrl: document.querySelector('#ReturnUrl')?.value || '',
isRecoveryCode: document.querySelector('#IsRecoveryCode')?.value || 'False',
requestToken: document.querySelector('input[name="__RequestVerificationToken"]')?.value || '',
trustDeviceValue: document.querySelector('input[name="TrustDevice"][type="hidden"]')?.value || 'false'
action: existingForm?.getAttribute("action") || "",
clientId: document.querySelector("#ClientId")?.value || "",
rememberLogin: document.querySelector("#RememberLogin")?.value || "False",
returnUrl: document.querySelector("#ReturnUrl")?.value || "",
isRecoveryCode:
document.querySelector("#IsRecoveryCode")?.value || "False",
requestToken:
document.querySelector('input[name="__RequestVerificationToken"]')
?.value || "",
trustDeviceValue:
document.querySelector('input[name="TrustDevice"][type="hidden"]')
?.value || "false",
};
const newHTML = `
<div class="login-container">
<div class="login-card">
<div class="card-header">
<p class="logo-text">
<img src=${chrome.runtime.getURL('images/firka_logo.png')} alt="Firka" class="logo">
<img src=${chrome.runtime.getURL("images/firka_logo.png")} alt="Firka" class="logo">
Firka
</p>
<h1 class="twofactor-title">${LanguageManager.t('twofactor.title')}</h1>
<h1 class="twofactor-title">${LanguageManager.t("twofactor.title")}</h1>
</div>
<form class="twofactor-form" action="${formData.action}" method="post" id="twoFactorForm">
@@ -41,30 +46,30 @@ async function transformTwoFactorPage() {
<div class="form-group password-group">
<input class="form-control" type="password" id="VerificationCode" name="VerificationCode"
placeholder="${LanguageManager.t('twofactor.code_placeholder')}" maxlength="256" autocomplete="off" required autofocus>
<button type="button" class="show-password" aria-label="${LanguageManager.t('twofactor.show_code')}">
<img src="${chrome.runtime.getURL('icons/eye-off.svg')}" alt="Show password" class="icon-eye">
placeholder="${LanguageManager.t("twofactor.code_placeholder")}" maxlength="256" autocomplete="off" required autofocus>
<button type="button" class="show-password" aria-label="${LanguageManager.t("twofactor.show_code")}">
<img src="${chrome.runtime.getURL("icons/eye-off.svg")}" alt="Show password" class="icon-eye">
</button>
<div class="error-message">${LanguageManager.t('twofactor.code_required')}</div>
<div class="error-message">${LanguageManager.t("twofactor.code_required")}</div>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="trustDevice" name="TrustDevice" value="true">
<label class="form-check-label" for="trustDevice">
${LanguageManager.t('twofactor.trust_device')}
${LanguageManager.t("twofactor.trust_device")}
</label>
<input name="TrustDevice" type="hidden" value="false">
</div>
<div class="d-flex justify-content-center mb-3 mt-4">
<button type="submit" class="btn-kreta">${LanguageManager.t('twofactor.verify_button')}</button>
<button type="submit" class="btn-kreta">${LanguageManager.t("twofactor.verify_button")}</button>
</div>
<div class="d-flex justify-content-center mt-3">
<span class="subtext">
${LanguageManager.t('twofactor.no_access')}
${LanguageManager.t("twofactor.no_access")}
<button type="submit" class="btn-link" formaction="/account/loginwithrecoverycode">
${LanguageManager.t('twofactor.recovery_code')}
${LanguageManager.t("twofactor.recovery_code")}
</button>
</span>
</div>
@@ -73,21 +78,25 @@ async function transformTwoFactorPage() {
<footer class="login-footer">
<a href="https://tudasbazis.ekreta.hu/pages/viewpage.action?pageId=4064926"
target="_blank" class="privacy-link">${LanguageManager.t('login.privacy_policy')}</a>
target="_blank" class="privacy-link">${LanguageManager.t("login.privacy_policy")}</a>
</footer>
</div>
`;
document.body.innerHTML = newHTML;
document.body.innerHTML = '';
const parser = new DOMParser();
const doc = parser.parseFromString(newHTML, 'text/html');
const tempDiv = doc.body;
while (tempDiv.firstChild) {
document.body.appendChild(tempDiv.firstChild);
}
applyTheme();
setupEventListeners();
if (typeof loadingScreen !== 'undefined') {
if (typeof loadingScreen !== "undefined") {
loadingScreen.hide();
}
} catch (error) {
console.error('Error transforming two-factor page:', error);
if (typeof loadingScreen !== 'undefined') {
if (typeof loadingScreen !== "undefined") {
loadingScreen.hide();
}
}
@@ -95,77 +104,85 @@ async function transformTwoFactorPage() {
function applyTheme() {
try {
if (typeof getCookie === 'function') {
const theme = getCookie('theme') || 'light-blue';
document.documentElement.setAttribute('data-theme', theme);
if (typeof getCookie === "function") {
const theme = getCookie("theme") || "light-blue";
document.documentElement.setAttribute("data-theme", theme);
}
} catch (error) {
console.error('Error applying theme:', error);
}
}
function setupEventListeners() {
const twoFactorForm = document.getElementById('twoFactorForm');
const verificationInput = document.getElementById('VerificationCode');
const togglePasswordBtn = document.querySelector('.show-password');
const formInputs = document.querySelectorAll('.form-control');
const twoFactorForm = document.getElementById("twoFactorForm");
const verificationInput = document.getElementById("VerificationCode");
const togglePasswordBtn = document.querySelector(".show-password");
const formInputs = document.querySelectorAll(".form-control");
if (togglePasswordBtn && verificationInput) {
togglePasswordBtn.addEventListener('click', () => {
const isPassword = verificationInput.type === 'password';
verificationInput.type = isPassword ? 'text' : 'password';
const icon = togglePasswordBtn.querySelector('.icon-eye');
icon.src = chrome.runtime.getURL(`icons/${isPassword ? 'eye-on' : 'eye-off'}.svg`);
togglePasswordBtn.addEventListener("click", () => {
const isPassword = verificationInput.type === "password";
verificationInput.type = isPassword ? "text" : "password";
const icon = togglePasswordBtn.querySelector(".icon-eye");
icon.src = chrome.runtime.getURL(
`icons/${isPassword ? "eye-on" : "eye-off"}.svg`,
);
});
}
formInputs.forEach(input => {
input.addEventListener('input', () => {
formInputs.forEach((input) => {
input.addEventListener("input", () => {
validateInput(input);
});
input.addEventListener('blur', () => {
input.addEventListener("blur", () => {
validateInput(input, true);
});
});
if (twoFactorForm) {
twoFactorForm.addEventListener('submit', handleSubmit);
twoFactorForm.addEventListener("submit", handleSubmit);
}
}
function validateInput(input, showError = false) {
const isValid = input.value.trim().length > 0;
const errorElement = input.nextElementSibling?.nextElementSibling;
if (!isValid && showError) {
input.classList.add('error');
errorElement?.classList.add('show');
input.classList.add("error");
errorElement?.classList.add("show");
} else {
input.classList.remove('error');
errorElement?.classList.remove('show');
input.classList.remove("error");
errorElement?.classList.remove("show");
}
return isValid;
}
function handleSubmit(event) {
event.preventDefault();
const form = event.target;
const inputs = form.querySelectorAll('.form-control[required]');
const inputs = form.querySelectorAll(".form-control[required]");
let isValid = true;
inputs.forEach(input => {
inputs.forEach((input) => {
if (!validateInput(input, true)) {
isValid = false;
}
});
if (isValid) {
const submitButton = form.querySelector('.btn-kreta');
const submitButton = form.querySelector(".btn-kreta");
if (submitButton) {
submitButton.disabled = true;
submitButton.innerHTML = `<span class="spinner"></span><span class="btn-text">${LanguageManager.t('twofactor.verifying')}</span>`;
submitButton.innerHTML = '';
const spinnerSpan = document.createElement('span');
spinnerSpan.className = 'spinner';
const textSpan = document.createElement('span');
textSpan.className = 'btn-text';
textSpan.textContent = LanguageManager.t('twofactor.verifying');
submitButton.appendChild(spinnerSpan);
submitButton.appendChild(textSpan);
}
form.submit();
}
}
transformTwoFactorPage();
transformTwoFactorPage();

View File

@@ -1,138 +1,117 @@
* {
box-sizing: border-box;
margin: 0;
padding: 0;
box-sizing:border-box;
margin:0;
padding:0;
}
body {
margin: 0;
padding: 0;
color: var(--text-primary);
background-color: var(--background) !important;
font-family: "Montserrat", serif !important;
min-height: 100vh;
font-size: 16px;
display: flex;
align-items: center;
justify-content: center;
margin:0;
padding:0;
color:var(--text-primary);
background-color:var(--background) !important;
font-family:"Montserrat",serif !important;
min-height:100vh;
font-size:16px;
display:flex;
align-items:center;
justify-content:center;
}
.logout-container {
width: 100%;
max-width: 500px;
padding: 20px;
margin: 0 auto;
width:100%;
max-width:500px;
padding:20px;
margin:0 auto;
}
.logout-header {
text-align: center;
margin-bottom: 24px;
text-align:center;
margin-bottom:24px;
}
.logo-text {
color: var(--text-primary);
font-size: 24px;
font-weight: 600;
margin: 16px 0;
display: flex;
align-items: center;
justify-content: center;
color:var(--text-primary);
font-size:24px;
font-weight:600;
margin:16px 0;
display:flex;
align-items:center;
justify-content:center;
}
.logo {
width: 24px;
border-radius: 8px;
margin-right: 8px;
width:24px;
border-radius:8px;
margin-right:8px;
}
.logout-card {
background: var(--card-card);
padding: 24px;
border-radius: 24px;
text-align: center;
margin-bottom: 16px;
box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow);
background:var(--card-card);
padding:24px;
border-radius:24px;
text-align:center;
margin-bottom:16px;
box-shadow:0px 1px var(--shadow-blur) 0px var(--accent-shadow);
}
.logout-message {
margin-bottom: 24px;
margin-bottom:24px;
}
.logout-message strong {
font-size: 18px;
color: var(--text-primary);
font-weight: 600;
font-size:18px;
color:var(--text-primary);
font-weight:600;
}
.redirect-timer {
font-size: 48px;
font-weight: 700;
color: var(--accent-accent);
margin-bottom: 24px;
font-size:48px;
font-weight:700;
color:var(--accent-accent);
margin-bottom:24px;
}
.btn-continue {
display: inline-block;
padding: 12px 24px;
background: var(--accent-accent);
color: var(--button-secondaryFill);
text-decoration: none;
border-radius: 12px;
font-weight: 600;
transition: background 0.2s ease, color 0.2s ease;
display:inline-block;
padding:12px 24px;
background:var(--accent-accent);
color:var(--button-secondaryFill);
text-decoration:none;
border-radius:12px;
font-weight:600;
transition:background 0.2s ease,color 0.2s ease;
}
.btn-continue:hover {
background: var(--accent-secondary) !important;
color: var(--button-secondaryFill) !important;
background:var(--accent-secondary) !important;
color:var(--button-secondaryFill) !important;
}
.logout-footer {
text-align: center;
text-align:center;
}
.privacy-link {
color: var(--text-secondary);
text-decoration: none;
font-size: 14px;
display: inline-block;
margin-bottom: 8px;
transition: color 0.2s ease;
color:var(--text-secondary);
text-decoration:none;
font-size:14px;
display:inline-block;
margin-bottom:8px;
transition:color 0.2s ease;
}
.privacy-link:hover {
color: var(--text-primary);
color:var(--text-primary);
}
@media (max-width: 600px) {
@media (max-width:600px) {
.logout-container {
padding: 16px;
}
.logout-card {
padding: 20px;
}
.redirect-timer {
font-size: 36px;
}
.logo-text {
font-size: 20px;
}
.logo {
width: 20px;
}
padding:16px;
}
@keyframes fadeIn {
.logout-card {
padding:20px;
}
.redirect-timer {
font-size:36px;
}
.logo-text {
font-size:20px;
}
.logo {
width:20px;
}
}@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
opacity:0;
transform:translateY(-10px);
}
to {
opacity:1;
transform:translateY(0);
}
}

View File

@@ -1,25 +1,17 @@
(() => {
function loadFonts() {
// Create a new style element
const style = document.createElement('style');
style.textContent = `
@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;600;700&display=swap');
@import url('https://fonts.googleapis.com/icon?family=Material+Icons+Round');
`;
document.head.appendChild(style);
}
function transformLogoutPage() {
// Get current theme and school ID from cookies
const theme = cookieManager.get('themePreference') || localStorage.getItem('themePreference') || 'light-green';
const instituteCode = cookieManager.get('schoolSubdomain');
document.documentElement.setAttribute('data-theme', theme);
// Create new HTML structure
async function transformLogoutPage() {
const theme =
await storageManager.get("themePreference", null) ||
localStorage.getItem("themePreference") ||
"light-green";
const instituteCode = await storageManager.get("schoolSubdomain", null);
document.documentElement.setAttribute("data-theme", theme);
const newHTML = `
<div class="logout-container">
<header class="logout-header">
<p class="logo-text">
<img src=${chrome.runtime.getURL('images/firka_logo.png')} alt="Firka" class="logo">
<img src=${chrome.runtime.getURL("images/firka_logo.png")} alt="Firka" class="logo">
Firka
</p>
</header>
@@ -42,39 +34,49 @@
</footer>
</div>
`;
// Replace body content
document.body.innerHTML = newHTML;
// Start countdown timer
const timerElement = document.getElementById('automaticRedirectTimer');
document.body.innerHTML = '';
const parser = new DOMParser();
const doc = parser.parseFromString(newHTML, 'text/html');
const tempDiv = doc.body;
while (tempDiv.firstChild) {
document.body.appendChild(tempDiv.firstChild);
}
const timerElement = document.getElementById("automaticRedirectTimer");
let remainingTime = 5;
const countdownInterval = setInterval(() => {
remainingTime--;
if (timerElement) {
timerElement.textContent = remainingTime;
}
if (remainingTime <= 0) {
clearInterval(countdownInterval);
window.location.href = `https://${instituteCode}.e-kreta.hu`;
}
}, 1000);
// Handle manual redirect click
document.querySelector('.btn-continue')?.addEventListener('click', (e) => {
document.querySelector(".btn-continue")?.addEventListener("click", (e) => {
e.preventDefault();
clearInterval(countdownInterval);
window.location.href = `https://${instituteCode}.e-kreta.hu`;
});
}
// Load fonts immediately
loadFonts();
// Run the transformation
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', transformLogoutPage);
if (document.readyState === "loading") {
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.2.3",
"version": "1.3.4",
"description": "KRÉTA webes verziójának újraírása",
"icons": {
"128": "images/firka_logo_128.png"
@@ -12,110 +12,217 @@
"128": "images/firka_logo_128.png"
}
},
"permissions": [
"storage"
],
"background": {
"service_worker": "tools/background.js"
},
"browser_specific_settings": {
"gecko": {
"id": "firxa@zan1456.hu",
"strict_min_version": "58.0"
"strict_min_version": "109.0",
"data_collection_permissions": {
"required": ["none"]
}
}
},
"web_accessible_resources": [{
"resources": [
"settings/*",
"global/language.js",
"images/*",
"fonts/*.woff2",
"icons/*.svg",
"grades/chart.js",
"i18n/*.json",
"tools/cookieManager.js"
],
"matches": ["<all_urls>"]
}],
"web_accessible_resources": [
{
"resources": [
"settings/*",
"global/language.js",
"images/*",
"fonts/*.woff2",
"icons/*.svg",
"grades/chart.js",
"i18n/*.json",
"tools/cookieManager.js",
"tools/storageManager.js",
"tools/storageTest.js"
],
"matches": [
"<all_urls>"
]
}
],
"content_scripts": [
{
"matches": ["https://*.e-kreta.hu/*"],
"js": ["tools/loadingScreen.js, tools/cookieManager.js", "tools/helper.js", "tools/createTemplate.js",
"global/language.js", "global/maintenance.js", "global/theme.js", "global/navigation.js"],
"css": ["tools/loadingScreen.css", "global/theme.css", "global/navigation.css", "global/maintenance.css"],
"matches": [
"https://idp.e-kreta.hu/Account/Login*",
"https://idp.e-kreta.hu/Account/Logout*",
"https://idp.e-kreta.hu/Account/LoginWithTwoFactor*",
"https://*.e-kreta.hu/Hianyzas/Hianyzasok*",
"https://*.e-kreta.hu/Adminisztracio/BelepesKezelo*",
"https://*.e-kreta.hu/Intezmeny/Faliujsag*",
"https://*.e-kreta.hu/TanuloErtekeles/Osztalyzatok*",
"https://*.e-kreta.hu/Orarend/InformaciokOrarend*",
"https://*.e-kreta.hu/Adminisztracio/Profil*",
"https://*.e-kreta.hu/Tanulo/TanuloHaziFeladat*",
"https://*.e-kreta.hu/Adminisztracio/ElfelejtettJelszo*",
"https://intezmenykereso.e-kreta.hu/*"
],
"js": [
"global/language.js",
"global/theme.js",
"tools/loadingScreen.js",
"tools/storageManager.js",
"tools/helper.js",
"tools/createTemplate.js",
"global/maintenance.js",
"global/navigation.js"
],
"css": [
"tools/loadingScreen.css",
"global/theme.css",
"global/navigation.css",
"global/maintenance.css"
],
"run_at": "document_start"
},
{
"matches": ["https://idp.e-kreta.hu/Account/Login*"],
"js": ["login/login.js"],
"css": ["login/login.css"]
},
{
"matches": ["https://idp.e-kreta.hu/account/loginwithtwofactor*"],
"js": ["login/twofactor.js"],
"css": ["login/twofactor.css"]
},
{
"matches": ["https://*.e-kreta.hu/Hianyzas/Hianyzasok*"],
"js": ["absences/absences.js"],
"css": ["absences/absences.css"],
"run_at": "document_end"
},
{
"matches": ["https://idp.e-kreta.hu/Account/Logout*"],
"js": ["logout/logout.js"],
"css": ["logout/logout.css"],
"run_at": "document_end"
},
{
"matches": ["https://*.e-kreta.hu/Adminisztracio/BelepesKezelo*"],
"js": ["roleselect/roleselect.js"],
"css": ["roleselect/roleselect.css"],
"run_at": "document_end"
},
{
"matches": ["https://*.e-kreta.hu/Adminisztracio/ElfelejtettJelszo*"],
"js": ["forgotpassword/forgotpassword.js"],
"css": ["forgotpassword/forgotpassword.css"],
"run_at": "document_end"
},
{
"matches": ["https://*.e-kreta.hu/Intezmeny/Faliujsag*"],
"js": ["dashboard/dashboard.js"],
"css": ["dashboard/dashboard.css"],
"run_at": "document_end"
},
{
"matches": [ "https://*.e-kreta.hu/TanuloErtekeles/Osztalyzatok*"
"matches": [
"https://idp.e-kreta.hu/Account/Login*"
],
"js": [
"login/login.js"
],
"css": [
"login/login.css"
],
"run_at": "document_start"
},
{
"matches": [
"https://idp.e-kreta.hu/account/loginwithtwofactor*"
],
"js": [
"login/twofactor.js"
],
"css": [
"login/twofactor.css"
],
"run_at": "document_start"
},
{
"matches": [
"https://*.e-kreta.hu/Hianyzas/Hianyzasok*"
],
"js": [
"absences/absences.js"
],
"css": [
"absences/absences.css"
],
"run_at": "document_end"
},
{
"matches": [
"https://idp.e-kreta.hu/Account/Logout*"
],
"js": [
"logout/logout.js"
],
"css": [
"logout/logout.css"
],
"run_at": "document_start"
},
{
"matches": [
"https://*.e-kreta.hu/Adminisztracio/BelepesKezelo*"
],
"js": [
"roleselect/roleselect.js"
],
"css": [
"roleselect/roleselect.css"
],
"run_at": "document_start"
},
{
"matches": [
"https://*.e-kreta.hu/Intezmeny/Faliujsag*"
],
"js": [
"dashboard/dashboard.js"
],
"css": [
"dashboard/dashboard.css"
],
"run_at": "document_end"
},
{
"matches": [
"https://*.e-kreta.hu/TanuloErtekeles/Osztalyzatok*"
],
"js": [
"grades/grades.js",
"grades/chart.js"
],
"css": [
"grades/grades.css"
],
"js": ["grades/grades.js", "grades/chart.js"],
"css": ["grades/grades.css"],
"run_at": "document_end"
},
{
"matches": [
"https://*.e-kreta.hu/Orarend/InformaciokOrarend*"
],
"js": ["timetable/timetable.js"],
"css": ["timetable/timetable.css"],
"js": [
"timetable/timetable.js"
],
"css": [
"timetable/timetable.css"
],
"run_at": "document_end"
},
{
"matches": [
"https://*.e-kreta.hu/Adminisztracio/Profil*"
],
"js": ["profile/profile.js"],
"css": ["profile/profile.css"],
"js": [
"profile/profile.js"
],
"css": [
"profile/profile.css"
],
"run_at": "document_end"
},
{
"matches": [
"https://*.e-kreta.hu/Tanulo/TanuloHaziFeladat*"
],
"js": ["homework/homework.js"],
"css": ["homework/homework.css"],
"js": [
"homework/homework.js"
],
"css": [
"homework/homework.css"
],
"run_at": "document_end"
},
{
"matches": [
"https://*.e-kreta.hu/Adminisztracio/ElfelejtettJelszo*"
],
"js": [
"forgotpassword/forgotpassword.js"
],
"css": [
"forgotpassword/forgotpassword.css"
],
"run_at": "document_end"
},
{
"matches": [
"https://intezmenykereso.e-kreta.hu/"
],
"js": ["search/search.js"],
"css": ["search/search.css"],
"js": [
"search/search.js"
],
"css": [
"search/search.css"
],
"run_at": "document_end"
}
]

View File

@@ -1,366 +1,325 @@
* {
box-sizing: border-box;
margin: 0;
padding: 0;
@import url('../global/theme.css');
.main-header,
.main-menu,
.main-sidebar,
.content-header,
.favoriteIconContainer,
#frissitesDatumDiv,
#layout_navigationBar,
.navbar,
.sidebar-container,
#sidepanel_tabs,
.sidepanel-wrapper {
display: none !important;
}
body {
margin: 0;
padding: 0;
color: var(--text-primary);
color: var(--text-primary) !important;
background-color: var(--background) !important;
font-family: "Montserrat", serif !important;
font-family: 'Montserrat', sans-serif !important;
min-height: 100vh;
font-size: 16px;
}
.kreta-container {
.page-wrapper {
background-color: var(--background) !important;
min-height: 100vh;
}
.main-wrapper {
display: flex;
flex-direction: column;
min-height: 100vh;
background-color: var(--background) !important;
}
.main-content {
flex: 1;
padding: 0;
background-color: var(--background) !important;
}
.content-content {
background-color: var(--background) !important;
min-height: auto !important;
padding: 0;
}
.content-container {
max-width: 1200px;
margin: 0 auto;
padding: clamp(1rem, 3vw, 2rem);
background-color: var(--background) !important;
}
.kreta-header {
.firka-header {
padding: clamp(1rem, 3vw, 2rem);
display: grid;
grid-template-columns: minmax(300px, 400px) 1fr minmax(200px, 300px);
display: flex;
align-items: center;
gap: 1rem;
background-color: var(--background);
border-bottom: 1px solid var(--accent-15);
}
.school-info {
.back-button {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
background: var(--card-card);
border: none;
border-radius: 12px;
padding: 12px 16px;
color: var(--text-primary);
font-family: 'Montserrat', sans-serif;
font-weight: 500;
font-size: 14px;
cursor: pointer;
transition: all 0.2s ease;
text-decoration: none;
box-shadow: 0px 1px var(--shadow-blur, 2px) 0px var(--accent-shadow);
}
.logo-text {
.back-button:hover {
background: var(--button-secondaryFill);
transform: translateY(-1px);
box-shadow: 0px 2px var(--shadow-blur, 4px) 0px var(--accent-shadow);
}
.back-button svg {
width: 16px;
height: 16px;
fill: var(--text-primary);
}
.page-title {
color: var(--text-primary);
font-size: 24px;
font-weight: 600;
display: flex;
align-items: center;
margin: 0;
}
.logo {
width: 24px;
border-radius: 8px;
margin-right: 8px;
.k-content {
background-color: var(--background) !important;
}
.school-details {
color: var(--text-secondary);
font-size: 14px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 300px;
}
.user-profile {
position: relative;
justify-self: flex-end;
}
.user-dropdown-btn {
display: flex;
align-items: center;
gap: 1rem;
background: none;
border: none;
cursor: pointer;
padding: 0.5rem;
border-radius: 8px;
transition: background-color 0.2s;
}
.user-dropdown-btn:hover {
background: var(--card-card);
}
.user-info {
text-align: right;
}
.user-dropdown {
position: absolute;
top: 100%;
right: 0;
margin-top: 0.5rem;
background: var(--card-card);
border-radius: 12px;
box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow);
width: 200px;
display: none;
z-index: 1000;
}
.user-dropdown.show {
display: block;
animation: dropdownShow 0.2s ease;
}
.dropdown-item {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.75rem 1rem;
color: var(--text-primary);
text-decoration: none;
transition: background-color 0.2s;
}
.dropdown-item:hover {
background: var(--button-secondaryFill);
}
.kreta-main {
flex: 1;
padding: clamp(1rem, 3vw, 2rem);
max-width: 800px;
margin: 0 auto;
width: 100%;
}
.card {
background: var(--card-card);
border-radius: 24px;
overflow: hidden;
box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow);
}
.card h2 {
font-size: 18px;
font-weight: 600;
color: var(--text-primary);
padding: 1.5rem;
padding-bottom: 0.5rem;
background-color: var(--card-card);
}
.profile-tabs {
padding: 1.5rem;
}
.tab-headers {
display: flex;
gap: 0.5rem;
margin-bottom: 1.5rem;
border-bottom: 1px solid var(--card-translucent);
overflow-x: auto;
scrollbar-width: none;
}
.tab-headers::-webkit-scrollbar {
display: none;
}
.tab-header {
padding: 0.75rem 1rem;
background: none;
border: none;
color: var(--text-secondary);
font-weight: 500;
cursor: pointer;
white-space: nowrap;
border-bottom: 2px solid transparent;
font-size: 14px;
}
.tab-header.active {
color: var(--accent-accent);
border-bottom-color: var(--accent-accent);
}
.tab-content {
display: none;
background: var(--button-secondaryFill);
border-radius: 8px;
padding: 1.5rem;
}
.tab-content.active {
display: block;
}
.form-group {
margin-bottom: 1rem;
}
.form-label {
display: block;
color: var(--text-secondary);
font-size: 14px;
margin-bottom: 0.5rem;
}
.form-control {
width: 100%;
padding: 0.75rem;
border: 1px solid var(--accent-15);
border-radius: 8px;
background: var(--accent-15);
color: var(--text-primary);
font-size: 14px;
}
.form-control:focus {
outline: none;
border-color: var(--accent-accent);
}
.form-text {
font-size: 12px;
color: var(--text-secondary);
margin-top: 0.25rem;
}
.security-content {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
.step-card {
background: var(--button-secondaryFill);
border-radius: 12px;
padding: 1.5rem;
animation: fadeIn 0.3s ease;
}
.step-card h3 {
color: var(--text-primary);
font-size: 16px;
font-weight: 600;
margin-bottom: 1rem;
}
.step-card p {
color: var(--text-secondary);
font-size: 14px;
margin-bottom: 1rem;
line-height: 1.5;
}
.app-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1.5rem;
margin-top: 1rem;
}
.app-section h4 {
color: var(--text-primary);
font-size: 14px;
font-weight: 600;
margin-bottom: 0.75rem;
}
.app-links {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.app-link {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.75rem;
background: var(--card-card);
border-radius: 8px;
color: var(--text-primary);
text-decoration: none;
font-size: 14px;
transition: background-color 0.2s;
}
.app-link:hover {
background: var(--button-secondaryFill);
}
.qr-container {
display: flex;
flex-direction: column;
align-items: center;
gap: 1rem;
margin: 1.5rem 0;
}
.qr-container img {
background: white;
padding: 1rem;
border-radius: 8px;
max-width: 200px;
}
.setup-key {
display: flex;
flex-direction: column;
gap: 0.5rem;
width: 100%;
}
.key-display {
display: flex;
align-items: center;
gap: 0.5rem;
background: var(--card-card);
padding: 0.75rem;
border-radius: 8px;
}
.key-display code {
font-family: monospace;
color: var(--text-primary);
font-size: 14px;
flex-grow: 1;
.k-content h4 {
color: var(--text-primary) !important;
font-family: 'Montserrat', sans-serif !important;
font-size: 28px !important;
font-weight: 600 !important;
margin: 0 0 2rem 0 !important;
text-align: center;
}
.btn-copy {
background: none;
border: none;
color: var(--text-secondary);
cursor: pointer;
padding: 0.25rem;
border-radius: 4px;
transition: all 0.2s;
.k-tabstrip-wrapper {
background: var(--card-card) !important;
border-radius: 24px !important;
overflow: hidden;
box-shadow: 0px 1px var(--shadow-blur, 2px) 0px var(--accent-shadow);
border: none !important;
}
.btn-copy:hover {
color: var(--text-primary);
background: var(--button-secondaryFill);
.k-tabstrip {
background: var(--card-card) !important;
border: none !important;
}
.k-tabstrip-items {
background: var(--card-card) !important;
border: none !important;
border-radius: 24px 24px 0 0 !important;
padding: 0 20px !important;
}
.k-tabstrip-items .k-item {
background: transparent !important;
border: none !important;
margin: 0 !important;
border-radius: 0 !important;
}
.k-tabstrip-items .k-item .k-link {
color: var(--text-secondary) !important;
font-family: 'Montserrat', sans-serif !important;
font-weight: 500 !important;
font-size: 14px !important;
padding: 16px 20px !important;
border: none !important;
background: transparent !important;
border-radius: 0 !important;
transition: all 0.2s ease !important;
}
.k-tabstrip-items .k-item.k-state-active .k-link {
color: var(--accent-accent) !important;
font-weight: 600 !important;
border-bottom: 2px solid var(--accent-accent) !important;
}
.k-tabstrip-items .k-item:hover .k-link {
color: var(--text-primary) !important;
}
.btn-save {
padding: 0.75rem 1.5rem;
background: var(--accent-accent);
color: var(--button-secondaryFill);
border: none;
border-radius: 8px;
font-weight: 500;
cursor: pointer;
font-size: 14px;
transition: background-color 0.2s;
.k-tabstrip .k-content {
background: var(--card-card) !important;
border: none !important;
padding: 20px !important;
border-radius: 0 0 24px 24px !important;
}
.btn-save:hover {
background: var(--accent-secondary);
form {
background: transparent !important;
}
.container-fluid.details {
background: transparent !important;
margin-bottom: 2rem;
}
.row {
margin-bottom: 1rem;
align-items: center;
}
.windowInputLabel {
color: var(--text-primary) !important;
font-family: 'Montserrat', sans-serif !important;
font-weight: 500 !important;
font-size: 14px !important;
margin: 0 !important;
}
input[type="text"],
input[type="password"],
input[type="email"],
select,
textarea {
background: var(--button-secondaryFill) !important;
border: 1px solid var(--accent-15) !important;
border-radius: 12px !important;
padding: 12px 16px !important;
color: var(--text-primary) !important;
font-family: 'Montserrat', sans-serif !important;
font-size: 14px !important;
transition: all 0.2s ease !important;
}
input[type="text"]:focus,
input[type="password"]:focus,
input[type="email"]:focus,
select:focus,
textarea:focus {
outline: none !important;
border-color: var(--accent-accent) !important;
box-shadow: 0 0 0 3px var(--accent-15) !important;
}
.k-checkbox {
appearance: none;
width: 20px !important;
height: 20px !important;
border: 2px solid var(--accent-15) !important;
border-radius: 4px !important;
background: var(--button-secondaryFill) !important;
cursor: pointer !important;
position: relative !important;
transition: all 0.2s ease !important;
}
.k-checkbox:checked {
background: var(--accent-accent) !important;
border-color: var(--accent-accent) !important;
}
.k-checkbox:checked::after {
content: '✓';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
font-size: 12px;
font-weight: bold;
}
.k-checkbox-label {
margin-left: 8px !important;
color: var(--text-primary) !important;
font-family: 'Montserrat', sans-serif !important;
cursor: pointer !important;
}
.k-button,
button {
background: var(--accent-accent) !important;
border: none !important;
border-radius: 12px !important;
padding: 12px 24px !important;
color: white !important;
font-family: 'Montserrat', sans-serif !important;
font-weight: 600 !important;
font-size: 14px !important;
cursor: pointer !important;
transition: all 0.2s ease !important;
box-shadow: 0px 1px var(--shadow-blur, 2px) 0px var(--accent-shadow) !important;
}
.k-button:hover,
button:hover {
background: var(--accent-secondary) !important;
transform: translateY(-1px) !important;
box-shadow: 0px 2px var(--shadow-blur, 4px) 0px var(--accent-shadow) !important;
}
.k-button:active,
button:active {
transform: translateY(0) !important;
}
@media (max-width: 768px) {
.content-container {
padding: 1rem;
}
.firka-header {
padding: 1rem;
}
.page-title {
font-size: 20px;
}
.k-content h4 {
font-size: 24px !important;
}
.k-tabstrip-items {
padding: 0 10px !important;
}
.k-tabstrip-items .k-item .k-link {
padding: 12px 16px !important;
font-size: 13px !important;
}
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(-10px);
transform: translateY(20px);
}
to {
opacity: 1;
@@ -368,70 +327,159 @@ body {
}
}
@keyframes dropdownShow {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
.k-tabstrip-wrapper {
animation: fadeIn 0.5s ease forwards;
}
@media (max-width: 768px) {
.kreta-header {
grid-template-columns: 1fr auto auto;
grid-template-areas:
"school toggle user"
"nav nav nav";
padding: 1rem;
gap: 0.5rem;
}
.k-widget,
.k-header {
background: var(--card-card) !important;
color: var(--text-primary) !important;
border: none !important;
}
.school-info {
grid-area: school;
}
.k-state-default {
background: transparent !important;
border: none !important;
}
.user-profile {
grid-area: user;
}
.app-grid {
grid-template-columns: 1fr;
}
.profile-tabs {
padding: 1rem;
}
.tab-content {
padding: 1rem;
}
.k-state-active {
background: transparent !important;
}
.material-icons-round {
font-size: 20px;
vertical-align: middle;
.k-overlay,
.k-window,
.k-notification {
display: none !important;
}
::-webkit-scrollbar {
width: 8px;
height: 8px;
.main-content .content-content {
display: block !important;
}
::-webkit-scrollbar-track {
background: var(--background);
div[style*="display:flex;justify-content:space-between"] {
display: flex !important;
justify-content: space-between !important;
align-items: center !important;
margin-top: 2rem !important;
padding-top: 2rem !important;
border-top: 1px solid var(--accent-15) !important;
}
::-webkit-scrollbar-thumb {
background: var(--text-secondary);
border-radius: 4px;
div[style*="display:flex;justify-content:space-between"] label {
color: var(--text-secondary) !important;
font-size: 12px !important;
font-style: italic !important;
margin: 0 !important;
}
::-webkit-scrollbar-thumb:hover {
background: var(--text-primary);
.hidden-contact-info {
display: none !important;
visibility: hidden !important;
}
.hidden-tab {
display: none !important;
}
#ProfilTab-3 {
padding: 20px;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
min-height: 500px;
}
#ProfilTab-3 .container-fluid {
background: white;
border-radius: 12px;
padding: 30px;
margin-top: 20px;
}
#ProfilTab-3 h4 {
color: #2c3e50;
font-weight: 600;
margin-bottom: 25px;
padding-bottom: 10px;
border-bottom: 3px solid #3498db;
display: inline-block;
}
#ProfilTab-3 .row {
margin-bottom: 20px;
padding: 15px;
background: #f8f9fa;
border-radius: 8px;
border-left: 4px solid #3498db;
transition: all 0.3s ease;
}
#ProfilTab-3 .row:hover {
background: #e3f2fd;
transform: translateX(5px);
box-shadow: 0 2px 10px rgba(52, 152, 219, 0.2);
}
#ProfilTab-3 .windowInputLabel {
color: #34495e;
font-weight: 500;
font-size: 14px;
}
#ProfilTab-3 .k-button {
background: linear-gradient(135deg, #3498db, #2980b9);
border: none;
border-radius: 6px;
padding: 10px 20px;
color: white;
font-weight: 500;
transition: all 0.3s ease;
}
#ProfilTab-3 .k-button:hover {
background: linear-gradient(135deg, #2980b9, #1f5f8b);
transform: translateY(-2px);
box-shadow: 0 4px 15px rgba(52, 152, 219, 0.4);
}
#ProfilTab-3 .k-input {
border: 2px solid #e0e6ed;
border-radius: 6px;
padding: 10px;
transition: border-color 0.3s ease;
}
#ProfilTab-3 .k-input:focus {
border-color: #3498db;
box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1);
}
#ProfilTab-3 .alert {
border-radius: 8px;
border: none;
padding: 15px;
margin: 15px 0;
}
#ProfilTab-3 .alert-info {
background: linear-gradient(135deg, #e3f2fd, #bbdefb);
color: #1565c0;
}
#ProfilTab-3 .alert-success {
background: linear-gradient(135deg, #e8f5e8, #c8e6c9);
color: #2e7d32;
}
#ProfilTab-3 .alert-warning {
background: linear-gradient(135deg, #fff3e0, #ffcc02);
color: #ef6c00;
}
.details .row {
border-bottom: none !important;
}

View File

@@ -1,396 +1,228 @@
(() => {
function createSecurityTab() {
return `
<div class="security-content">
<div class="setup-steps">
<div class="step-card">
<h3>1. lépés: Hitelesítési alkalmazás telepítése</h3>
<p>A kétfaktoros hitelesítés használatához telepítsen egy időalapú, egyszer használatos jelszó (TOTP) alkalmazást:</p>
<div class="app-grid">
<div class="app-section">
<h4>Android</h4>
<div class="app-links">
<a href="https://play.google.com/store/apps/details?id=hu.innobile.niszauth" target="_blank" class="app-link">
<span class="material-icons-round">download</span>
NISZ Hitelesítő
</a>
<a href="https://play.google.com/store/apps/details?id=com.azure.authenticator" target="_blank" class="app-link">
<span class="material-icons-round">download</span>
Microsoft Authenticator
</a>
<a href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2" target="_blank" class="app-link">
<span class="material-icons-round">download</span>
Google Authenticator
</a>
</div>
</div>
<div class="app-section">
<h4>iPhone</h4>
<div class="app-links">
<a href="https://apps.apple.com/hu/app/nisz-hiteles%C3%ADt%C5%91/id1603444961" target="_blank" class="app-link">
<span class="material-icons-round">download</span>
NISZ Hitelesítő
</a>
<a href="https://apps.apple.com/hu/app/microsoft-authenticator/id983156458" target="_blank" class="app-link">
<span class="material-icons-round">download</span>
Microsoft Authenticator
</a>
<a href="https://apps.apple.com/hu/app/google-authenticator/id388497605" target="_blank" class="app-link">
<span class="material-icons-round">download</span>
Google Authenticator
</a>
</div>
</div>
</div>
</div>
<div class="step-card">
<h3>2. lépés: Kétfaktoros azonosítás beállítása</h3>
<div class="setup-form">
<div class="form-group">
<button type="button" class="btn-save" id="enable2FA">Kétfaktoros azonosítás bekapcsolása</button>
</div>
<div id="qrSetup" style="display: none;">
<div class="qr-container">
<img id="qrCode" alt="QR kód" style="display: none;">
<div class="setup-key">
<label class="form-label">Biztonsági kulcs:</label>
<div class="key-display">
<code id="secretKey"></code>
<button type="button" class="btn-copy" id="copyKey">
<span class="material-icons-round">content_copy</span>
</button>
</div>
</div>
</div>
<div class="form-group">
<label class="form-label" for="verificationCode">Ellenőrző kód</label>
<input type="text" class="form-control" id="verificationCode" maxlength="6" placeholder="123456">
<small class="form-text">Adja meg a hitelesítő alkalmazásban megjelenő 6 számjegyű kódot.</small>
</div>
<div class="form-group">
<button type="button" class="btn-save" id="verify2FA">Ellenőrzés és aktiválás</button>
</div>
</div>
</div>
</div>
<div class="step-card" id="backupCodes" style="display: none;">
<h3>3. lépés: Biztonsági kódok mentése</h3>
<p>Az alábbi biztonsági kódokat használhatja bejelentkezéshez, ha nem fér hozzá a hitelesítő alkalmazásához. Minden kód csak egyszer használható.</p>
<div class="backup-codes">
<pre id="backupCodesList"></pre>
<button type="button" class="btn-save" id="downloadCodes">
<span class="material-icons-round">download</span>
Kódok letöltése
</button>
</div>
</div>
</div>
</div>
`;
}
function createContactTab() {
return `
<div class="contact-form">
<div class="form-group">
<label class="form-label" for="email">E-mail cím</label>
<input type="email" class="form-control" id="email" required>
<small class="form-text">Az e-mail cím megadása a jelszó emlékeztető miatt szükséges.</small>
</div>
<div class="form-group">
<label class="form-label" for="phone">Telefonszám</label>
<input type="tel" class="form-control" id="phone" placeholder="+36 xx xxx xxxx">
<small class="form-text">A telefonszám megadása nem kötelező.</small>
</div>
<div class="form-group">
<button type="button" class="btn-save" id="saveContacts">Mentés</button>
</div>
</div>
`;
}
function createPasswordTab() {
return `
<div class="password-form">
<div class="form-group">
<label class="form-label" for="currentPassword">Jelenlegi jelszó</label>
<input type="password" class="form-control" id="currentPassword" required>
</div>
<div class="form-group">
<label class="form-label" for="newPassword">Új jelszó</label>
<input type="password" class="form-control" id="newPassword" required minlength="8">
<small class="form-text">A jelszónak legalább 8 karakter hosszúnak kell lennie.</small>
</div>
<div class="form-group">
<label class="form-label" for="confirmPassword">Új jelszó megerősítése</label>
<input type="password" class="form-control" id="confirmPassword" required>
</div>
<div class="form-group">
<button type="button" class="btn-save" id="savePassword">Jelszó módosítása</button>
</div>
</div>
`;
}
function createSettingsTab() {
return `
<div class="settings-form">
<div class="form-group">
<label class="form-label">
<input type="checkbox" id="hideTips">
Tippek elrejtése
</label>
<small class="form-text">A tippek megjelenítésének ki/be kapcsolása.</small>
</div>
<div class="form-group">
<button type="button" class="btn-save" id="saveSettings">Mentés</button>
</div>
</div>
`;
}
function setupContactForm() {
const form = document.querySelector('.contact-form');
if (!form) return;
const emailInput = form.querySelector('#email');
const phoneInput = form.querySelector('#phone');
const saveButton = form.querySelector('#saveContacts');
emailInput.value = cookieManager.get('userEmail') || '';
phoneInput.value = cookieManager.get('userPhone') || '';
saveButton?.addEventListener('click', async () => {
const email = emailInput.value.trim();
const phone = phoneInput.value.trim();
if (!email) {
alert(LanguageManager.t('profile.email_required'));
return;
(function() {
'use strict';
function hideLoadingScreen() {
const loadingElement = document.getElementById('KretaProgressBar');
if (loadingElement) {
loadingElement.style.display = 'none !important';
loadingElement.style.visibility = 'hidden';
loadingElement.style.opacity = '0';
loadingElement.remove();
}
if (email && !isValidEmail(email)) {
alert(LanguageManager.t('profile.invalid_email'));
return;
}
if (phone && !isValidPhone(phone)) {
alert(LanguageManager.t('profile.invalid_phone'));
return;
}
try {
const response = await fetch('/Adminisztracio/Profil/SaveElerhetosegek', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'RequestVerificationToken': document.querySelector('input[name="__RequestVerificationToken"]').value
},
body: JSON.stringify({ email, phone })
});
if (response.ok) {
alert(LanguageManager.t('profile.contacts_saved'));
} else {
throw new Error(LanguageManager.t('profile.contacts_save_error'));
}
} catch (error) {
console.error('Error saving contacts:', error);
alert(LanguageManager.t('profile.save_error'));
}
});
}
function isValidEmail(email) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
function isValidPhone(phone) {
return /^\+?[0-9\s-]{9,}$/.test(phone);
}
function setupEventListeners() {
document.querySelectorAll('.tab-header').forEach(header => {
header.addEventListener('click', () => {
document.querySelectorAll('.tab-header').forEach(h => h.classList.remove('active'));
document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
header.classList.add('active');
const targetId = header.dataset.tab;
document.getElementById(`${targetId}-content`).classList.add('active');
const loadingElements = document.querySelectorAll('[class*="loading"], [id*="loading"], [class*="Loading"], [id*="Loading"]');
loadingElements.forEach(el => {
el.style.display = 'none !important';
el.style.visibility = 'hidden';
el.style.opacity = '0';
});
});
const userBtn = document.querySelector('.user-dropdown-btn');
const userDropdown = document.querySelector('.user-dropdown');
userBtn?.addEventListener('click', (e) => {
e.stopPropagation();
userDropdown?.classList.toggle('show');
});
document.addEventListener('click', () => {
userDropdown?.classList.remove('show');
});
document.getElementById('saveSettings')?.addEventListener('click', async () => {
const hideTips = document.getElementById('hideTips').checked;
try {
const response = await fetch('/Adminisztracio/Profil/SaveTippekBeallitasa', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'RequestVerificationToken': document.querySelector('input[name="__RequestVerificationToken"]').value
},
body: JSON.stringify({ hideTips })
});
if (response.ok) {
alert(LanguageManager.t('profile.settings_saved'));
} else {
throw new Error(LanguageManager.t('profile.settings_save_error'));
}
} catch (error) {
console.error('Error saving settings:', error);
alert(LanguageManager.t('profile.save_error'));
}
});
document.getElementById('savePassword')?.addEventListener('click', async () => {
const currentPassword = document.getElementById('currentPassword').value;
const newPassword = document.getElementById('newPassword').value;
const confirmPassword = document.getElementById('confirmPassword').value;
if (!currentPassword || !newPassword || !confirmPassword) {
alert(LanguageManager.t('profile.fill_all_fields'));
return;
}
if (newPassword !== confirmPassword) {
alert(LanguageManager.t('profile.passwords_not_match'));
return;
}
if (newPassword.length < 8) {
alert(LanguageManager.t('profile.password_min_length'));
return;
}
try {
const response = await fetch('/Adminisztracio/Profil/SaveJelszoModositas', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'RequestVerificationToken': document.querySelector('input[name="__RequestVerificationToken"]').value
},
body: JSON.stringify({
currentPassword,
newPassword,
confirmPassword
})
});
if (response.ok) {
alert(LanguageManager.t('profile.password_changed'));
document.getElementById('currentPassword').value = '';
document.getElementById('newPassword').value = '';
document.getElementById('confirmPassword').value = '';
} else {
throw new Error(LanguageManager.t('profile.password_change_error'));
}
} catch (error) {
console.error('Error changing password:', error);
alert(LanguageManager.t('profile.password_change_error'));
}
});
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')}`;
if (timeLeft <= 0) {
window.location.href = '/Home/Logout';
} else {
timeLeft--;
}
};
updateTimer();
setInterval(updateTimer, 1000);
}
}
function createProfileHTML() {
return `
<div class="kreta-container">
${createTemplate.header()}
<main class="kreta-main">
<div class="card">
<h2>Profil beállítások</h2>
<div class="profile-tabs">
<div class="tab-headers">
<button class="tab-header active" data-tab="settings">Beállítások</button>
<button class="tab-header" data-tab="password">Jelszó módosítása</button>
<button class="tab-header" data-tab="security">Biztonsági beállítások</button>
<button class="tab-header" data-tab="contacts">Elérhetőségek</button>
</div>
<div id="settings-content" class="tab-content active">
${createSettingsTab()}
</div>
<div id="password-content" class="tab-content">
${createPasswordTab()}
</div>
<div id="security-content" class="tab-content">
${createSecurityTab()}
</div>
<div id="contacts-content" class="tab-content">
${createContactTab()}
</div>
</div>
</div>
</main>
</div>
`;
}
async function init() {
if (window.location.pathname.includes('/Adminisztracio/Profil')) {
function addBackButton() {
if (document.getElementById('firka-back-button')) {
return;
}
createTemplate.importFonts();
document.body.innerHTML = createProfileHTML();
setupUserDropdown();
setupMobileNavigation();
setupEventListeners();
setupContactForm();
}
const backButton = document.createElement('button');
backButton.id = 'firka-back-button';
backButton.innerHTML = '← Vissza';
backButton.style.cssText = `
position: static;
margin: 20px;
z-index: 100;
background-color: var(--card-background, #ffffff);
color: var(--text-primary, #333333);
border: 1px solid var(--border-color, #e0e0e0);
border-radius: 8px;
padding: 10px 16px;
font-family: 'Montserrat', sans-serif;
font-size: 14px;
font-weight: 500;
cursor: pointer;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transition: all 0.2s ease;
display: inline-flex;
align-items: center;
gap: 8px;
width: auto;
`;
backButton.addEventListener('mouseenter', function() {
this.style.backgroundColor = 'var(--card-hover, #f5f5f5)';
this.style.transform = 'translateY(-1px)';
this.style.boxShadow = '0 4px 12px rgba(0, 0, 0, 0.15)';
});
backButton.addEventListener('mouseleave', function() {
this.style.backgroundColor = 'var(--card-background, #ffffff)';
this.style.transform = 'translateY(0)';
this.style.boxShadow = '0 2px 8px rgba(0, 0, 0, 0.1)';
});
backButton.addEventListener('click', function() {
window.history.back();
});
document.body.insertBefore(backButton, document.body.firstChild);
}
init();
function hideMainFooter2() {
const footer2 = document.querySelector('.main-footer2');
if (footer2) {
footer2.style.display = 'none';
}
}
function hideLakatImg() {
const lakatImg = document.querySelector('.lakatimg');
if (lakatImg) {
lakatImg.style.display = 'none';
}
}
function hideCustomUserSettingsTab() {
const firstTab = document.querySelector('#ProfilTab .k-tabstrip-items li[aria-controls="ProfilTab-1"]');
if (firstTab) {
firstTab.classList.add('hidden-tab');
}
const tabLinks = document.querySelectorAll('#ProfilTab .k-tabstrip-items .k-link');
tabLinks.forEach(link => {
if (link.textContent && link.textContent.includes('Egyedi felhasználó beállítások')) {
const parentTab = link.closest('li');
if (parentTab) {
parentTab.classList.add('hidden-tab');
}
}
});
const contentPanel = document.querySelector('#ProfilTab-1');
if (contentPanel) {
contentPanel.classList.add('hidden-tab');
}
}
function hideAdditionalContactInfo() {
function hideElementsWithText(text) {
const elements = document.querySelectorAll('h4');
elements.forEach(h4 => {
if (h4.textContent && h4.textContent.includes(text)) {
// Hide the parent row
let parent = h4.closest('.row');
if (parent) {
parent.classList.add('hidden-contact-info');
}
}
});
}
hideElementsWithText('TOVÁBBI E-MAIL ELÉRHETŐSÉGEK');
hideElementsWithText('TOVÁBBI TELEFONSZÁMOK');
const rows = document.querySelectorAll('.row');
rows.forEach(row => {
const h4Elements = row.querySelectorAll('h4');
h4Elements.forEach(h4 => {
if (h4.textContent &&
(h4.textContent.includes('TOVÁBBI E-MAIL ELÉRHETŐSÉGEK') ||
h4.textContent.includes('TOVÁBBI TELEFONSZÁMOK'))) {
row.classList.add('hidden-contact-info');
}
});
});
}
function init() {
hideLoadingScreen();
addBackButton();
hideAdditionalContactInfo();
hideCustomUserSettingsTab();
hideMainFooter2();
hideLakatImg();
const observer = new MutationObserver(() => {
hideAdditionalContactInfo();
hideCustomUserSettingsTab();
hideMainFooter2();
hideLakatImg();
});
observer.observe(document.body, {
childList: true,
subtree: true
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
window.addEventListener('load', init);
setTimeout(hideLoadingScreen, 1000);
let attempts = 0;
const maxAttempts = 20;
const aggressiveHide = setInterval(() => {
attempts++;
hideLoadingScreen();
if (attempts >= maxAttempts) {
clearInterval(aggressiveHide);
}
}, 500);
if (typeof MutationObserver !== 'undefined') {
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
mutation.addedNodes.forEach((node) => {
if (node.nodeType === 1) {
if (node.id === 'KretaProgressBar' ||
node.className && (node.className.includes('loading') || node.className.includes('Loading'))) {
node.style.display = 'none !important';
node.style.visibility = 'hidden';
node.style.opacity = '0';
if (node.parentNode) {
node.parentNode.removeChild(node);
}
}
}
});
});
});
observer.observe(document.body, {
childList: true,
subtree: true
});
}
})();

View File

@@ -1,354 +1,323 @@
* {
box-sizing: border-box;
margin: 0;
padding: 0;
box-sizing:border-box;
margin:0;
padding:0;
}
body {
color: var(--text-primary);
background-color: var(--background) !important;
font-family: "Montserrat", serif !important;
min-height: 100vh;
font-size: 16px;
color:var(--text-primary);
background-color:var(--background) !important;
font-family:"Montserrat",serif !important;
min-height:100vh;
font-size:16px;
}
.kreta-container {
width: 100%;
min-height: 100vh;
display: flex;
flex-direction: column;
padding: clamp(1rem, 3vw, 2rem);
max-width: 1200px;
margin: 0 auto;
width:100%;
min-height:100vh;
display:flex;
flex-direction:column;
padding:clamp(1rem,3vw,2rem);
max-width:1200px;
margin:0 auto;
}
.kreta-header {
display: grid;
grid-template-columns: auto 1fr auto;
align-items: center;
gap: 2rem;
margin-bottom: clamp(2rem, 5vw, 3rem);
display:grid;
grid-template-columns:auto 1fr auto;
align-items:center;
gap:2rem;
margin-bottom:clamp(2rem,5vw,3rem);
}
.school-info {
display: flex;
flex-direction: column;
gap: 0.5rem;
display:flex;
flex-direction:column;
gap:0.5rem;
}
.logo-text {
display: flex;
align-items: center;
font-size: 1.5rem;
font-weight: 600;
color: var(--text-primary);
margin: 0;
display:flex;
align-items:center;
font-size:1.5rem;
font-weight:600;
color:var(--text-primary);
margin:0;
}
.logo {
width: 32px;
height: 32px;
border-radius: 8px;
margin-right: 0.75rem;
width:32px;
height:32px;
border-radius:8px;
margin-right:0.75rem;
}
.school-details {
color: var(--text-secondary);
font-size: 1.1rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 300px;
padding-left: 2px;
color:var(--text-secondary);
font-size:1.1rem;
white-space:nowrap;
overflow:hidden;
text-overflow:ellipsis;
max-width:300px;
padding-left:2px;
}
.user-profile {
justify-self: flex-end;
text-align: right;
justify-self:flex-end;
text-align:right;
}
.user-info {
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 4px;
display:flex;
flex-direction:column;
align-items:flex-end;
gap:4px;
}
.user-name, .role-text {
color: var(--text-primary);
font-family: Montserrat;
font-weight: 600;
.user-name,.role-text {
color:var(--text-primary);
font-family:Montserrat;
font-weight:600;
}
.user-name {
font-size: 16px;
font-size:16px;
}
.role-text {
font-size: 20px;
text-align: center;
font-size:20px;
text-align:center;
}
.logout-timer, .role-description {
color: var(--text-secondary);
font-family: Figtree;
font-weight: 500;
line-height: 130%;
.logout-timer,.role-description {
color:var(--text-secondary);
font-family:Figtree;
font-weight:500;
line-height:130%;
}
.logout-timer {
font-size: 14px;
text-align: right;
font-size:14px;
text-align:right;
}
.role-description {
font-size: 16px;
text-align: center;
font-size:16px;
text-align:center;
}
.role-container {
flex: 1;
display: flex;
align-items: center;
flex:1;
display:flex;
align-items:center;
}
.role-grid {
display: grid;
grid-template-columns: 1fr minmax(300px, 1fr);
gap: 1.5rem;
width: 100%;
display:grid;
grid-template-columns:1fr minmax(300px,1fr);
gap:1.5rem;
width:100%;
}
.side-roles {
display: grid;
grid-template-rows: 1fr auto;
gap: 1.5rem;
display:grid;
grid-template-rows:1fr auto;
gap:1.5rem;
}
.role-card {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 1.5rem;
padding: 2rem;
background: var(--card-card);
border-radius: 1rem;
cursor: pointer;
text-align: center;
border: none;
box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow);
transition: all 0.2s ease;
width:100%;
display:flex;
flex-direction:column;
align-items:center;
justify-content:center;
gap:1.5rem;
padding:2rem;
background:var(--card-card);
border-radius:1rem;
cursor:pointer;
text-align:center;
border:none;
box-shadow:0px 1px var(--shadow-blur) 0px var(--accent-shadow);
transition:all 0.2s ease;
}
.role-card[data-role="Ellenorzo"] {
height: 480px;
background: var(--card-card);
height:480px;
background:var(--card-card);
}
.role-card[data-role="DKT"] {
height: 280px;
background: var(--card-card);
box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow);
height:280px;
background:var(--card-card);
box-shadow:0px 1px var(--shadow-blur) 0px var(--accent-shadow);
}
.logout-card {
height: 180px;
background: var(--error-card);
box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow);
height:180px;
background:var(--error-card);
box-shadow:0px 1px var(--shadow-blur) 0px var(--accent-shadow);
}
.role-icon {
width: 48px;
height: 48px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 12px;
transition: transform 0.2s ease;
background: var(--accent-15);
width:48px;
height:48px;
display:flex;
align-items:center;
justify-content:center;
border-radius:12px;
transition:transform 0.2s ease;
background:var(--accent-15);
}
.role-icon img {
width: 32px;
height: 32px;
transition: transform 0.2s ease;
width:32px;
height:32px;
transition:transform 0.2s ease;
}
.role-card[data-role="DKT"] .role-icon {
background: var(--warning-15);
background:var(--warning-15);
}
.logout-card .role-icon {
background: var(--error-15);
background:var(--error-15);
}
.role-icon img {
width: 32px;
height: 32px;
transition: transform 0.2s ease;
width:32px;
height:32px;
transition:transform 0.2s ease;
}
.role-card:hover {
transform: translateY(-2px);
transform:translateY(-2px);
}
.role-card:hover .role-icon img {
transform: scale(1.2);
transform:scale(1.2);
}
.role-card:active {
transform: translateY(1px);
box-shadow: 0px 0px var(--shadow-blur) 0px var(--accent-shadow);
transform:translateY(1px);
box-shadow:0px 0px var(--shadow-blur) 0px var(--accent-shadow);
}
.role-card[data-role="Ellenorzo"]:hover {
background-color: var(--accent-15);
background-color:var(--accent-15);
}
.role-card[data-role="DKT"]:hover {
background-color: var(--accent-15);
background-color:var(--accent-15);
}
.role-card[data-role="DKT"]:active {
box-shadow: 0px 0px var(--shadow-blur) 0px var(--accent-shadow);
box-shadow:0px 0px var(--shadow-blur) 0px var(--accent-shadow);
}
.logout-card:hover {
background-color: var(--error-15);
background-color:var(--error-15);
}
.logout-card:active {
box-shadow: 0px 0px var(--shadow-blur) 0px var(--error-shadow);
box-shadow:0px 0px var(--shadow-blur) 0px var(--error-shadow);
}
:root[data-theme="light-blue"] .role-card:hover,
:root[data-theme="light-green"] .role-card:hover {
box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow);
:root[data-theme="light-blue"] .role-card:hover,:root[data-theme="light-green"] .role-card:hover {
box-shadow:0px 1px var(--shadow-blur) 0px var(--accent-shadow);
}
::-webkit-scrollbar {
width: 8px;
height: 8px;
width:8px;
height:8px;
}
::-webkit-scrollbar-track {
background: var(--background);
background:var(--background);
}
::-webkit-scrollbar-thumb {
background: var(--text-secondary);
border-radius: 4px;
background:var(--text-secondary);
border-radius:4px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--text-primary);
background:var(--text-primary);
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
opacity:0;
transform:translateY(-10px);
}
@media (max-width: 1200px) {
to {
opacity:1;
transform:translateY(0);
}
}@media (max-width:1200px) {
.role-grid {
grid-template-columns: 1fr 280px;
}
grid-template-columns:1fr 280px;
}
@media (max-width: 900px) {
}@media (max-width:900px) {
.role-grid {
grid-template-columns: 1fr;
}
.side-roles {
grid-template-columns: 1fr 1fr;
grid-template-rows: none;
}
.role-card[data-role="Ellenorzo"],
.role-card[data-role="DKT"],
.logout-card {
height: 300px;
}
grid-template-columns:1fr;
}
@media (max-width: 768px) {
.side-roles {
grid-template-columns:1fr 1fr;
grid-template-rows:none;
}
.role-card[data-role="Ellenorzo"],.role-card[data-role="DKT"],.logout-card {
height:300px;
}
}@media (max-width:768px) {
.kreta-header {
grid-template-columns: 1fr auto;
gap: 1rem;
}
.school-info {
max-width: 60%;
}
.school-details {
max-width: 200px;
font-size: 1rem;
}
.logo-text {
font-size: 1.2rem;
}
.logo {
width: 24px;
height: 24px;
}
grid-template-columns:1fr auto;
gap:1rem;
}
@media (max-width: 640px) {
.school-info {
max-width:60%;
}
.school-details {
max-width:200px;
font-size:1rem;
}
.logo-text {
font-size:1.2rem;
}
.logo {
width:24px;
height:24px;
}
}@media (max-width:640px) {
.kreta-container {
padding: 1rem;
}
.side-roles {
grid-template-columns: 1fr;
gap: 1rem;
}
.role-card {
padding: 1.5rem;
}
.role-icon {
width: 40px;
height: 40px;
}
.role-icon img {
width: 24px;
height: 24px;
}
.role-text {
font-size: 1.2rem;
}
.role-description {
font-size: 1rem;
}
padding:1rem;
}
.side-roles {
grid-template-columns:1fr;
gap:0.75rem;
}
.role-card {
padding:1rem;
gap:1rem;
}
.role-card[data-role="Ellenorzo"],.role-card[data-role="DKT"],.logout-card {
height:200px;
}
.role-icon {
width:40px;
height:40px;
}
.role-icon img {
width:24px;
height:24px;
}
.role-text {
font-size:1.5rem;
}
.role-description {
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

@@ -1,17 +1,17 @@
(() => {
const startLogoutTimer = () => {
let timeLeft = 45 * 60;
const timerElement = document.getElementById('logoutTimer');
const timerElement = document.getElementById("logoutTimer");
const updateTimer = () => {
const minutes = Math.floor(timeLeft / 60);
const seconds = timeLeft % 60;
if (timerElement) {
timerElement.textContent = `${minutes}:${seconds.toString().padStart(2, '0')}`;
timerElement.textContent = `${minutes}:${seconds.toString().padStart(2, "0")}`;
}
timeLeft <= 0 ? window.location.href = '/Home/Logout' : timeLeft--;
timeLeft <= 0 ? (window.location.href = "/Home/Logout") : timeLeft--;
};
updateTimer();
@@ -20,21 +20,24 @@
const handleRoleChange = async (role) => {
try {
const response = await fetch('/Adminisztracio/SzerepkorValaszto/ChangeRole', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ Role: role })
});
const response = await fetch(
"/Adminisztracio/SzerepkorValaszto/ChangeRole",
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ Role: role }),
},
);
const data = await response.json();
if (data.Success) {
window.location.assign(data.Url);
} else {
throw new Error('Role change failed');
throw new Error("Role change failed");
}
} catch (error) {
console.error('Error changing role:', error);
alert(LanguageManager.t('roleselect.role_change_error'));
console.error("Error changing role:", error);
alert(LanguageManager.t("roleselect.role_change_error"));
}
};
@@ -43,11 +46,11 @@
<header class="kreta-header">
<div class="school-info">
<p class="logo-text">
<img src=${chrome.runtime.getURL('images/firka_logo.png')} alt="Firka" class="logo">
<img src=${chrome.runtime.getURL("images/firka_logo.png")} alt="Firka" class="logo">
Firka
</p>
<div class="school-details">
<span>${schoolCode || ''} - ${fullSchoolName || 'Iskola'}</span>
<span>${schoolCode || ""} - ${fullSchoolName || "Iskola"}</span>
</div>
</div>
<div class="user-profile">
@@ -63,11 +66,11 @@
<div class="main-role">
<div class="role-card" data-role="Ellenorzo">
<div class="role-icon">
<img src="${chrome.runtime.getURL('icons/naplo.svg')}" alt="Napló ikon">
<img src="${chrome.runtime.getURL("icons/naplo.svg")}" alt="Napló ikon">
</div>
<div class="role-text">
${LanguageManager.t('roleselect.student_book')}
<div class="role-description">${LanguageManager.t('roleselect.student_description')}</div>
${LanguageManager.t("roleselect.student_book")}
<div class="role-description">${LanguageManager.t("roleselect.student_description")}</div>
</div>
</div>
</div>
@@ -75,21 +78,21 @@
<div class="side-roles">
<div class="role-card" data-role="DKT">
<div class="role-icon">
<img src="${chrome.runtime.getURL('icons/dkt.svg')}" alt="DKT ikon">
<img src="${chrome.runtime.getURL("icons/dkt.svg")}" alt="DKT ikon">
</div>
<div class="role-text">
${LanguageManager.t('roleselect.dkt_title')}
<div class="role-description">${LanguageManager.t('roleselect.dkt_description')}</div>
${LanguageManager.t("roleselect.dkt_title")}
<div class="role-description">${LanguageManager.t("roleselect.dkt_description")}</div>
</div>
</div>
<div class="role-card logout-card">
<div class="role-icon">
<img src="${chrome.runtime.getURL('icons/logout.svg')}" alt="Kijelentkezés ikon">
<img src="${chrome.runtime.getURL("icons/logout.svg")}" alt="Kijelentkezés ikon">
</div>
<div class="role-text">
${LanguageManager.t('roleselect.logout_title')}
<div class="role-description">${LanguageManager.t('roleselect.logout_description')}</div>
${LanguageManager.t("roleselect.logout_title")}
<div class="role-description">${LanguageManager.t("roleselect.logout_description")}</div>
</div>
</div>
</div>
@@ -100,65 +103,77 @@
const transformRoleSelectPage = async () => {
try {
if (document.readyState !== 'complete') {
await new Promise(resolve => window.addEventListener('load', resolve));
if (document.readyState !== "complete") {
await new Promise((resolve) =>
window.addEventListener("load", resolve),
);
}
const schoolNameEl = document.querySelector('.IntezmenyNev');
const schoolName = schoolNameEl?.textContent.trim() || 'Iskola neve';
const [schoolCode, fullSchoolName] = schoolName.split(' - ');
const schoolNameEl = document.querySelector(".IntezmenyNev");
const schoolName = schoolNameEl?.textContent.trim() || "Iskola neve";
const [schoolCode, fullSchoolName] = schoolName.split(" - ");
const schoolSubdomain = window.location.hostname.split('.')[0];
const schoolSubdomain = window.location.hostname.split(".")[0];
const userNameEl = document.querySelector('.UserName');
const userName = userNameEl?.textContent.trim() || LanguageManager.t('common.username');
const userNameEl = document.querySelector(".UserName");
const userName =
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();
const doc = parser.parseFromString(createHTML(
schoolCode,
fullSchoolName,
userName,
), 'text/html');
const tempDiv = doc.body;
while (tempDiv.firstChild) {
document.body.appendChild(tempDiv.firstChild);
}
document.body.innerHTML = createHTML(schoolCode, fullSchoolName, userName);
createTemplate.importFonts();
const timerInterval = startLogoutTimer();
document.querySelector('.role-card[data-role="Ellenorzo"]')?.addEventListener('click', () => {
handleRoleChange('Ellenorzo');
});
document
.querySelector('.role-card[data-role="Ellenorzo"]')
?.addEventListener("click", () => {
handleRoleChange("Ellenorzo");
});
document.querySelector('.role-card[data-role="DKT"]')?.addEventListener('click', () => {
window.location.href = '/Adminisztracio/BelepesKezelo/DKTTanuloOrGondviselo';
});
document.querySelector('.logout-card')?.addEventListener('click', async () => {
try {
clearInterval(timerInterval);
await fetch('/Home/LogOut', { method: 'POST' });
} catch {
window.location.replace("https://idp.e-kreta.hu/Account/Logout");
} finally {
window.location.replace("https://idp.e-kreta.hu/Account/Logout");
}
});
document
.querySelector('.role-card[data-role="DKT"]')
?.addEventListener("click", () => {
window.location.href =
"/Adminisztracio/BelepesKezelo/DKTTanuloOrGondviselo";
});
document
.querySelector(".logout-card")
?.addEventListener("click", async () => {
try {
clearInterval(timerInterval);
await fetch("/Home/LogOut", { method: "POST" });
} catch {
window.location.replace("https://idp.e-kreta.hu/Account/Logout");
} finally {
window.location.replace("https://idp.e-kreta.hu/Account/Logout");
}
});
} catch (error) {
console.error('Error transforming page:', error);
console.error("Error transforming page:", error);
}
};
if (window.location.href.includes('/Adminisztracio/BelepesKezelo')) {
if (window.location.href.includes("/Adminisztracio/BelepesKezelo")) {
transformRoleSelectPage();
}
})();
})();

View File

@@ -1,222 +1,196 @@
/* Hide original elements */
header, footer, .page-title, .card-kreta {
display: none !important;
header,footer,.page-title,.card-kreta {
display:none !important;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
box-sizing:border-box;
margin:0;
padding:0;
}
body {
margin: 0;
padding: 0;
color: var(--text-primary);
background-color: var(--background) !important;
font-family: "Montserrat", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
min-height: 100vh;
font-size: 16px;
display: flex;
align-items: center;
justify-content: center;
margin:0;
padding:0;
color:var(--text-primary);
background-color:var(--background) !important;
font-family:"Montserrat",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif !important;
min-height:100vh;
font-size:16px;
display:flex;
align-items:center;
justify-content:center;
}
/* Firka search page styling */
.firka-search-wrapper {
width: 90%;
max-width: 500px;
padding: 0;
margin: 0 auto;
display: flex;
flex-direction: column;
align-items: center;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width:90%;
max-width:500px;
padding:0;
margin:0 auto;
display:flex;
flex-direction:column;
align-items:center;
position:absolute;
top:50%;
left:50%;
transform:translate(-50%,-50%);
}
/* Firka header styling */
.firka-header {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
margin: 0;
background: var(--card-card) !important;
padding: 24px;
border-radius: 24px 24px 0 0;
width: 100%;
box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow);
display:flex;
flex-direction:column;
align-items:center;
gap:8px;
margin:0;
background:var(--card-card) !important;
padding:24px;
border-radius:24px 24px 0 0;
width:100%;
box-shadow:0px 1px var(--shadow-blur) 0px var(--accent-shadow);
}
.logo-text {
color: var(--text-primary);
text-align: center;
font-family: Montserrat;
font-size: 20px;
font-style: normal;
font-weight: 700;
line-height: normal;
display: flex;
align-items: center;
gap: 8px;
color:var(--text-primary);
text-align:center;
font-family:Montserrat;
font-size:20px;
font-style:normal;
font-weight:700;
line-height:normal;
display:flex;
align-items:center;
gap:8px;
}
.logo {
width: 32px;
height: 32px;
width:32px;
height:32px;
}
.search-title {
color: var(--text-primary);
text-align: center;
font-family: Montserrat;
font-size: 24px;
font-style: normal;
font-weight: 600;
line-height: normal;
margin: 8px 0;
color:var(--text-primary);
text-align:center;
font-family:Montserrat;
font-size:24px;
font-style:normal;
font-weight:600;
line-height:normal;
margin:8px 0;
}
/* Form container styling */
.firka-form-container {
background: var(--card-card);
padding: 0 24px 24px 24px;
border-radius: 0 0 24px 24px;
width: 100%;
box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow);
background:var(--card-card);
padding:0 24px 24px 24px;
border-radius:0 0 24px 24px;
width:100%;
box-shadow:0px 1px var(--shadow-blur) 0px var(--accent-shadow);
}
/* Form styling */
form {
width: 100%;
width:100%;
}
.form-control {
background-color: var(--button-secondaryFill) !important;
border: 1px solid var(--accent-15) !important;
border-radius: 12px !important;
color: var(--text-primary) !important;
padding: 12px 16px !important;
font-family: Montserrat !important;
font-size: 16px !important;
font-weight: 400 !important;
height: auto !important;
transition: border-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
background-color:var(--button-secondaryFill) !important;
border:1px solid var(--accent-15) !important;
border-radius:12px !important;
color:var(--text-primary) !important;
padding:12px 16px !important;
font-family:Montserrat !important;
font-size:16px !important;
font-weight:400 !important;
height:auto !important;
transition:border-color 0.2s ease-in-out,box-shadow 0.2s ease-in-out;
}
.form-control:focus {
border-color: var(--accent-accent) !important;
box-shadow: 0 0 0 2px var(--accent-15) !important;
outline: none !important;
border-color:var(--accent-accent) !important;
box-shadow:0 0 0 2px var(--accent-15) !important;
outline:none !important;
}
.form-control::placeholder {
color: var(--text-teritary) !important;
color:var(--text-teritary) !important;
}
/* Autocomplete dropdown styling */
.dropdown-menu {
background-color: var(--card-card) !important;
border: 1px solid var(--accent-15) !important;
border-radius: 12px !important;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1) !important;
padding: 8px !important;
max-height: 300px !important;
overflow-y: auto !important;
width: 100% !important;
background-color:var(--card-card) !important;
border:1px solid var(--accent-15) !important;
border-radius:12px !important;
box-shadow:0 4px 8px rgba(0,0,0,0.1) !important;
padding:8px !important;
max-height:300px !important;
overflow-y:auto !important;
width:100% !important;
}
.dropdown-item {
color: var(--text-primary) !important;
padding: 10px 16px !important;
border-radius: 8px !important;
margin-bottom: 4px !important;
font-family: Montserrat !important;
font-size: 14px !important;
transition: background-color 0.2s ease-in-out !important;
color:var(--text-primary) !important;
padding:10px 16px !important;
border-radius:8px !important;
margin-bottom:4px !important;
font-family:Montserrat !important;
font-size:14px !important;
transition:background-color 0.2s ease-in-out !important;
}
li.dropdown-item:hover, li.dropdown-item:focus {
background-color: var(--accent-15) !important;
color: var(--text-primary) !important;
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;
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;
color: white !important;
background-color:var(--accent-accent) !important;
color:white !important;
}
/* Button styling */
.btn-kreta {
background-color: var(--accent-accent) !important;
color: white !important;
border: none !important;
border-radius: 12px !important;
padding: 12px 24px !important;
font-family: Montserrat !important;
font-size: 16px !important;
font-weight: 600 !important;
cursor: pointer !important;
transition: background-color 0.2s ease-in-out, transform 0.1s ease-in-out !important;
display: inline-flex !important;
align-items: center !important;
justify-content: center !important;
background-color:var(--accent-accent) !important;
color:white !important;
border:none !important;
border-radius:12px !important;
padding:12px 24px !important;
font-family:Montserrat !important;
font-size:16px !important;
font-weight:600 !important;
cursor:pointer !important;
transition:background-color 0.2s ease-in-out,transform 0.1s ease-in-out !important;
display:inline-flex !important;
align-items:center !important;
justify-content:center !important;
}
.btn-kreta:hover {
background-color: var(--accent-secondary) !important;
transform: translateY(-1px) !important;
background-color:var(--accent-secondary) !important;
transform:translateY(-1px) !important;
}
.btn-kreta:active {
transform: translateY(1px) !important;
transform:translateY(1px) !important;
}
.btn-kreta:disabled {
background-color: var(--text-teritary) !important;
cursor: not-allowed !important;
transform: none !important;
background-color:var(--text-teritary) !important;
cursor:not-allowed !important;
transform:none !important;
}
/* Footer styling */
.firka-footer {
margin-top: 16px;
text-align: center;
width: 100%;
margin-top:16px;
text-align:center;
width:100%;
}
.privacy-link {
color: var(--text-secondary);
font-family: Montserrat;
font-size: 14px;
text-decoration: none;
transition: color 0.2s ease-in-out;
color:var(--text-secondary);
font-family:Montserrat;
font-size:14px;
text-decoration:none;
transition:color 0.2s ease-in-out;
}
.privacy-link:hover {
color: var(--accent-accent);
text-decoration: underline;
color:var(--accent-accent);
text-decoration:underline;
}
/* Responsive adjustments */
@media (max-width: 576px) {
@media (max-width:576px) {
.firka-search-wrapper {
width: 95%;
}
.search-title {
font-size: 20px;
}
.btn-kreta {
padding: 10px 20px !important;
font-size: 14px !important;
}
width:95%;
}
.search-title {
font-size:20px;
}
.btn-kreta {
padding:10px 20px !important;
font-size:14px !important;
}
}

View File

@@ -1,7 +1,7 @@
function initializeTransformation() {
const form = document.querySelector('form');
const autocomplete = document.querySelector('.autocomplete');
const form = document.querySelector("form");
const autocomplete = document.querySelector(".autocomplete");
if (form && autocomplete) {
applyFirkaStyling();
} else {
@@ -9,46 +9,67 @@ function initializeTransformation() {
}
}
document.addEventListener('DOMContentLoaded', () => {
document.addEventListener("DOMContentLoaded", () => {
setTimeout(initializeTransformation, 1000);
});
if (document.readyState === 'complete' || document.readyState === 'interactive') {
if (
document.readyState === "complete" ||
document.readyState === "interactive"
) {
setTimeout(initializeTransformation, 1000);
}
function applyFirkaStyling() {
async function applyFirkaStyling() {
try {
const theme = cookieManager.get('themePreference') || localStorage.getItem('themePreference') || 'light-green';
document.documentElement.setAttribute('data-theme', theme);
if (typeof loadingScreen !== 'undefined') {
const theme =
await storageManager.get("themePreference") ||
localStorage.getItem("themePreference") ||
"light-green";
document.documentElement.setAttribute("data-theme", theme);
if (typeof loadingScreen !== "undefined") {
loadingScreen.hide();
}
const originalForm = document.querySelector('form');
const instituteInput = document.querySelector('.autocomplete');
const redirectButton = document.getElementById('redirectToInstitute');
const instituteCodeInput = document.querySelector('.autocomplete-value');
const requestToken = document.querySelector('input[name="__RequestVerificationToken"]');
const searchWrapper = document.createElement('div');
searchWrapper.className = 'firka-search-wrapper';
const firkaHeader = document.createElement('div');
firkaHeader.className = 'firka-header';
firkaHeader.innerHTML = `
<p class="logo-text">
<img src="${chrome.runtime.getURL('images/firka_logo.png')}" alt="Firka" class="logo">
Firka
</p>
<h1 class="search-title">Válassz iskolát</h1>
`;
const formContainer = document.createElement('div');
formContainer.className = 'firka-form-container';
const firkaFooter = document.createElement('div');
firkaFooter.className = 'firka-footer';
firkaFooter.innerHTML = `
<a href="https://tudasbazis.ekreta.hu/pages/viewpage.action?pageId=4064926"
target="_blank" class="privacy-link">Adatkezelési tájékoztató</a>
`;
const existingWrapper = document.querySelector('.firka-search-wrapper');
const originalForm = document.querySelector("form");
const instituteInput = document.querySelector(".autocomplete");
const redirectButton = document.getElementById("redirectToInstitute");
const instituteCodeInput = document.querySelector(".autocomplete-value");
const requestToken = document.querySelector(
'input[name="__RequestVerificationToken"]',
);
const searchWrapper = document.createElement("div");
searchWrapper.className = "firka-search-wrapper";
const firkaHeader = document.createElement("div");
firkaHeader.className = "firka-header";
const logoText = document.createElement('p');
logoText.className = 'logo-text';
const logoImg = document.createElement('img');
logoImg.src = chrome.runtime.getURL('images/firka_logo.png');
logoImg.alt = 'Firka';
logoImg.className = 'logo';
logoText.appendChild(logoImg);
logoText.appendChild(document.createTextNode('Firka'));
const searchTitle = document.createElement('h1');
searchTitle.className = 'search-title';
searchTitle.textContent = 'Válassz iskolát';
firkaHeader.appendChild(logoText);
firkaHeader.appendChild(searchTitle);
const formContainer = document.createElement("div");
formContainer.className = "firka-form-container";
const firkaFooter = document.createElement("div");
firkaFooter.className = "firka-footer";
const privacyLink = document.createElement('a');
privacyLink.href = 'https://tudasbazis.ekreta.hu/pages/viewpage.action?pageId=4064926';
privacyLink.target = '_blank';
privacyLink.className = 'privacy-link';
privacyLink.textContent = 'Adatkezelési tájékoztató';
firkaFooter.appendChild(privacyLink);
const existingWrapper = document.querySelector(".firka-search-wrapper");
if (existingWrapper) {
existingWrapper.remove();
}
@@ -61,33 +82,32 @@ function applyFirkaStyling() {
document.body.appendChild(searchWrapper);
setupAutocompleteListeners();
if (redirectButton) {
redirectButton.addEventListener('click', function(event) {
redirectButton.addEventListener("click", function (event) {
if (!instituteCodeInput.value) {
event.preventDefault();
alert(LanguageManager.t('search.select_institution'));
alert(LanguageManager.t("search.select_institution"));
}
});
}
observeAutocompleteValue(instituteCodeInput, redirectButton);
} catch (error) {
console.error('Error applying Firka styling:', error);
}
}
function setupAutocompleteListeners() {
const autocompleteInput = document.querySelector('.autocomplete');
const autocompleteValue = document.querySelector('.autocomplete-value');
const redirectButton = document.getElementById('redirectToInstitute');
const autocompleteInput = document.querySelector(".autocomplete");
const autocompleteValue = document.querySelector(".autocomplete-value");
const redirectButton = document.getElementById("redirectToInstitute");
if (autocompleteInput && autocompleteValue) {
const observer = new MutationObserver((mutations) => {
const dropdown = document.querySelector('.autocomplete-dropdown');
const dropdown = document.querySelector(".autocomplete-dropdown");
if (dropdown) {
dropdown.classList.add('dropdown-menu');
const items = dropdown.querySelectorAll('li');
items.forEach(item => {
item.classList.add('dropdown-item');
item.addEventListener('click', () => {
dropdown.classList.add("dropdown-menu");
const items = dropdown.querySelectorAll("li");
items.forEach((item) => {
item.classList.add("dropdown-item");
item.addEventListener("click", () => {
if (redirectButton) {
redirectButton.disabled = false;
}
@@ -95,10 +115,10 @@ function setupAutocompleteListeners() {
});
}
});
observer.observe(document.body, {
childList: true,
subtree: true
subtree: true,
});
}
}
@@ -112,7 +132,7 @@ function observeAutocompleteValue(valueInput, button) {
observer.observe(valueInput, {
attributes: true,
attributeFilter: ['value']
attributeFilter: ["value"],
});
const checkInterval = setInterval(() => {
@@ -121,4 +141,4 @@ function observeAutocompleteValue(valueInput, button) {
clearInterval(checkInterval);
}
}, 500);
}
}

View File

@@ -1,308 +1,250 @@
* {
box-sizing: border-box;
margin: 0;
padding: 0;
box-sizing:border-box;
margin:0;
padding:0;
}
body {
width: 400px;
margin: 0;
padding: 0;
color: var(--text-primary);
background-color: var(--background) !important;
font-family: "Montserrat", serif;
font-size: 14px;
width:400px;
margin:0;
padding:0;
color:var(--text-primary);
background-color:var(--background) !important;
font-family:"Montserrat",serif;
font-size:14px;
}
* {
scrollbar-width: none;
-ms-overflow-style: none;
scrollbar-width:none;
-ms-overflow-style:none;
}
*::-webkit-scrollbar {
display: none;
display:none;
}
.popup-container {
padding: 16px;
padding:16px;
}
.popup-header {
text-align: center;
margin-bottom: 16px;
text-align:center;
margin-bottom:16px;
}
.logo-text {
color: var(--text-primary);
font-size: 20px;
font-weight: 600;
margin: 8px 0;
display: flex;
align-items: center;
justify-content: center;
color:var(--text-primary);
font-size:20px;
font-weight:600;
margin:8px 0;
display:flex;
align-items:center;
justify-content:center;
}
.logo {
width: 20px;
border-radius: 6px;
margin-right: 8px;
width:20px;
border-radius:6px;
margin-right:8px;
}
.settings-card,
.about-card,
.support-card {
background: var(--card-card);
border-radius: 16px;
padding: 16px;
margin-bottom: 16px;
box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow);
.settings-card,.about-card,.support-card {
background:var(--card-card);
border-radius:16px;
padding:16px;
margin-bottom:16px;
box-shadow:0px 1px var(--shadow-blur) 0px var(--accent-shadow);
}
h2 {
font-size: 16px;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 12px;
background-color: var(--card-card);
font-size:16px;
font-weight:600;
color:var(--text-primary);
margin-bottom:12px;
background-color:var(--card-card);
}
.settings-group {
display: flex;
flex-direction: column;
gap: 16px;
display:flex;
flex-direction:column;
gap:16px;
}
.setting-section {
display: flex;
flex-direction: column;
gap: 12px;
display:flex;
flex-direction:column;
gap:12px;
}
.setting-header {
display: flex;
align-items: center;
gap: 8px;
color: var(--text-primary);
font-weight: 500;
display:flex;
align-items:center;
gap:8px;
color:var(--text-primary);
font-weight:500;
}
.theme-grid,
.language-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
.theme-grid,.language-grid {
display:grid;
grid-template-columns:repeat(2,1fr);
gap:12px;
}
.theme-option,
.language-option {
background: none;
border: none;
padding: 0;
cursor: pointer;
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
transition: transform 0.2s ease;
.theme-option,.language-option {
background:none;
border:none;
padding:0;
cursor:pointer;
display:flex;
flex-direction:column;
align-items:center;
gap:8px;
transition:transform 0.2s ease;
}
.theme-option:hover,
.language-option:hover {
transform: translateY(-2px);
.theme-option:hover,.language-option:hover {
transform:translateY(-2px);
}
.theme-option.active .theme-preview {
outline: 2px solid var(--accent-accent);
outline-offset: 2px;
outline:2px solid var(--accent-accent);
outline-offset:2px;
}
.language-option.active .language-preview {
outline: 2px solid var(--accent-accent);
outline-offset: 2px;
outline:2px solid var(--accent-accent);
outline-offset:2px;
}
.theme-preview {
width: 100%;
height: 100px;
border-radius: 8px;
overflow: hidden;
position: relative;
width:100%;
height:100px;
border-radius:8px;
overflow:hidden;
position:relative;
}
.theme-option.disabled {
opacity: 0.5;
cursor: not-allowed;
position: relative;
opacity:0.5;
cursor:not-allowed;
position:relative;
}
.theme-option.disabled::after {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.1);
border-radius: 8px;
content:"";
position:absolute;
top:0;
left:0;
width:100%;
height:100%;
background-color:rgba(0,0,0,0.1);
border-radius:8px;
}
.language-option {
background: var(--card-card);
border: 1px solid var(--border-border);
border-radius: 8px;
padding: 12px;
transition: all 0.2s ease;
background:var(--card-card);
border:1px solid var(--border-border);
border-radius:8px;
padding:12px;
transition:all 0.2s ease;
}
.language-option:hover {
background: var(--card-hover);
border-color: var(--accent-accent);
background:var(--card-hover);
border-color:var(--accent-accent);
}
.language-option.active {
background: var(--accent-accent);
border-color: var(--accent-accent);
color: white;
background:var(--accent-accent);
border-color:var(--accent-accent);
color:white;
}
.language-name {
color: var(--text-primary);
font-size: 12px;
font-weight: 500;
color:var(--text-primary);
font-size:12px;
font-weight:500;
}
.theme-preview.light-blue {
background: #DAE4F7;
background:#DAE4F7;
}
.theme-preview.light-blue .preview-header {
background: #EDF3FF;
background:#EDF3FF;
}
.theme-preview.light-blue .preview-card {
background: #FBFCFF;
background:#FBFCFF;
}
.theme-preview.light-green {
background: #FAFFF0;
background:#FAFFF0;
}
.theme-preview.light-green .preview-header {
background: #F3FBDE;
background:#F3FBDE;
}
.theme-preview.light-green .preview-card {
background: #FEFFFD;
background:#FEFFFD;
}
.theme-preview.dark-blue {
background: #070A0E;
background:#070A0E;
}
.theme-preview.dark-blue .preview-header {
background: #0F131B;
background:#0F131B;
}
.theme-preview.dark-blue .preview-card {
background: #131822;
background:#131822;
}
.theme-preview.dark-green {
background: #0D1202;
background:#0D1202;
}
.theme-preview.dark-green .preview-header {
background: #141905;
background:#141905;
}
.theme-preview.dark-green .preview-card {
background: #20290b;
background:#20290b;
}
.preview-header {
height: 30%;
width: 100%;
height:30%;
width:100%;
}
.preview-content {
padding: 8px;
padding:8px;
}
.preview-card {
height: 30px;
border-radius: 4px;
height:30px;
border-radius:4px;
}
.theme-name {
color: var(--text-primary);
font-size: 12px;
font-weight: 500;
color:var(--text-primary);
font-size:12px;
font-weight:500;
}
.about-content,
.support-content {
color: var(--text-secondary);
font-size: 14px;
line-height: 1.5;
.about-content,.support-content {
color:var(--text-secondary);
font-size:14px;
line-height:1.5;
}
.about-content p,
.support-content p {
margin-bottom: 12px;
.about-content p,.support-content p {
margin-bottom:12px;
}
.github-link {
display: inline-flex;
align-items: center;
gap: 6px;
color: var(--accent-accent);
text-decoration: none;
font-weight: 500;
transition: color 0.2s;
display:inline-flex;
align-items:center;
gap:6px;
color:var(--accent-accent);
text-decoration:none;
font-weight:500;
transition:color 0.2s;
}
.github-link:hover {
color: var(--accent-secondary);
color:var(--accent-secondary);
}
.support-buttons {
display: flex;
gap: 8px;
margin-top: 12px;
display:flex;
gap:8px;
margin-top:12px;
}
.support-button {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
padding: 8px;
background: var(--accent-15);
color: var(--text-primary);
text-decoration: none;
border-radius: 8px;
font-weight: 500;
transition: all 0.2s;
flex:1;
display:flex;
align-items:center;
justify-content:center;
gap:6px;
padding:8px;
background:var(--accent-15);
color:var(--text-primary);
text-decoration:none;
border-radius:8px;
font-weight:500;
transition:all 0.2s;
}
.support-button:hover {
background: var(--accent-accent);
color: var(--button-secondaryFill);
background:var(--accent-accent);
color:var(--button-secondaryFill);
}
.popup-footer {
text-align: center;
margin-top: 16px;
text-align:center;
margin-top:16px;
}
.version-info {
color: var(--text-secondary);
font-size: 12px;
color:var(--text-secondary);
font-size:12px;
}
.material-icons-round {
font-size: 18px;
vertical-align: middle;
}
font-size:18px;
vertical-align:middle;
}

View File

@@ -17,7 +17,7 @@
<div class="popup-container">
<header class="popup-header">
<p class="logo-text">
<img src="https://i.imgur.com/WugwlzI.png" alt="Firka" class="logo">
<img src="../images/firka_logo.png" alt="Firka" class="logo">
Firxa
</p>
</header>

View File

@@ -1,181 +1,189 @@
document.addEventListener('DOMContentLoaded', async () => {
while (typeof window.LanguageManager === 'undefined') {
await new Promise(resolve => setTimeout(resolve, 10));
}
function isThemeDisabled(theme) {
const blueThemesUnlocked = localStorage.getItem('blueThemesUnlocked') === 'true';
return (theme === 'default' || theme === 'light-blue' || theme === 'dark-blue') && !blueThemesUnlocked;
}
function updateThemeAvailability() {
const blueThemesUnlocked = localStorage.getItem('blueThemesUnlocked') === 'true';
document.querySelectorAll('.theme-option').forEach(button => {
const theme = button.dataset.theme;
if (theme === 'default' || theme === 'light-blue' || theme === 'dark-blue') {
if (blueThemesUnlocked) {
button.style.display = 'block';
button.classList.remove('disabled');
button.removeAttribute('disabled');
} else {
button.style.display = 'none';
}
}
});
}
function getCookie(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;
document.addEventListener("DOMContentLoaded", async () => {
while (typeof window.LanguageManager === "undefined") {
await new Promise((resolve) => setTimeout(resolve, 10));
}
function isThemeDisabled(theme) {
const blueThemesUnlocked =
localStorage.getItem("blueThemesUnlocked") === "true";
return (
(theme === "default" ||
theme === "light-blue" ||
theme === "dark-blue") &&
!blueThemesUnlocked
);
}
function updateThemeAvailability() {
const blueThemesUnlocked =
localStorage.getItem("blueThemesUnlocked") === "true";
document.querySelectorAll(".theme-option").forEach((button) => {
const theme = button.dataset.theme;
if (
theme === "default" ||
theme === "light-blue" ||
theme === "dark-blue"
) {
if (blueThemesUnlocked) {
button.style.display = "block";
button.classList.remove("disabled");
button.removeAttribute("disabled");
} else {
button.style.display = "none";
}
}
});
}
function getCookie(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;
}
function setCookie(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`;
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`;
}
function getCurrentTheme() {
return localStorage.getItem('themePreference') ||
getCookie('themePreference') ||
'light-green';
return (
localStorage.getItem("themePreference") ||
getCookie("themePreference") ||
"light-green"
);
}
function updateThemeButtons(currentTheme) {
document.querySelectorAll('.theme-option').forEach(button => {
const theme = button.dataset.theme;
button.classList.toggle('active', theme === currentTheme);
});
updateThemeAvailability();
document.querySelectorAll(".theme-option").forEach((button) => {
const theme = button.dataset.theme;
button.classList.toggle("active", theme === currentTheme);
});
updateThemeAvailability();
}
function getCurrentLanguage() {
return localStorage.getItem('languagePreference') ||
getCookie('languagePreference') ||
'hu';
return (
localStorage.getItem("languagePreference") ||
getCookie("languagePreference") ||
"hu"
);
}
function updateLanguageButtons(currentLanguage) {
document.querySelectorAll('.language-option').forEach(button => {
const language = button.dataset.language;
button.classList.toggle('active', language === currentLanguage);
});
document.querySelectorAll(".language-option").forEach((button) => {
const language = button.dataset.language;
button.classList.toggle("active", language === currentLanguage);
});
}
async function applyLanguage(language) {
setCookie('languagePreference', language);
localStorage.setItem('languagePreference', language);
setCookie("languagePreference", language);
localStorage.setItem("languagePreference", language);
updateLanguageButtons(language);
updateLanguageButtons(language);
const tabs = await chrome.tabs.query({});
tabs.forEach(tab => {
chrome.tabs.sendMessage(tab.id, {
action: 'changeLanguage',
language: language
}).catch(() => {
});
});
const tabs = await chrome.tabs.query({});
tabs.forEach((tab) => {
chrome.tabs
.sendMessage(tab.id, {
action: "changeLanguage",
language: language,
})
.catch(() => {});
});
}
async function applyTheme(theme) {
setCookie('themePreference', theme);
localStorage.setItem('themePreference', theme);
document.documentElement.setAttribute('data-theme', theme);
updateThemeButtons(theme);
const tabs = await chrome.tabs.query({});
tabs.forEach(tab => {
chrome.tabs.sendMessage(tab.id, {
action: 'changeTheme',
theme: theme
}).catch(() => {
});
});
setCookie("themePreference", theme);
localStorage.setItem("themePreference", theme);
document.documentElement.setAttribute("data-theme", theme);
updateThemeButtons(theme);
const tabs = await chrome.tabs.query({});
tabs.forEach((tab) => {
chrome.tabs
.sendMessage(tab.id, {
action: "changeTheme",
theme: theme,
})
.catch(() => {});
});
}
const themeButtons = document.querySelectorAll('.theme-option');
themeButtons.forEach(button => {
button.addEventListener('click', () => {
const theme = button.dataset.theme;
if (button.hasAttribute('disabled')) {
alert(window.LanguageManager.t('common.warning') + ': ' + window.LanguageManager.t('settings.theme_not_available'));
return;
}
applyTheme(theme);
});
const themeButtons = document.querySelectorAll(".theme-option");
themeButtons.forEach((button) => {
button.addEventListener("click", () => {
const theme = button.dataset.theme;
if (button.hasAttribute("disabled")) {
alert(
window.LanguageManager.t("common.warning") +
": " +
window.LanguageManager.t("settings.theme_not_available"),
);
return;
}
applyTheme(theme);
});
});
const languageButtons = document.querySelectorAll('.language-option');
languageButtons.forEach(button => {
button.addEventListener('click', () => {
const language = button.dataset.language;
applyLanguage(language);
});
const languageButtons = document.querySelectorAll(".language-option");
languageButtons.forEach((button) => {
button.addEventListener("click", () => {
const language = button.dataset.language;
applyLanguage(language);
});
});
let initialTheme = getCurrentTheme();
if (isThemeDisabled(initialTheme)) {
initialTheme = 'light-green';
initialTheme = "light-green";
}
updateThemeAvailability();
await applyTheme(initialTheme);
const initialLanguage = getCurrentLanguage();
updateLanguageButtons(initialLanguage);
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === 'themeChanged') {
updateThemeButtons(message.theme);
document.documentElement.setAttribute('data-theme', message.theme);
}
if (message.action === "themeChanged") {
updateThemeButtons(message.theme);
document.documentElement.setAttribute("data-theme", message.theme);
}
});
const manifest = chrome.runtime.getManifest();
const versionElement = document.getElementById('version');
const versionElement = document.getElementById("version");
versionElement.textContent = `v${manifest.version}`;
let clickCount = 0;
versionElement.addEventListener('click', () => {
clickCount++;
if (clickCount >= 5) {
localStorage.setItem('blueThemesUnlocked', 'true');
updateThemeAvailability();
const notification = document.createElement('div');
notification.style.cssText = `
versionElement.addEventListener("click", () => {
clickCount++;
if (clickCount >= 5) {
localStorage.setItem("blueThemesUnlocked", "true");
updateThemeAvailability();
const notification = document.createElement("div");
notification.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
@@ -189,54 +197,54 @@ document.addEventListener('DOMContentLoaded', async () => {
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
animation: slideIn 0.3s ease-out;
`;
notification.textContent = window.LanguageManager.t('common.success') + ': ' + window.LanguageManager.t('settings.blue_themes_unlocked');
const style = document.createElement('style');
style.textContent = `
notification.textContent =
window.LanguageManager.t("common.success") +
": " +
window.LanguageManager.t("settings.blue_themes_unlocked");
const style = document.createElement("style");
style.textContent = `
@keyframes slideIn {
from { transform: translateX(100%); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
`;
document.head.appendChild(style);
document.body.appendChild(notification);
setTimeout(() => {
notification.remove();
style.remove();
}, 3000);
clickCount = 0;
document.head.appendChild(style);
document.body.appendChild(notification);
setTimeout(() => {
notification.remove();
style.remove();
}, 3000);
clickCount = 0;
}
});
themeButtons.forEach((button) => {
button.addEventListener("mouseover", () => {
if (!button.hasAttribute("disabled")) {
button.style.transform = "translateY(-2px)";
}
});
button.addEventListener("mouseout", () => {
button.style.transform = "translateY(0)";
});
});
themeButtons.forEach(button => {
button.addEventListener('mouseover', () => {
if (!button.hasAttribute('disabled')) {
button.style.transform = 'translateY(-2px)';
}
});
button.addEventListener('mouseout', () => {
button.style.transform = 'translateY(0)';
});
languageButtons.forEach((button) => {
button.addEventListener("mouseover", () => {
button.style.transform = "translateY(-2px)";
});
button.addEventListener("mouseout", () => {
button.style.transform = "translateY(0)";
});
});
languageButtons.forEach(button => {
button.addEventListener('mouseover', () => {
button.style.transform = 'translateY(-2px)';
});
button.addEventListener('mouseout', () => {
button.style.transform = 'translateY(0)';
});
window.addEventListener("languageChanged", (event) => {
updateLanguageButtons(event.detail.language);
});
window.addEventListener('languageChanged', (event) => {
updateLanguageButtons(event.detail.language);
});
});
});

File diff suppressed because it is too large Load Diff

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,26 +1,25 @@
const createTemplate = {
header() {
const data = {
schoolInfo: {
name: cookieManager.get('schoolName') || 'Iskola',
id: cookieManager.get('schoolCode') || ''
},
userData: {
name: cookieManager.get('userName') || 'Felhasználó',
time: document.querySelector('.usermenu_timer')?.textContent?.trim() || '45:00',
email: cookieManager.get('userEmail') || ''
}
};
async header() {
const data = {
schoolInfo: {
name: await storageManager.get("schoolName", "OM azonosító - Iskola neve"),
id: await storageManager.get("schoolCode", ""),
},
userData: {
name: await storageManager.get("userName", "Felhasználónév"),
time:
document.querySelector(".usermenu_timer")?.textContent?.trim() ||
"45:00",
},
};
const schoolNameFull = `${data.schoolInfo.id} - ${data.schoolInfo.name}`;
const shortenedSchoolName = helper.shortenSchoolName(schoolNameFull);
const schoolNameFull = `${data.schoolInfo.id} - ${data.schoolInfo.name}`;
const shortenedSchoolName = helper.shortenSchoolName(schoolNameFull);
const element = `<header class="kreta-header">
const element = `<header class="kreta-header">
<div class="school-info">
<p class="logo-text">
<img src="${chrome.runtime.getURL('images/firka_logo.png')}" alt="Firka" class="logo">
<img src="${chrome.runtime.getURL("images/firka_logo.png")}" alt="Firka" class="logo">
Firka
</p>
<div class="school-details" title="${schoolNameFull}">
@@ -28,7 +27,7 @@ const createTemplate = {
</div>
</div>
<button class="nav-toggle" aria-label="${LanguageManager.t('navigation.nav_toggle')}">
<button class="nav-toggle" aria-label="${LanguageManager.t("navigation.nav_toggle")}">
<svg viewBox="0 0 24 24">
<path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"/>
</svg>
@@ -36,25 +35,25 @@ const createTemplate = {
<nav class="kreta-nav">
<div class="nav-links">
<a href="/Intezmeny/Faliujsag" data-page="dashboard" class="nav-item ${( location.pathname == '/Intezmeny/Faliujsag' ? 'active' : '')}">
<img src="${chrome.runtime.getURL('icons/dashboard-' + ( location.pathname == '/Intezmeny/Faliujsag' ? 'active' : 'inactive') + '.svg')}" alt="${LanguageManager.t('navigation.dashboard')}">
${LanguageManager.t('navigation.dashboard')}
<a href="/Intezmeny/Faliujsag" data-page="dashboard" class="nav-item ${location.pathname == "/Intezmeny/Faliujsag" ? "active" : ""}">
<img src="${chrome.runtime.getURL("icons/dashboard-" + (location.pathname == "/Intezmeny/Faliujsag" ? "active" : "inactive") + ".svg")}" alt="${LanguageManager.t("navigation.dashboard")}">
${LanguageManager.t("navigation.dashboard")}
</a>
<a href="/TanuloErtekeles/Osztalyzatok" data-page="grades" class="nav-item ${( location.pathname == '/TanuloErtekeles/Osztalyzatok' ? 'active' : '')}">
<img src="${chrome.runtime.getURL('icons/grades-' + ( location.pathname == '/TanuloErtekeles/Osztalyzatok' ? 'active' : 'inactive') + '.svg')}" alt="${LanguageManager.t('navigation.grades')}">
${LanguageManager.t('navigation.grades')}
<a href="/TanuloErtekeles/Osztalyzatok" data-page="grades" class="nav-item ${location.pathname == "/TanuloErtekeles/Osztalyzatok" ? "active" : ""}">
<img src="${chrome.runtime.getURL("icons/grades-" + (location.pathname == "/TanuloErtekeles/Osztalyzatok" ? "active" : "inactive") + ".svg")}" alt="${LanguageManager.t("navigation.grades")}">
${LanguageManager.t("navigation.grades")}
</a>
<a href="/Orarend/InformaciokOrarend" data-page="timetable" class="nav-item ${( location.pathname == '/Orarend/InformaciokOrarend' ? 'active' : '')}">
<img src="${chrome.runtime.getURL('icons/timetable-' + ( location.pathname == '/Orarend/InformaciokOrarend' ? 'active' : 'inactive') + '.svg')}" alt="${LanguageManager.t('navigation.timetable')}">
${LanguageManager.t('navigation.timetable')}
<a href="/Orarend/InformaciokOrarend" data-page="timetable" class="nav-item ${location.pathname == "/Orarend/InformaciokOrarend" ? "active" : ""}">
<img src="${chrome.runtime.getURL("icons/timetable-" + (location.pathname == "/Orarend/InformaciokOrarend" ? "active" : "inactive") + ".svg")}" alt="${LanguageManager.t("navigation.timetable")}">
${LanguageManager.t("navigation.timetable")}
</a>
<a href="/Hianyzas/Hianyzasok" data-page="absences" class="nav-item ${( location.pathname == '/Hianyzas/Hianyzasok' ? 'active' : '')}">
<img src="${chrome.runtime.getURL('icons/absences-' + ( location.pathname == '/Hianyzas/Hianyzasok' ? 'active' : 'inactive') + '.svg')}" alt="${LanguageManager.t('navigation.absences')}">
${LanguageManager.t('navigation.absences')}
<a href="/Hianyzas/Hianyzasok" data-page="absences" class="nav-item ${location.pathname == "/Hianyzas/Hianyzasok" ? "active" : ""}">
<img src="${chrome.runtime.getURL("icons/absences-" + (location.pathname == "/Hianyzas/Hianyzasok" ? "active" : "inactive") + ".svg")}" alt="${LanguageManager.t("navigation.absences")}">
${LanguageManager.t("navigation.absences")}
</a>
<a href="/Tanulo/TanuloHaziFeladat" data-page="other" class="nav-item ${( location.pathname == '/Tanulo/TanuloHaziFeladat' ? 'active' : '')}">
<img src="${chrome.runtime.getURL('icons/others.svg')}" alt="${LanguageManager.t('navigation.other')}">
${LanguageManager.t('navigation.other')}
<a href="/Tanulo/TanuloHaziFeladat" data-page="other" class="nav-item ${location.pathname == "/Tanulo/TanuloHaziFeladat" ? "active" : ""}">
<img src="${chrome.runtime.getURL("icons/others.svg")}" alt="${LanguageManager.t("navigation.other")}">
${LanguageManager.t("navigation.other")}
</a>
</div>
</nav>
@@ -68,73 +67,55 @@ const createTemplate = {
</button>
<div class="user-dropdown">
<a href="https://bmszc-puskas.e-kreta.hu/Home/Uzenetek" data-page="messages" class="dropdown-item">
<img src="${chrome.runtime.getURL('icons/messages.svg')}" alt="${LanguageManager.t('navigation.messages')}">
${LanguageManager.t('navigation.messages')}
<img src="${chrome.runtime.getURL("icons/messages.svg")}" alt="${LanguageManager.t("navigation.messages")}">
${LanguageManager.t("navigation.messages")}
</a>
<a href="/Adminisztracio/Profil" data-page="profile" class="dropdown-item">
<img src="${chrome.runtime.getURL('icons/profile.svg')}" alt="${LanguageManager.t('navigation.profile')}">
${LanguageManager.t('navigation.profile')}
<img src="${chrome.runtime.getURL("icons/profile.svg")}" alt="${LanguageManager.t("navigation.profile")}">
${LanguageManager.t("navigation.profile")}
</a>
<a href="#" class="dropdown-item" id="settingsBtn">
<img src="${chrome.runtime.getURL('icons/settings.svg')}" alt="${LanguageManager.t('navigation.settings')}">
${LanguageManager.t('navigation.settings')}
<img src="${chrome.runtime.getURL("icons/settings.svg")}" alt="${LanguageManager.t("navigation.settings")}">
${LanguageManager.t("navigation.settings")}
</a>
<a href="/Home/Logout" data-page="logout" class="dropdown-item">
<img src="${chrome.runtime.getURL('icons/logout.svg')}" alt="${LanguageManager.t('navigation.logout')}">
${LanguageManager.t('navigation.logout')}
<img src="${chrome.runtime.getURL("icons/logout.svg")}" alt="${LanguageManager.t("navigation.logout")}">
${LanguageManager.t("navigation.logout")}
</a>
</div>
</div>
</header>`
</header>`;
const startTime = parseInt(data.userData.time?.match(/\d+/)?.[0] || "45");
let timeLeft = startTime * 60;
const updateTimer = () => {
const minutes = Math.floor(timeLeft / 60);
const seconds = timeLeft % 60;
const timerEl = document.getElementById('logoutTimer');
if (timerEl) {
timerEl.textContent = `${minutes}:${seconds.toString().padStart(2, '0')}`;
}
if (timeLeft <= 0) {
window.location.href = '/Home/Logout';
} else {
timeLeft--;
}
};
const startTime = parseInt(data.userData.time?.match(/\d+/)?.[0] || "45");
let timeLeft = startTime * 60;
setInterval(updateTimer, 1000);
const updateTimer = () => {
const minutes = Math.floor(timeLeft / 60);
const seconds = timeLeft % 60;
const timerEl = document.getElementById("logoutTimer");
if (timerEl) {
timerEl.textContent = `${minutes}:${seconds.toString().padStart(2, "0")}`;
}
return element;
},
if (timeLeft <= 0) {
window.location.href = "/Home/Logout";
} else {
timeLeft--;
}
};
importFonts() {
const links = [
{ rel: 'preconnect', href: 'https://fonts.googleapis.com' },
{ rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: true },
{ rel: 'stylesheet', href: 'https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap' },
{ rel: 'stylesheet', href: 'https://fonts.googleapis.com/css2?family=Figtree:ital,wght@0,300..900;1,300..900&display=swap' },
{ rel: 'stylesheet', href: 'https://fonts.googleapis.com/icon?family=Material+Icons+Round' }
];
links.forEach(link => {
const linkElement = document.createElement('link');
Object.entries(link).forEach(([key, value]) => {
linkElement[key] = value;
});
document.head.appendChild(linkElement);
});
}
}
setInterval(updateTimer, 1000);
return element;
},
};
document.addEventListener("DOMContentLoaded", async () => {
await helper.waitForElement('#settingsBtn');
document.querySelector('#settingsBtn').addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
const url = chrome.runtime.getURL('settings/index.html');
window.open(url, '_blank', 'width=400,height=600');
});
});
await helper.waitForElement("#settingsBtn");
document.querySelector("#settingsBtn").addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();
const url = chrome.runtime.getURL("settings/index.html");
window.open(url, "_blank", "width=400,height=600");
});
});

View File

@@ -1,40 +1,40 @@
const helper = {
shortenSchoolName(name, maxLength = 50) {
if (!name) return '';
if (name.length <= maxLength) return name;
const parts = name.split(' - ');
if (parts.length === 2) {
const [code, fullName] = parts;
if (fullName.length > maxLength - code.length - 3) {
return `${code} - ${fullName.substring(0, maxLength - code.length - 6)}...`;
}
}
return name.substring(0, maxLength - 3) + '...';
},
async waitForElement(selector) {
return new Promise(resolve => {
if (document.querySelector(selector)) {
return resolve(document.querySelector(selector));
}
shortenSchoolName(name, maxLength = 50) {
if (!name) return "";
if (name.length <= maxLength) return name;
const observer = new MutationObserver(mutations => {
if (document.querySelector(selector)) {
observer.disconnect();
resolve(document.querySelector(selector));
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
});
},
convertTimeToMinutes(timeStr) {
const [hours, minutes] = timeStr.split(':').map(Number);
return hours * 60 + minutes;
const parts = name.split(" - ");
if (parts.length === 2) {
const [code, fullName] = parts;
if (fullName.length > maxLength - code.length - 3) {
return `${code} - ${fullName.substring(0, maxLength - code.length - 6)}...`;
}
}
}
return name.substring(0, maxLength - 3) + "...";
},
async waitForElement(selector) {
return new Promise((resolve) => {
if (document.querySelector(selector)) {
return resolve(document.querySelector(selector));
}
const observer = new MutationObserver((mutations) => {
if (document.querySelector(selector)) {
observer.disconnect();
resolve(document.querySelector(selector));
}
});
observer.observe(document.body, {
childList: true,
subtree: true,
});
});
},
convertTimeToMinutes(timeStr) {
const [hours, minutes] = timeStr.split(":").map(Number);
return hours * 60 + minutes;
},
};

View File

@@ -1,59 +1,53 @@
.modalBckgroundMain {
display: none !important;
display:none !important;
}
body:not(.loaded) {
opacity: 0 !important;
visibility: hidden !important;
height: 100vh !important;
overflow: hidden !important;
opacity:0 !important;
visibility:hidden !important;
height:100vh !important;
overflow:hidden !important;
}
.loading-screen {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: var(--background);
z-index: 9999;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
transition: opacity 0.3s ease;
position:fixed;
top:0;
left:0;
width:100vw;
height:100vh;
background-color:var(--background);
z-index:9999;
display:flex;
flex-direction:column;
align-items:center;
justify-content:center;
transition:opacity 0.3s ease;
}
.loading-content {
display: flex;
flex-direction: column;
align-items: center;
gap: 1rem;
display:flex;
flex-direction:column;
align-items:center;
gap:1rem;
}
.loading-logo {
width: 48px;
height: 48px;
border-radius: 16px;
width:48px;
height:48px;
border-radius:16px;
}
.loading-text {
color: var(--text-primary);
text-align: center;
font-family: Montserrat;
font-size: 20px;
font-style: normal;
font-weight: 700;
line-height: normal;
color:var(--text-primary);
text-align:center;
font-family:Montserrat;
font-size:20px;
font-style:normal;
font-weight:700;
line-height:normal;
}
.loading-text2 {
align-self: stretch;
color: var(--text-secondary);
text-align: center;
font-family: Figtree;
font-size: 16px;
font-style: normal;
font-weight: 500;
line-height: 130%;
align-self:stretch;
color:var(--text-secondary);
text-align:center;
font-family:Figtree;
font-size:16px;
font-style:normal;
font-weight:500;
line-height:130%;
}

View File

@@ -1,53 +1,77 @@
const loadingScreen = {
show() {
document.body.classList.remove('loaded');
const existingLoadingScreen = document.querySelector('.loading-screen');
if (existingLoadingScreen) return;
show() {
document.body.classList.remove("loaded");
const existingLoadingScreen = document.querySelector(".loading-screen");
if (existingLoadingScreen) return;
const loadingScreen = document.createElement('div');
loadingScreen.className = 'loading-screen';
loadingScreen.innerHTML = `
<div class="loading-content">
<img src="${chrome.runtime.getURL('images/loading.gif')}" alt="Firka" class="loading-logo">
<div class="loading-text" data-i18n="loading.text">Betöltés alatt...</div>
<div class="loading-text2" data-i18n="loading.subtext">Kis türelmet!</div>
</div>
`;
document.body.appendChild(loadingScreen);
document.body.classList.add('loaded');
},
const loadingScreen = document.createElement("div");
loadingScreen.className = "loading-screen";
const loadingContent = document.createElement('div');
loadingContent.className = 'loading-content';
const loadingLogo = document.createElement('img');
loadingLogo.src = chrome.runtime.getURL("images/loading.gif");
loadingLogo.alt = 'Firka';
loadingLogo.className = 'loading-logo';
const loadingText = document.createElement('div');
loadingText.className = 'loading-text';
loadingText.setAttribute('data-i18n', 'loading.text');
loadingText.textContent = 'Betöltés alatt...';
const loadingText2 = document.createElement('div');
loadingText2.className = 'loading-text2';
loadingText2.setAttribute('data-i18n', 'loading.subtext');
loadingText2.textContent = 'Kis türelmet!';
loadingContent.appendChild(loadingLogo);
loadingContent.appendChild(loadingText);
loadingContent.appendChild(loadingText2);
loadingScreen.appendChild(loadingContent);
document.body.appendChild(loadingScreen);
document.body.classList.add("loaded");
},
hide() {
document.body.classList.add('loaded');
const loadingScreen = document.querySelector('.loading-screen');
if (loadingScreen) {
loadingScreen.style.opacity = '0';
hide() {
document.body.classList.add("loaded");
const loadingScreen = document.querySelector(".loading-screen");
if (loadingScreen) {
loadingScreen.style.opacity = "0";
const removeLoadingScreen = () => {
if (loadingScreen && loadingScreen.parentNode) {
loadingScreen.remove();
}
};
loadingScreen.addEventListener('transitionend', removeLoadingScreen, { once: true });
setTimeout(removeLoadingScreen, 500);
const removeLoadingScreen = () => {
if (loadingScreen && loadingScreen.parentNode) {
loadingScreen.remove();
}
}
}
};
window.addEventListener('DOMContentLoaded', () => {
const manifest = chrome.runtime.getManifest();
const urls = [];
if (manifest.content_scripts) {
manifest.content_scripts.forEach(script => {
if (script.matches) {
urls.push(...script.matches);
}
});
loadingScreen.addEventListener("transitionend", removeLoadingScreen, {
once: true,
});
setTimeout(removeLoadingScreen, 500);
}
},
};
if (urls.some(url => url.includes(location.pathname))) {
loadingScreen.show();
}
});
window.addEventListener("DOMContentLoaded", () => {
const manifest = chrome.runtime.getManifest();
const urls = [];
if (manifest.content_scripts) {
manifest.content_scripts.forEach((script) => {
if (script.matches) {
urls.push(...script.matches);
}
});
}
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);
});
}