diff --git a/absences/absences.js b/absences/absences.js index 56e02ce..0dade5f 100644 --- a/absences/absences.js +++ b/absences/absences.js @@ -54,23 +54,23 @@ async function transformAbsencesPage() {
-

Szűrés

+

${LanguageManager.t('absences.filter_title')}

- - - - + + + +
@@ -97,7 +97,7 @@ async function transformAbsencesPage() {
event ${date} - ${dayAbsences.length} óra + ${dayAbsences.length} ${LanguageManager.t('absences.hours')}
${dayAbsences.map(absence => ` @@ -106,7 +106,7 @@ async function transformAbsencesPage() { data-justified="${absence.justified}">
schedule - ${absence.lesson}. óra + ${absence.lesson}. ${LanguageManager.t('absences.lesson').toLowerCase()}
${absence.subject}
@@ -114,10 +114,10 @@ async function transformAbsencesPage() {
${absence.justificationStatus === 'justified' ? - `Igazolt check_circle` : + `${LanguageManager.t('absences.justified')} check_circle` : absence.justificationStatus === 'unjustified' ? - `Igazolatlan cancel` : - `Igazolásra vár pending`} + `${LanguageManager.t('absences.unjustified')} cancel` : + `${LanguageManager.t('absences.pending')} pending`}
`).join('')} @@ -252,6 +252,6 @@ function setupFilters() { if (window.location.href.includes('/Hianyzas/Hianyzasok')) { transformAbsencesPage().catch(error => { - console.error('Hiba történt az oldal átalakítása során:', error); + console.error(LanguageManager.t('absences.page_transform_error'), error); }); } \ No newline at end of file diff --git a/dashboard/dashboard.css b/dashboard/dashboard.css index 6a46c4b..33cadd6 100644 --- a/dashboard/dashboard.css +++ b/dashboard/dashboard.css @@ -14,6 +14,10 @@ body { font-size: 16px; } +h2 { + background-color: #00000000 !important; +} + .kreta-container { min-height: 100vh; display: flex; @@ -35,42 +39,191 @@ body { gap: 20px; } - -.card { +.widget-card { background: var(--card-card); - padding: 20px; - padding-top: 5px !important; border-radius: 24px; overflow: hidden; animation: fadeIn 0.5s ease forwards; - box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow); + box-shadow: 0px 1px var(--shadow-blur, 2px) 0px var(--accent-shadow); display: flex; flex-direction: column; height: 100%; + border: none; + min-height: 400px; +} + +.widget-header { + padding: 20px 20px 0 20px; + background: var(--card-card) !important; +} + +.widget-card-title { + font-size: 18px; + font-weight: 600; + color: var(--text-primary); + margin: 0; + padding-bottom: 16px; +} + +.widget-content { + flex: 1; + padding: 0 20px; + background: var(--card-card); + display: flex; + flex-direction: column; + justify-content: flex-start; +} + +.widget-footer { + padding: 0px 20px 20px 20px; + background: var(--card-card); +} + +.widget-link { + margin: 0; + padding: 0; } .card h2 { - font-size: 16px; + font-size: 18px; font-weight: 600; color: var(--text-primary); - background-color: var(--card-card); + margin: 0; + padding: 20px 0 16px 0; } .card:last-child { grid-column: 1 / -1; } - -.grade-item, .absence-item, .note-item, .exam-item, .news-item { - border-radius: 6px; +.widget-item { + border-radius: 12px; transition: transform 0.2s ease, box-shadow 0.2s ease; - border: 1px solid var(--card-card); + border: none; + background: var(--card-card); + box-shadow: 0px 1px var(--shadow-blur, 2px) 0px var(--accent-shadow); display: flex; flex-direction: column; - margin-bottom: 12px; - padding: 12px; + padding: 8px; + position: relative; + min-height: 80px; } +.widget-item:hover { + transform: translateY(-2px); + box-shadow: 0px 2px calc(var(--shadow-blur, 2px) * 2) 0px var(--accent-shadow); +} + +.widget-row { + display: flex; + align-items: flex-start; + justify-content: space-between; + width: 100%; + gap: 12px; + min-height: 40px; +} + +.widget-row.grade-row { + align-items: center; + justify-content: flex-start; +} + +.widget-details { + flex: 1; + display: flex; + flex-direction: column; + gap: 6px; + min-width: 0; +} + +.widget-details.grade-details { + flex: 1; + margin-right: auto; +} + +.widget-title { + color: var(--text-primary); + font-weight: 600; + font-size: 16px; + line-height: 1.3; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.widget-subtitle { + color: var(--text-secondary); + font-weight: 500; + font-size: 14px; + line-height: 1.2; +} + +.widget-content { + color: var(--text-secondary); + font-size: 14px; + line-height: 1.4; + margin-top: 4px; +} + +.widget-date { + color: var(--text-secondary); + font-size: 14px; + font-weight: 500; + white-space: nowrap; + text-align: right; + align-self: center; +} + +.grade-type-with-date { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + gap: 8px; +} + +.grade-type-with-date .grade-type { + flex: 1; + min-width: 0; +} + +.note-author { + color: var(--text-tertiary); + font-size: 12px; + font-weight: 400; + margin-top: 4px; +} + +.grade-date { + color: var(--text-secondary); + font-size: 13px; + font-weight: 400; + white-space: nowrap; + text-align: right; +} + + + +.widget-author { + color: var(--text-tertiary); + font-size: 12px; + font-weight: 400; +} + +.widget-meta { + display: flex; + flex-direction: column; + align-items: flex-end; + gap: 4px; + text-align: right; +} + +.widget-empty { + color: var(--text-secondary); + font-style: italic; + text-align: center; + padding: 20px; +} .grade { width: 32px; @@ -84,15 +237,25 @@ body { color: var(--text-primary); font-size: 22px; } -.subject-name, .absence-type, .note-title, .exam-subject { - color: var(--text-primary); - font-weight: 600; + +.news-title { font-size: 16px; + font-weight: 600; + margin-bottom: 8px; } -.grade-type, .absence-date, .note-date, .exam-date { - color: var(--text-secondary); - font-weight: 500; + +.news-content { font-size: 14px; + 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; @@ -180,15 +343,25 @@ body { width: 20px; height: 20px; } -.subject-name, .absence-type, .note-title, .exam-subject { - color: var(--text-primary); - font-weight: 600; + +.news-title { font-size: 16px; + font-weight: 600; + margin-bottom: 8px; } -.grade-type, .absence-date, .note-date, .exam-date { - color: var(--text-secondary); - font-weight: 500; + +.news-content { font-size: 14px; + 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; @@ -212,22 +385,12 @@ body { font-size: 0.875rem; } -.grade-row { +.exam-info { display: flex; - align-items: center; - justify-content: space-between; - width: 100%; -} - -.grade-details { - flex: 1; - margin-right: 10px; -} - -.grade-date, .exam-date { + gap: 8px; + margin-top: 4px; color: var(--text-secondary); font-size: 14px; - white-space: nowrap; } .exam-info { diff --git a/dashboard/dashboard.js b/dashboard/dashboard.js index 015708b..4ec40fb 100644 --- a/dashboard/dashboard.js +++ b/dashboard/dashboard.js @@ -1,4 +1,4 @@ -const utils = { +const DashboardUtils = { formatGradeValue(value) { const trimmedValue = value?.trim() || ''; if (trimmedValue.toLowerCase() === 'szöveges') { @@ -10,7 +10,7 @@ const utils = { parseDate(dateStr) { return dateStr?.trim() || ''; }, - + formatHungarianDate(dateStr) { if (!dateStr) return ''; @@ -21,20 +21,29 @@ const utils = { const day = parseInt(dateParts[2], 10); if (isNaN(month) || month < 1 || month > 12) return dateStr; - - const hungarianMonths = [ - 'január', 'február', 'március', 'április', 'május', 'június', - 'július', 'augusztus', 'szeptember', 'október', 'november', 'december' + + 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' + ]; + 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' ]; - return `${hungarianMonths[month - 1]} ${day}.`; + return `${LanguageManager.t(monthKeys[month - 1])} ${day}.`; } }; - -class DashboardDataExtractor { +class DashboardDataManager { constructor() { - this.data = { + this.dashboardData = { grades: [], absences: [], notes: [], @@ -43,46 +52,69 @@ class DashboardDataExtractor { }; } - extractGrades() { + extractGradeData() { const gradeRows = document.querySelectorAll('#legutobbiErtekelesek tr:not(:first-child)'); - this.data.grades = Array.from(gradeRows).map(row => { + 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 [fullSubject, date] = gradeInfo.split('\n').map(str => str.trim()); - const { subject, type } = this.parseSubjectInfo(fullSubject); + const { subject, type, dateInSubject } = this.parseSubjectInformation(fullSubject); return { - value: utils.formatGradeValue(gradeValue), + value: DashboardUtils.formatGradeValue(gradeValue), subject, - date: utils.parseDate(date), - type: type || 'Értékelés' + date: DashboardUtils.parseDate(date), + type: type || LanguageManager.t('dashboard.evaluation'), + dateInSubject: dateInSubject || null }; }).filter(Boolean); } - parseSubjectInfo(fullSubject) { - const months = ['január', 'február', 'március', 'április', 'május', 'június', - 'július', 'augusztus', 'szeptember', 'október', 'november', 'december']; - const monthPattern = new RegExp(months.join('|'), 'i'); - const monthMatch = fullSubject.match(monthPattern); + 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 dateMatch = fullSubject.match(datePattern); - if (!monthMatch) return { subject: fullSubject, type: '' }; + if (dateMatch) { + const subjectPart = fullSubject.substring(0, dateMatch.index).trim(); + const datePart = dateMatch[0].trim(); + return { + subject: subjectPart, + 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') + ]; + const fallbackMonthPattern = new RegExp(months.join('|'), 'i'); + const monthMatch = fullSubject.match(fallbackMonthPattern); - const monthIndex = fullSubject.lastIndexOf(monthMatch[0]); - return { - subject: fullSubject.substring(0, monthIndex).trim(), - type: fullSubject.substring(monthIndex).trim() - }; + if (monthMatch) { + const monthIndex = fullSubject.lastIndexOf(monthMatch[0]); + return { + subject: fullSubject.substring(0, monthIndex).trim(), + type: fullSubject.substring(monthIndex).trim() + }; + } + + return { subject: fullSubject, type: '' }; } - extractAbsences() { + extractAbsenceData() { const absenceRows = document.querySelectorAll('#legutobbiMulasztasok tr:not(:first-child)'); - this.data.absences = Array.from(absenceRows).map(row => { + this.dashboardData.absences = Array.from(absenceRows).map(row => { const spans = row.querySelectorAll('span'); if (spans.length < 4) return null; @@ -95,10 +127,10 @@ class DashboardDataExtractor { }).filter(Boolean); } - extractNotes() { + extractNoteData() { const noteRows = document.querySelectorAll('#legutobbiFeljegyzesek tr:not(:first-child)'); - this.data.notes = Array.from(noteRows).map(row => { + this.dashboardData.notes = Array.from(noteRows).map(row => { const spans = row.querySelectorAll('span'); if (spans.length < 3) return null; @@ -110,10 +142,10 @@ class DashboardDataExtractor { }).filter(Boolean); } - extractExams() { + extractExamData() { const examRows = document.querySelectorAll('#legutobbiBejelentettSzamonkeres tr:not(:first-child)'); - this.data.upcomingExams = Array.from(examRows).map(row => { + this.dashboardData.upcomingExams = Array.from(examRows).map(row => { const spans = row.querySelectorAll('span'); if (spans.length < 4) return null; @@ -126,56 +158,79 @@ class DashboardDataExtractor { }).filter(Boolean); } - extractNews() { - const newsContainer = document.querySelector('.faliujsag-lista, #faliujsagLista'); - if (!newsContainer) return; + async extractNewsData() { - const newsItems = newsContainer.querySelectorAll('.nb-item, .news-item'); - - this.data.news = Array.from(newsItems).map(item => { - const titleElement = item.querySelector('.subject h4, .news-title'); - const contentElement = item.querySelector('.content, .news-content'); + try { + const timestamp = Date.now(); + const apiUrl = `https://${window.location.hostname}/Intezmeny/Faliujsag/GetMoreEntries?startindex=0&range=10&_=${timestamp}`; - - const dateElement = item.querySelector('.nb-date, .news-date'); - let dateStr = ''; - - if (dateElement) { - const yearElement = dateElement.querySelector('.year'); - const monthElement = dateElement.querySelector('.month'); - const dayElement = dateElement.querySelector('.day'); - - if (yearElement && monthElement && dayElement) { - dateStr = `${yearElement.textContent} ${monthElement.textContent} ${dayElement.textContent}`; - } else { - dateStr = dateElement.textContent; + const response = await fetch(apiUrl, { + method: 'GET', + credentials: 'include', + headers: { + 'Accept': 'application/json, text/javascript, */*; q=0.01', + 'X-Requested-With': 'XMLHttpRequest' } + }); + + if (!response.ok) { + throw new Error(`API request failed with status: ${response.status}`); } + const data = await response.json(); - const authorElement = item.querySelector('.auth-name span, .news-author'); + if (!data.FaliujsagElemek || !Array.isArray(data.FaliujsagElemek)) { + return; + } - return { - title: titleElement?.textContent?.trim() || '', - date: dateStr.trim(), - content: contentElement?.textContent?.trim() || '', - author: authorElement?.textContent?.trim() || '' - }; - }).filter(news => news.title || news.content); + data.FaliujsagElemek.forEach((item, index) => { + 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+)\)\//); + if (match) { + const timestamp = parseInt(match[1]); + const date = new Date(timestamp); + formattedDate = date.toLocaleDateString('hu-HU'); + } + } + + if (!formattedDate) { + 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(); + + const newsItem = { + title: item.EsemenyCime || `Hír ${index + 1}`, + content: cleanContent || 'Nincs elérhető tartalom', + date: formattedDate, + author: `${item.Nev || 'Ismeretlen'} (${item.Munkakor || 'Ismeretlen'})` + }; + + this.dashboardData.news.push(newsItem); + }); + + } catch (error) { + console.error('❌ Error fetching news from API:', error); + } } - extractAll() { - this.extractGrades(); - this.extractAbsences(); - this.extractNotes(); - this.extractExams(); - this.extractNews(); - return this.data; + async extractAllData() { + this.extractGradeData(); + this.extractAbsenceData(); + this.extractNoteData(); + this.extractExamData(); + await this.extractNewsData(); + return this.dashboardData; } } - -class DashboardUI { +class DashboardRenderer { constructor(data) { this.data = { ...data, @@ -192,134 +247,204 @@ class DashboardUI { this.shortenedSchoolName = helper.shortenSchoolName(this.schoolNameFull); } - generateMainContentHTML() { + generateMainContent() { return `
- ${this.generateGradeCard()} - ${this.generateAbsenceCard()} - ${this.generateNoteCard()} - ${this.generateExamCard()} - ${this.generateNewsCard()} + ${this.createGradeCard()} + ${this.createAbsenceCard()} + ${this.createNoteCard()} + ${this.createExamCard()} + ${this.createNewsCard()}
`; } - generateNewsCard() { + createNewsCard() { const newsItems = this.data.news.map(news => ` -
-
-
${news.date}
- ${news.author ? `
${news.author}
` : ''} -
-
-

${news.title}

-
${news.content}
-
-
- `).join(''); - - return this.generateCard('Hírek', newsItems || 'Jelenleg ez egy nem támogatott funkció', '/Intezmeny/Faliujsag', 'Összes hír'); - } - generateGradeCard() { - const gradeItems = this.data.grades.map(grade => ` -
-
-
${grade.value}
-
-
${grade.subject}
-
${grade.type}
+
+
+
+
${news.title}
+
${news.content}
+
+
+ ${news.date ? `
${news.date}
` : ''} + ${news.author ? `
${news.author}
` : ''}
- ${grade.date ? `
${grade.date}
` : ''}
`).join(''); - return this.generateCard('Értékeléseid', gradeItems, '/TanuloErtekeles/Osztalyzatok', 'Összes jegyed'); + return this.createCard(LanguageManager.t('dashboard.news'), newsItems || LanguageManager.t('dashboard.not_supported'), '/Intezmeny/Faliujsag', LanguageManager.t('dashboard.all_news')); } - generateAbsenceCard() { + + createGradeCard() { + const gradeItems = this.data.grades.map(grade => ` +
+
+
${grade.value}
+
+
${grade.subject}
+
+
${grade.type}
+ ${grade.dateInSubject || grade.date ? `
${grade.dateInSubject || grade.date}
` : ''} +
+
+
+
+ `).join(''); + + return this.createCard(LanguageManager.t('dashboard.grades'), gradeItems, '/TanuloErtekeles/Osztalyzatok', LanguageManager.t('dashboard.all_grades')); + } + + createAbsenceCard() { const absenceItems = this.data.absences.map(absence => ` -
-
-
${absence.type}
-
${absence.date}
+
+
+
+
${absence.type}
+
${absence.date}
+
+ ${absence.day ? `
${absence.day}
` : ''}
`).join(''); - return this.generateCard('Mulasztások', absenceItems, '/Hianyzas/Hianyzasok', 'Összes mulasztás'); + return this.createCard(LanguageManager.t('dashboard.absences'), absenceItems, '/Hianyzas/Hianyzasok', LanguageManager.t('dashboard.all_absences')); } - generateNoteCard() { + + createNoteCard() { const noteItems = this.data.notes.map(note => ` -
-
-
${note.title}
-
${note.date}
+
+
+
+
${note.title}
+
${note.date}
+
+ ${note.author ? `
${note.author}
` : ''}
`).join(''); - return this.generateCard('Feljegyzések', noteItems, '/TanuloErtekeles/InformaciokFeljegyzesek', 'Összes üzeneted'); + return this.createCard(LanguageManager.t('dashboard.notes'), noteItems, '/TanuloErtekeles/InformaciokFeljegyzesek', LanguageManager.t('dashboard.all_messages')); } - generateExamCard() { + + createExamCard() { const examItems = this.data.upcomingExams.map(exam => ` -
-
-
${exam.subject}
-
${utils.formatHungarianDate(exam.date)}
+
+
+
+
${exam.subject}
+
${exam.type || ''}
+
+
${DashboardUtils.formatHungarianDate(exam.date)}
`).join(''); - return this.generateCard('Bejelentett dolgozatok', examItems, '/Tanulo/TanuloBejelentettSzamonkeresek', 'Összes dolgozat'); + return this.createCard(LanguageManager.t('dashboard.exams'), examItems, '/Tanulo/TanuloBejelentettSzamonkeresek', LanguageManager.t('dashboard.all_exams')); } - generateCard(title, content, linkHref, linkText) { + + createCard(title, content, linkHref, linkText) { return ` -
-

${title}

-
- ${content || `Jelenleg ez egy nem támogatott funkció`} - + `; } - + render() { document.body.innerHTML = `
${createTemplate.header()} - ${this.generateMainContentHTML()} + ${this.generateMainContent()}
`; setupUserDropdown(); } } -class DashboardApp { +class DashboardApplication { constructor() { - this.initialize(); + this.init(); } - async initialize() { - if (!window.location.href.includes('/Intezmeny/Faliujsag')) return; + async init() { + 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 (!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'); + if (newsContainer) { + const possibleSelectors = [ + '.nb-item', + '.news-item', + '.faliujsag-item', + '.list-group-item', + 'li', + 'div[class*="item"]', + 'div[class*="news"]' + ]; + + for (const selector of possibleSelectors) { + const items = newsContainer.querySelectorAll(selector); + if (items.length > 0) { + newsItemsFound = true; + break; + } + } + + if (!newsItemsFound) { + if (newsContainer.children.length > 0 || newsContainer.textContent.trim().length > 0) { + newsItemsFound = true; + } + } + } + + if (!newsItemsFound) { + attempts++; + await new Promise(resolve => setTimeout(resolve, 100)); + } + } try { - const dataExtractor = new DashboardDataExtractor(); - const dashboardData = dataExtractor.extractAll(); + const dataManager = new DashboardDataManager(); + const dashboardData = await dataManager.extractAllData(); createTemplate.importFonts(); - const ui = new DashboardUI(dashboardData); - ui.render(); + const renderer = new DashboardRenderer(dashboardData); + renderer.render(); } catch (error) { console.error('Error initializing dashboard:', error); } } } - -new DashboardApp(); \ No newline at end of file +new DashboardApplication(); \ No newline at end of file diff --git a/forgotpassword/forgotpassword.js b/forgotpassword/forgotpassword.js index d87dbfe..1c17093 100644 --- a/forgotpassword/forgotpassword.js +++ b/forgotpassword/forgotpassword.js @@ -25,31 +25,31 @@
-

Elfelejtett jelszó

+

${LanguageManager.t('forgotpassword.title')}

- + -
Kérjük, add meg az OM azonosítód.
+ placeholder="${LanguageManager.t('forgotpassword.om_id_placeholder')}" required> +
${LanguageManager.t('forgotpassword.om_id_required')}
- + -
Kérjük, add meg az e-mail címed.
+ placeholder="${LanguageManager.t('forgotpassword.email_placeholder')}" required> +
${LanguageManager.t('forgotpassword.email_required')}
- Vissza a bejelentkezéshez + ${LanguageManager.t('forgotpassword.back_to_login')}
@@ -130,7 +130,7 @@ window.location.href = '/Adminisztracio/Login'; } else { - alert(result.Message || 'Hiba történt a jelszó visszaállítása során. (Kérlek használd az eredeti kréta oldalt erre)'); + alert(result.Message || LanguageManager.t('forgotpassword.error_message')); grecaptcha.reset(); } } catch (error) { diff --git a/global/language.js b/global/language.js new file mode 100644 index 0000000..e9c7857 --- /dev/null +++ b/global/language.js @@ -0,0 +1,131 @@ +(function() { + let currentLanguage = 'hu'; + let translations = {}; + + async function setLanguage(language) { + 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) {} + } + + 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 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' } + ] + }; + +})(); \ No newline at end of file diff --git a/global/maintenance.css b/global/maintenance.css index 4cc9452..a09347c 100644 --- a/global/maintenance.css +++ b/global/maintenance.css @@ -1,3 +1,28 @@ +@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; @@ -7,7 +32,7 @@ body.maintenance-mode { justify-content: center; background-color: var(--background); color: var(--text-primary); - font-family: 'Inter', sans-serif; + font-family: 'Figtree', sans-serif; } body { @@ -35,6 +60,7 @@ body { font-weight: 600; margin-bottom: 1rem; color: var(--accent-accent); + font-family: 'Montserrat', sans-serif; } .maintenance-message { @@ -42,10 +68,22 @@ body { 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; +} + +.maintenance-cactus { + position: fixed; + bottom: 0px; + right: 20px; + width: 120px; + height: 120px; + opacity: 1; + z-index: 1000; } \ No newline at end of file diff --git a/global/maintenance.js b/global/maintenance.js index d9b172b..5e01f30 100644 --- a/global/maintenance.js +++ b/global/maintenance.js @@ -7,18 +7,46 @@ function loadMaintenanceCSS() { function checkMaintenancePage() { const maintenanceContent = document.querySelector('.login_content'); - if (maintenanceContent && maintenanceContent.textContent.includes('frissítés alatt')) { + 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 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 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(); + + 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(); @@ -34,20 +62,25 @@ function checkMaintenancePage() { const title = document.createElement('h1'); title.className = 'maintenance-title'; - title.textContent = 'Karbantartás'; + 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 = 'A KRÉTA rendszer jelenleg frissítés alatt van, hamarosan újra elérhetővé válik.'; + 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 = 'Köszönjük türelmüket és megértésüket!'; + 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 = 'KRÉTA Csapat'; + 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); @@ -59,6 +92,7 @@ function checkMaintenancePage() { container.appendChild(footer); body.appendChild(container); + body.appendChild(cactus); } } diff --git a/global/navigation.js b/global/navigation.js index 932195c..1f709c0 100644 --- a/global/navigation.js +++ b/global/navigation.js @@ -6,8 +6,8 @@ const COOKIE_KEYS = { }; const DEFAULT_VALUES = { - SCHOOL: 'Iskola', - USER: 'Felhasználó', + SCHOOL: LanguageManager.t('navigation.school_default'), + USER: LanguageManager.t('navigation.user_default'), TIMER: '45:00' }; diff --git a/grades/grades.js b/grades/grades.js index 64afbb7..0951e2b 100644 --- a/grades/grades.js +++ b/grades/grades.js @@ -27,7 +27,6 @@ loadingScreen.hide(); } catch (error) { - console.error('Error transforming grades page:', error); loadingScreen.hide(); } } @@ -42,7 +41,20 @@ const subjectName = cells[2].textContent.trim(); if (subjectName && subjectName !== 'Magatartás/Szorgalom') { const grades = []; - const months = ['Szeptember', 'Oktober', 'November', 'December', 'JanuarI', 'JanuarII', 'Februar', 'Marcius', 'Aprilis', 'Majus', 'JuniusI', 'JuniusII']; + const months = [ + LanguageManager.t('grades.september'), + LanguageManager.t('grades.october'), + LanguageManager.t('grades.november'), + LanguageManager.t('grades.december'), + LanguageManager.t('grades.january_1'), + LanguageManager.t('grades.january_2'), + LanguageManager.t('grades.february'), + LanguageManager.t('grades.march'), + LanguageManager.t('grades.april'), + LanguageManager.t('grades.may'), + LanguageManager.t('grades.june_1'), + LanguageManager.t('grades.june_2') + ]; months.forEach((month, index) => { const gradeElements = cells[index + 3].querySelectorAll('span[data-tanuloertekelesid]'); @@ -136,7 +148,20 @@ function generateGradeItem(grade) { const semesterClass = grade.isSemesterGrade ? 'semester-grade' : ''; const dateObj = new Date(grade.date); - const monthNames = ['Január', 'Február', 'Március', 'Április', 'Május', 'Június', 'Július', 'Augusztus', 'Szeptember', 'Október', 'November', 'December']; + const monthNames = [ + LanguageManager.t('months.january'), + LanguageManager.t('months.february'), + LanguageManager.t('months.march'), + LanguageManager.t('months.april'), + LanguageManager.t('months.may'), + LanguageManager.t('months.june'), + LanguageManager.t('months.july'), + LanguageManager.t('months.august'), + LanguageManager.t('months.september'), + LanguageManager.t('months.october'), + LanguageManager.t('months.november'), + LanguageManager.t('months.december') + ]; const formattedDate = `${monthNames[dateObj.getMonth()]} ${dateObj.getDate()}`; const shortenedTheme = shortenEvaluationName(grade.theme); return ` @@ -183,7 +208,7 @@
-
Jegyek (${totalGrades}db)
+
${LanguageManager.t('grades.chart_title')} (${totalGrades}db)
${studentAverage > 0 ? studentAverage.toFixed(2) : '-'} @@ -210,7 +235,7 @@
${semesterGrades.length > 0 ? `
-

Félévi értékelések

+

${LanguageManager.t('grades.semester_evaluations')}

${semesterGrades.map(grade => `
diff --git a/homework/homework.js b/homework/homework.js index 2a14bdc..355949d 100644 --- a/homework/homework.js +++ b/homework/homework.js @@ -75,7 +75,15 @@ function formatApiDate(dateString) { const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); - const dayNames = ['vasárnap', 'hétfő', 'kedd', 'szerda', 'csütörtök', 'péntek', 'szombat']; + 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') + ]; const dayName = dayNames[date.getDay()]; return `${month}.${day}. (${dayName})`; @@ -120,16 +128,16 @@ async function transformHomeworkPage() {
-

Szűrés

+

${LanguageManager.t('homework.filter_title')}

- + ${[...new Set(homeworkItems.map(item => item.teacher))] .sort() .map(teacher => ``) @@ -152,13 +160,13 @@ async function transformHomeworkPage() {
@@ -202,7 +210,7 @@ function renderHomeworkList(groupedHomework) { if (sortedDates.length === 0) { return `
-

Nincs megjeleníthető házi feladat.

+

${LanguageManager.t('homework.no_homework')}

`; } @@ -255,12 +263,20 @@ function formatDateHeader(dateStr) { const date = new Date(currentYear, month, day); if (date.toDateString() === today.toDateString()) { - return 'Ma - ' + dateStr; + return LanguageManager.t('common.today') + ' - ' + dateStr; } else if (date.toDateString() === tomorrow.toDateString()) { - return 'Holnap - ' + dateStr; + return LanguageManager.t('common.tomorrow') + ' - ' + dateStr; } - const weekdays = ['Vasárnap', 'Hétfő', 'Kedd', 'Szerda', 'Csütörtök', 'Péntek', 'Szombat']; + 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') + ]; return `${weekdays[date.getDay()]} - ${dateStr}`; } @@ -376,7 +392,7 @@ function setupFilters(homeworkItems, groupedHomework) { if (!emptyState) { emptyState = document.createElement('div'); emptyState.className = 'empty-state'; - emptyState.innerHTML = '

Nincs a szűrési feltételeknek megfelelő házi feladat.

'; + emptyState.innerHTML = `

${LanguageManager.t('homework.no_matching_homework')}

`; homeworkList.appendChild(emptyState); } diff --git a/i18n/en.json b/i18n/en.json new file mode 100644 index 0000000..fed49fd --- /dev/null +++ b/i18n/en.json @@ -0,0 +1,319 @@ +{ + "loading": { + "text": "Loading...", + "subtext": "Please wait!" + }, + "settings": { + "title": "Settings", + "theme": "Theme", + "language": "Language", + "themes": { + "light_blue": "Light Blue", + "light_green": "Light Green", + "dark_blue": "Dark Blue", + "dark_green": "Dark Green", + "dark_red": "Dark Red", + "dark_purple": "Dark Purple", + "dark_orange": "Dark Orange", + "dark_pink": "Dark Pink", + "dark_yellow": "Dark Yellow", + "dark_cyan": "Dark Cyan", + "dark_lime": "Dark Lime", + "dark_indigo": "Dark Indigo" + }, + "languages": { + "hu": "Magyar", + "en": "English" + }, + "about": { + "title": "About", + "description": "Firka is an open-source project that creates a custom user interface for the KRÉTA system.", + "github": "GitHub" + }, + "support": { + "title": "Support", + "description": "If you like our work and would like to support the development, you can do so in the following way:", + "kofi": "Ko-Fi" + } + }, + "navigation": { + "dashboard": "Home", + "timetable": "Timetable", + "grades": "Grades", + "homework": "Homework", + "absences": "Absences", + "other": "Other", + "profile": "Profile", + "settings": "Settings", + "logout": "Logout", + "nav_toggle": "Open navigation" + }, + "dashboard": { + "welcome": "Welcome", + "recent_grades": "Recent grades", + "upcoming_lessons": "Upcoming lessons", + "homework_due": "Homework due", + "news": "News", + "grades": "Your grades", + "absences": "Absences", + "notes": "Notes", + "exams": "Announced tests", + "all_news": "All news", + "all_grades": "All your grades", + "all_absences": "All absences", + "all_messages": "All your messages", + "all_exams": "All tests", + "not_supported": "There is currently no data to show", + "evaluation": "Evaluation" + }, + "grades": { + "title": "Grades", + "subject": "Subject", + "grade": "Grade", + "date": "Date", + "teacher": "Teacher", + "average": "Average", + "chart_title": "Grades", + "semester_evaluations": "Semester evaluations", + "semester_average": "Semester average", + "no_grades": "No grades", + "september": "September", + "october": "October", + "november": "November", + "december": "December", + "january_1": "January I", + "january_2": "January II", + "february": "February", + "march": "March", + "april": "April", + "may": "May", + "june_1": "June I", + "june_2": "June II" + }, + "timetable": { + "title": "Timetable", + "lesson": "Lesson", + "time": "Time", + "subject": "Subject", + "teacher": "Teacher", + "classroom": "Classroom", + "homework_indicator": "Homework", + "test_indicator": "Test", + "teacher_label": "Teacher:", + "substitute_teacher_label": "Substitute teacher:", + "classroom_label": "Classroom:", + "time_label": "Time:", + "status_label": "Status:", + "substitution": "Substitution", + "cancelled": "Cancelled", + "has_homework": "Has homework", + "no_lessons_this_week": "No lessons this week or timeout occurred", + "monday": "Monday", + "tuesday": "Tuesday", + "wednesday": "Wednesday", + "thursday": "Thursday", + "friday": "Friday", + "found_current_week": "Found current week" + }, + "homework": { + "title": "Homework", + "due_date": "Due date", + "subject": "Subject", + "description": "Description", + "filter_title": "Filter", + "all_subjects": "All subjects", + "all_teachers": "All teachers", + "all_deadlines": "All deadlines", + "tomorrow_deadline": "Tomorrow's deadline", + "this_week": "This week", + "next_week": "Next week", + "no_homework": "No homework to display.", + "no_filtered_homework": "No homework matching the filter criteria.", + "teacher": "Teacher", + "no_matching_homework": "No homework matching the filter criteria." + }, + "absences": { + "title": "Absences", + "date": "Date", + "lesson": "Lesson", + "type": "Type", + "justified": "Justified", + "unjustified": "Unjustified", + "filter_title": "Filter", + "all_subjects": "All subjects", + "all_types": "All types", + "pending": "Pending justification", + "subject": "Subject", + "justification": "Justification", + "hours": "hours", + "page_transform_error": "An error occurred while transforming the page" + }, + "profile": { + "title": "Profile", + "name": "Name", + "class": "Class", + "school": "School", + "student_id": "Student ID", + "settings_title": "Profile settings", + "tab_settings": "Settings", + "tab_password": "Change password", + "tab_security": "Security settings", + "tab_contacts": "Contact information", + "two_factor_description": "To use two-factor authentication, install a time-based one-time password (TOTP) application:", + "android": "Android", + "iphone": "iPhone", + "enable_2fa": "Enable two-factor authentication", + "security_key": "Security key:", + "verification_code_label": "Verification code", + "verification_code_help": "Enter the 6-digit code shown in your authenticator app.", + "verification_code_placeholder": "123456", + "verify_and_activate": "Verify and activate", + "backup_codes_description": "You can use the following backup codes to log in if you don't have access to your authenticator app. Each code can only be used once.", + "email_label": "Email address", + "email_help": "Email address is required for password recovery.", + "phone_label": "Phone number", + "phone_help": "Phone number is optional.", + "phone_placeholder": "+1 xxx xxx xxxx", + "current_password": "Current password", + "new_password": "New password", + "new_password_help": "Password must be at least 8 characters long.", + "confirm_password": "Confirm new password", + "change_password": "Change password", + "show_tips": "Show tips", + "show_tips_help": "Toggle display of tips on/off.", + "email_required": "Email address is required!", + "email_invalid": "Please enter a valid email address!", + "phone_invalid": "Please enter a valid phone number!", + "contacts_saved": "Contact information saved successfully!", + "contacts_save_error": "An error occurred while saving. Please try again later.", + "settings_saved": "Settings saved successfully! Please log in again for changes to take effect.", + "settings_save_error": "An error occurred while saving. Please try again later.", + "password_fields_required": "Please fill in all fields!", + "passwords_not_match": "New passwords do not match!", + "password_too_short": "New password must be at least 8 characters long!", + "password_changed": "Password changed successfully!", + "password_change_error": "An error occurred while changing password. Please try again later." + }, + "login": { + "title": "Login", + "username": "Username", + "password": "Password", + "login_button": "Login", + "forgot_password": "Forgot password", + "two_factor_title": "Two-factor authentication", + "verification_code": "Verification code", + "username_placeholder": "Username", + "password_placeholder": "Password", + "username_required": "Please enter your username.", + "password_required": "Please enter your password.", + "help_login": "Can't log in?", + "help_link": "Help", + "system_message": "System message", + "privacy_policy": "Privacy policy", + "kreta_id": "KRÉTA ID", + "system_notification": "System notification" + }, + "forgot_password": { + "title": "Forgot password", + "om_id": "OM ID", + "email": "Email address", + "om_id_placeholder": "Enter your OM ID", + "email_placeholder": "Enter your email address", + "om_id_required": "Please enter your OM ID.", + "email_required": "Please enter your email address." + }, + "two_factor": { + "title": "Two-factor authentication", + "code_placeholder": "One-time password", + "code_required": "Please enter the one-time password.", + "verify_button": "Verify code", + "verifying": "Verifying...", + "trust_device": "Trust this device" + }, + "logout": { + "title": "Logout", + "message": "Are you sure you want to logout?", + "confirm": "Yes", + "cancel": "Cancel", + "success": "Successfully logged out!", + "continue": "Continue" + }, + "common": { + "save": "Save", + "cancel": "Cancel", + "close": "Close", + "loading": "Loading...", + "error": "Error", + "success": "Success", + "warning": "Warning", + "info": "Information", + "yes": "Yes", + "no": "No", + "continue": "Continue", + "back": "Back", + "next": "Next", + "previous": "Previous", + "all": "All", + "none": "None", + "filter": "Filter", + "search": "Search", + "select": "Select", + "required": "Required", + "optional": "Optional", + "api_error": "API error", + "api_load_error": "API load error", + "monday": "Monday", + "tuesday": "Tuesday", + "wednesday": "Wednesday", + "thursday": "Thursday", + "friday": "Friday", + "saturday": "Saturday", + "sunday": "Sunday", + "today": "Today", + "tomorrow": "Tomorrow" + }, + "months": { + "january": "January", + "february": "February", + "march": "March", + "april": "April", + "may": "May", + "june": "June", + "july": "July", + "august": "August", + "september": "September", + "october": "October", + "november": "November", + "december": "December" + }, + "search": { + "title": "Choose school", + "select_institution": "Please select an institution to continue!" + }, + "roleselect": { + "student_book": "Student Book", + "student_description": "View grades, absences, timetable and other information.", + "dkt_title": "Digital Collaboration Space (DKT)", + "dkt_description": "Classroom communication and assignments.", + "logout_title": "Logout", + "logout_description": "Log out of the system", + "role_change_error": "An error occurred while changing roles." + }, + "maintenance": { + "title": "Maintenance", + "message1": "The KRÉTA system is currently being updated and will be available again soon.", + "message2": "Thank you for your patience and understanding!", + "team": "KRÉTA Team" + }, + "about": { + "title": "About", + "description": "Firka is an open source project that creates a custom user interface for the KRÉTA system.", + "support_title": "Support", + "support_description": "If you like our work and want to support development, you can do so in the following way:", + "version": "v1.1.0" + }, + "app": { + "title": "Firka - KRÉTA", + "settings_title": "Firka - Settings" + } +} \ No newline at end of file diff --git a/i18n/hu.json b/i18n/hu.json new file mode 100644 index 0000000..6e6d54b --- /dev/null +++ b/i18n/hu.json @@ -0,0 +1,319 @@ +{ + "loading": { + "text": "Betöltés alatt...", + "subtext": "Kis türelmet!" + }, + "settings": { + "title": "Beállítások", + "theme": "Téma", + "language": "Nyelv", + "themes": { + "light_blue": "Világos Kék", + "light_green": "Világos Zöld", + "dark_blue": "Sötét Kék", + "dark_green": "Sötét Zöld", + "dark_red": "Sötét Piros", + "dark_purple": "Sötét Lila", + "dark_orange": "Sötét Narancs", + "dark_pink": "Sötét Rózsaszín", + "dark_yellow": "Sötét Sárga", + "dark_cyan": "Sötét Cián", + "dark_lime": "Sötét Lime", + "dark_indigo": "Sötét Indigó" + }, + "languages": { + "hu": "Magyar", + "en": "English" + }, + "about": { + "title": "Névjegy", + "description": "A Firka egy nyílt forráskódú projekt, amely a KRÉTA rendszerhez készít saját felhasználói felületet.", + "github": "GitHub" + }, + "support": { + "title": "Támogatás", + "description": "Ha tetszik a munkánk és szeretnéd támogatni a fejlesztést, az alábbi módon teheted meg:", + "kofi": "Ko-Fi" + } + }, + "navigation": { + "dashboard": "Kezdőlap", + "timetable": "Órarend", + "grades": "Jegyek", + "homework": "Házi feladatok", + "absences": "Mulasztások", + "other": "Egyéb", + "profile": "Profil", + "settings": "Beállítások", + "logout": "Kijelentkezés", + "nav_toggle": "Navigáció megnyitása" + }, + "dashboard": { + "welcome": "Üdvözöljük", + "recent_grades": "Legutóbbi jegyek", + "upcoming_lessons": "Következő órák", + "homework_due": "Esedékes házi feladatok", + "news": "Hírek", + "grades": "Értékeléseid", + "absences": "Mulasztások", + "notes": "Feljegyzések", + "exams": "Bejelentett dolgozatok", + "all_news": "Összes hír", + "all_grades": "Összes jegyed", + "all_absences": "Összes mulasztás", + "all_messages": "Összes üzeneted", + "all_exams": "Összes dolgozat", + "not_supported": "Jelenleg nincsen adat amivel fel lehetne tölteni", + "evaluation": "Értékelés" + }, + "grades": { + "title": "Jegyek", + "subject": "Tantárgy", + "grade": "Jegy", + "date": "Dátum", + "teacher": "Tanár", + "average": "Átlag", + "chart_title": "Jegyek", + "semester_evaluations": "Félévi értékelések", + "semester_average": "Félévi átlag", + "no_grades": "Nincsenek jegyek", + "september": "Szeptember", + "october": "Oktober", + "november": "November", + "december": "December", + "january_1": "JanuarI", + "january_2": "JanuarII", + "february": "Februar", + "march": "Marcius", + "april": "Aprilis", + "may": "Majus", + "june_1": "JuniusI", + "june_2": "JuniusII" + }, + "timetable": { + "title": "Órarend", + "lesson": "Óra", + "time": "Idő", + "subject": "Tantárgy", + "teacher": "Tanár", + "classroom": "Terem", + "homework_indicator": "Házi feladat", + "test_indicator": "Számonkérés", + "teacher_label": "Tanár:", + "substitute_teacher_label": "Helyettesítő tanár:", + "classroom_label": "Terem:", + "time_label": "Időpont:", + "status_label": "Állapot:", + "substitution": "Helyettesítés", + "cancelled": "Elmarad", + "has_homework": "Van házi feladat", + "no_lessons_this_week": "Nincsenek órák ezen a héten vagy időtúllépés történt", + "monday": "Hétfő", + "tuesday": "Kedd", + "wednesday": "Szerda", + "thursday": "Csütörtök", + "friday": "Péntek", + "found_current_week": "Megtalált jelenlegi hét" + }, + "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ő", + "tomorrow_deadline": "Holnapi határidő", + "this_week": "Ezen a héten", + "next_week": "Jövő 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." + }, + "absences": { + "title": "Hiányzások", + "date": "Dátum", + "lesson": "Óra", + "type": "Típus", + "justified": "Igazolt", + "unjustified": "Igazolatlan", + "filter_title": "Szűrés", + "all_subjects": "Minden tantárgy", + "all_types": "Mindegy", + "pending": "Igazolásra vár", + "subject": "Tantárgy", + "justification": "Igazolás", + "hours": "óra", + "page_transform_error": "Hiba történt az oldal átalakítása során" + }, + "profile": { + "title": "Profil", + "name": "Név", + "class": "Osztály", + "school": "Iskola", + "student_id": "Diák azonosító", + "settings_title": "Profil beállítások", + "tab_settings": "Beállítások", + "tab_password": "Jelszó módosítása", + "tab_security": "Biztonsági beállítások", + "tab_contacts": "Elérhetőségek", + "two_factor_description": "A kétfaktoros hitelesítés használatához telepítsen egy időalapú, egyszer használatos jelszó (TOTP) alkalmazást:", + "android": "Android", + "iphone": "iPhone", + "enable_2fa": "Kétfaktoros azonosítás bekapcsolása", + "security_key": "Biztonsági kulcs:", + "verification_code_label": "Ellenőrző kód", + "verification_code_help": "Adja meg a hitelesítő alkalmazásban megjelenő 6 számjegyű kódot.", + "verification_code_placeholder": "123456", + "verify_and_activate": "Ellenőrzés és aktiválás", + "backup_codes_description": "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ó.", + "email_label": "E-mail cím", + "email_help": "Az e-mail cím megadása a jelszó emlékeztető miatt szükséges.", + "phone_label": "Telefonszám", + "phone_help": "A telefonszám megadása nem kötelező.", + "phone_placeholder": "+36 xx xxx xxxx", + "current_password": "Jelenlegi jelszó", + "new_password": "Új jelszó", + "new_password_help": "A jelszónak legalább 8 karakter hosszúnak kell lennie.", + "confirm_password": "Új jelszó megerősítése", + "change_password": "Jelszó módosítása", + "show_tips": "Tippek megjelenítése", + "show_tips_help": "A tippek megjelenítésének ki/be kapcsolása.", + "email_required": "Az e-mail cím megadása kötelező!", + "email_invalid": "Kérjük, adjon meg egy érvényes e-mail címet!", + "phone_invalid": "Kérjük, adjon meg egy érvényes telefonszámot!", + "contacts_saved": "Elérhetőségek sikeresen mentve!", + "contacts_save_error": "Hiba történt a mentés során. Kérjük, próbálja újra később.", + "settings_saved": "Beállítások sikeresen mentve! A változtatások érvényesítéséhez jelentkezzen be újra.", + "settings_save_error": "Hiba történt a mentés során. Kérjük, próbálja újra később.", + "password_fields_required": "Kérjük, töltse ki az összes mezőt!", + "passwords_not_match": "Az új jelszavak nem egyeznek!", + "password_too_short": "Az új jelszónak legalább 8 karakter hosszúnak kell lennie!", + "password_changed": "Jelszó sikeresen módosítva!", + "password_change_error": "Hiba történt a jelszó módosítása során. Kérjük, próbálja újra később." + }, + "login": { + "title": "Bejelentkezés", + "username": "Felhasználónév", + "password": "Jelszó", + "login_button": "Bejelentkezés", + "forgot_password": "Elfelejtett jelszó", + "two_factor_title": "Kétfaktoros hitelesítés", + "verification_code": "Ellenőrző kód", + "username_placeholder": "Felhasználónév", + "password_placeholder": "Jelszó", + "username_required": "Kérjük, add meg a felhasználóneved.", + "password_required": "Kérjük, add meg a jelszavad.", + "help_login": "Nem tudsz bejelentkezni?", + "help_link": "Segítség", + "system_message": "Rendszerüzenet", + "privacy_policy": "Adatvédelmi szabályzat", + "kreta_id": "KRÉTA azonosító", + "system_notification": "Rendszerértesítés" + }, + "forgot_password": { + "title": "Elfelejtett jelszó", + "om_id": "OM azonosítód", + "email": "E-mail cím", + "om_id_placeholder": "Add meg az OM azonosítód", + "email_placeholder": "Add meg az e-mail címed", + "om_id_required": "Kérjük, add meg az OM azonosítód.", + "email_required": "Kérjük, add meg az e-mail címed." + }, + "two_factor": { + "title": "Kétfaktoros azonosítás", + "code_placeholder": "Egyszeri jelszó", + "code_required": "Kérjük, add meg az egyszeri jelszót.", + "verify_button": "Kód ellenőrzése", + "verifying": "Ellenőrzés...", + "trust_device": "Eszköz megbízhatónak jelölése" + }, + "logout": { + "title": "Kijelentkezés", + "message": "Biztosan ki szeretne jelentkezni?", + "confirm": "Igen", + "cancel": "Mégse", + "success": "Sikeres kijelentkezés!", + "continue": "Tovább" + }, + "common": { + "save": "Mentés", + "cancel": "Mégse", + "close": "Bezárás", + "loading": "Betöltés...", + "error": "Hiba", + "success": "Sikeres", + "warning": "Figyelmeztetés", + "info": "Információ", + "yes": "Igen", + "no": "Nem", + "continue": "Tovább", + "back": "Vissza", + "next": "Következő", + "previous": "Előző", + "all": "Összes", + "none": "Nincs", + "filter": "Szűrés", + "search": "Keresés", + "select": "Válassz", + "required": "Kötelező", + "optional": "Opcionális", + "api_error": "API hiba", + "api_load_error": "API betöltési hiba", + "monday": "hétfő", + "tuesday": "kedd", + "wednesday": "szerda", + "thursday": "csütörtök", + "friday": "péntek", + "saturday": "szombat", + "sunday": "vasárnap", + "today": "Ma", + "tomorrow": "Holnap" + }, + "months": { + "january": "január", + "february": "február", + "march": "március", + "april": "április", + "may": "május", + "june": "június", + "july": "július", + "august": "augusztus", + "september": "szeptember", + "october": "október", + "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.", + "dkt_title": "Digitális Kollaborációs Tér (DKT)", + "dkt_description": "Osztálytermi kommunikáció és feladatok.", + "logout_title": "Kijelentkezés", + "logout_description": "Kilépés a rendszerből", + "role_change_error": "Hiba történt a szerepkör váltása közben." + }, + "maintenance": { + "title": "Karbantartás", + "message1": "A KRÉTA rendszer jelenleg frissítés alatt van, hamarosan újra elérhetővé válik.", + "message2": "Köszönjük türelmüket és megértésüket!", + "team": "KRÉTA Csapat" + }, + "about": { + "title": "Névjegy", + "description": "A Firka egy nyílt forráskódú projekt, amely a KRÉTA rendszerhez készít saját felhasználói felületet.", + "support_title": "Támogatás", + "support_description": "Ha tetszik a munkánk és szeretnéd támogatni a fejlesztést, az alábbi módon teheted meg:", + "version": "v1.1.0" + }, + "app": { + "title": "Firka - KRÉTA", + "settings_title": "Firxa - Beállítások" + } +} \ No newline at end of file diff --git a/images/cactus.png b/images/cactus.png new file mode 100644 index 0000000..e025099 Binary files /dev/null and b/images/cactus.png differ diff --git a/login/login.js b/login/login.js index 8103197..cb013f1 100644 --- a/login/login.js +++ b/login/login.js @@ -27,7 +27,7 @@ async function transformLoginPage() { if (spanElement) { const lines = spanElement.textContent?.split('\n').map(line => line.trim()) || []; schoolInfo.kretaId = lines[0] || ''; - schoolInfo.omCode = (lines[1] || '').replace('KRÉTA azonosító: ', ''); + schoolInfo.omCode = (lines[1] || '').replace(`${LanguageManager.t('login.kreta_id')}: `, ''); } const rawSystemMessage = document.querySelector('.alert-primary')?.textContent?.trim() || ''; @@ -44,7 +44,7 @@ async function transformLoginPage() {

${schoolInfo.name}

${schoolInfo.kretaId ? `
${schoolInfo.kretaId}
` : ''} - ${schoolInfo.omCode ? `
KRÉTA azonosító: ${schoolInfo.omCode}
` : ''} + ${schoolInfo.omCode ? `
${LanguageManager.t('login.kreta_id')}: ${schoolInfo.omCode}
` : ''}
@@ -57,27 +57,27 @@ async function transformLoginPage() {
-
Kérjük, add meg a felhasználóneved.
+ placeholder="${LanguageManager.t('login.username_placeholder')}" maxlength="256" autocomplete="username" required value="${formData.userName}"> +
${LanguageManager.t('login.username_required')}
- -
Kérjük, add meg a jelszavad.
+
${LanguageManager.t('login.password_required')}
@@ -85,14 +85,14 @@ async function transformLoginPage() { ${systemMessage ? `
-

Rendszerértesítés

+

${LanguageManager.t('login.system_message')}

${systemMessage}

` : ''}
`; diff --git a/login/twofactor.js b/login/twofactor.js index 2fc2609..ea50ab8 100644 --- a/login/twofactor.js +++ b/login/twofactor.js @@ -29,7 +29,7 @@ async function transformTwoFactorPage() { Firka

-

Kétfaktoros azonosítás

+

${LanguageManager.t('twofactor.title')}

@@ -41,30 +41,30 @@ async function transformTwoFactorPage() {
- -
Kérjük, add meg az egyszeri jelszót.
+
${LanguageManager.t('twofactor.code_required')}
- +
- Nem fér hozzá eszközéhez? Lépjen be + ${LanguageManager.t('twofactor.no_access')}
@@ -73,7 +73,7 @@ async function transformTwoFactorPage() {
`; @@ -162,7 +162,7 @@ function handleSubmit(event) { const submitButton = form.querySelector('.btn-kreta'); if (submitButton) { submitButton.disabled = true; - submitButton.innerHTML = 'Ellenőrzés...'; + submitButton.innerHTML = `${LanguageManager.t('twofactor.verifying')}`; } form.submit(); diff --git a/manifest.json b/manifest.json index fd50abe..b4a2e8d 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "Firxa", - "version": "1.2.1", + "version": "1.2.2", "description": "KRÉTA webes verziójának újraírása", "icons": { "128": "images/firka_logo_128.png" @@ -15,10 +15,13 @@ "web_accessible_resources": [{ "resources": [ "settings/*", + "global/language.js", "images/*", "fonts/*.woff2", "icons/*.svg", - "grades/chart.js" + "grades/chart.js", + "i18n/*.json", + "tools/cookieManager.js" ], "matches": ["https://*.e-kreta.hu/*", "https://idp.e-kreta.hu/*"] }], @@ -28,7 +31,7 @@ "https://*.e-kreta.hu/*" ], "js": ["tools/cookieManager.js", "tools/helper.js", "tools/loadingScreen.js", "tools/createTemplate.js", - "global/maintenance.js", "global/theme.js", "global/navigation.js"], + "global/language.js", "global/maintenance.js", "global/theme.js", "global/navigation.js"], "css": ["tools/loadingScreen.css", "global/theme.css", "global/navigation.css"], "run_at": "document_start" }, diff --git a/profile/profile.js b/profile/profile.js index a5de3f6..d9fb01f 100644 --- a/profile/profile.js +++ b/profile/profile.js @@ -174,17 +174,17 @@ const phone = phoneInput.value.trim(); if (!email) { - alert('Az e-mail cím megadása kötelező!'); + alert(LanguageManager.t('profile.email_required')); return; } if (email && !isValidEmail(email)) { - alert('Kérjük, adjon meg egy érvényes e-mail címet!'); + alert(LanguageManager.t('profile.invalid_email')); return; } if (phone && !isValidPhone(phone)) { - alert('Kérjük, adjon meg egy érvényes telefonszámot!'); + alert(LanguageManager.t('profile.invalid_phone')); return; } @@ -199,13 +199,13 @@ }); if (response.ok) { - alert('Elérhetőségek sikeresen mentve!'); + alert(LanguageManager.t('profile.contacts_saved')); } else { - throw new Error('Hiba történt a mentés során.'); + throw new Error(LanguageManager.t('profile.contacts_save_error')); } } catch (error) { console.error('Error saving contacts:', error); - alert('Hiba történt a mentés során. Kérjük, próbálja újra később.'); + alert(LanguageManager.t('profile.save_error')); } }); } @@ -259,13 +259,13 @@ }); if (response.ok) { - alert('Beállítások sikeresen mentve! A változtatások érvényesítéséhez jelentkezzen be újra.'); + alert(LanguageManager.t('profile.settings_saved')); } else { - throw new Error('Hiba történt a mentés során.'); + throw new Error(LanguageManager.t('profile.settings_save_error')); } } catch (error) { console.error('Error saving settings:', error); - alert('Hiba történt a mentés során. Kérjük, próbálja újra később.'); + alert(LanguageManager.t('profile.save_error')); } }); @@ -276,17 +276,17 @@ const confirmPassword = document.getElementById('confirmPassword').value; if (!currentPassword || !newPassword || !confirmPassword) { - alert('Kérjük, töltse ki az összes mezőt!'); + alert(LanguageManager.t('profile.fill_all_fields')); return; } if (newPassword !== confirmPassword) { - alert('Az új jelszavak nem egyeznek!'); + alert(LanguageManager.t('profile.passwords_not_match')); return; } if (newPassword.length < 8) { - alert('Az új jelszónak legalább 8 karakter hosszúnak kell lennie!'); + alert(LanguageManager.t('profile.password_min_length')); return; } @@ -305,16 +305,16 @@ }); if (response.ok) { - alert('Jelszó sikeresen módosítva!'); + alert(LanguageManager.t('profile.password_changed')); document.getElementById('currentPassword').value = ''; document.getElementById('newPassword').value = ''; document.getElementById('confirmPassword').value = ''; } else { - throw new Error('Hiba történt a jelszó módosítása során.'); + throw new Error(LanguageManager.t('profile.password_change_error')); } } catch (error) { console.error('Error changing password:', error); - alert('Hiba történt a jelszó módosítása során. Kérjük, próbálja újra később.'); + alert(LanguageManager.t('profile.password_change_error')); } }); diff --git a/roleselect/roleselect.js b/roleselect/roleselect.js index 02c1f53..5b70033 100644 --- a/roleselect/roleselect.js +++ b/roleselect/roleselect.js @@ -34,7 +34,7 @@ } } catch (error) { console.error('Error changing role:', error); - alert('Hiba történt a szerepkör váltása közben.'); + alert(LanguageManager.t('roleselect.role_change_error')); } }; @@ -66,8 +66,8 @@ Napló ikon
- Ellenőrzőkönyv -
Jegyek, hiányzások, órarended és egyéb információk megtekintése.
+ ${LanguageManager.t('roleselect.student_book')} +
${LanguageManager.t('roleselect.student_description')}
@@ -78,8 +78,8 @@ DKT ikon
- Digitális Kollaborációs Tér (DKT) -
Osztálytermi kommunikáció és feladatok.
+ ${LanguageManager.t('roleselect.dkt_title')} +
${LanguageManager.t('roleselect.dkt_description')}
@@ -88,8 +88,8 @@ Kijelentkezés ikon
- Kijelentkezés -
Kilépés a rendszerből
+ ${LanguageManager.t('roleselect.logout_title')} +
${LanguageManager.t('roleselect.logout_description')}
@@ -113,7 +113,7 @@ const schoolSubdomain = window.location.hostname.split('.')[0]; const userNameEl = document.querySelector('.UserName'); - const userName = userNameEl?.textContent.trim() || 'Felhasználónév'; + const userName = userNameEl?.textContent.trim() || LanguageManager.t('common.username'); if (schoolCode && fullSchoolName) { diff --git a/search/search.js b/search/search.js index 46c6173..298f7c5 100644 --- a/search/search.js +++ b/search/search.js @@ -64,7 +64,7 @@ function applyFirkaStyling() { redirectButton.addEventListener('click', function(event) { if (!instituteCodeInput.value) { event.preventDefault(); - alert('Kérjük, válasszon egy intézményt a folytatáshoz!'); + alert(LanguageManager.t('search.select_institution')); } }); } diff --git a/settings/index.css b/settings/index.css index f64ab79..7f7a997 100644 --- a/settings/index.css +++ b/settings/index.css @@ -88,12 +88,14 @@ h2 { } -.theme-grid { +.theme-grid, +.language-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; } -.theme-option { +.theme-option, +.language-option { background: none; border: none; padding: 0; @@ -104,13 +106,18 @@ h2 { gap: 8px; transition: transform 0.2s ease; } -.theme-option:hover { +.theme-option:hover, +.language-option:hover { transform: translateY(-2px); } .theme-option.active .theme-preview { outline: 2px solid var(--accent-accent); outline-offset: 2px; } +.language-option.active .language-preview { + outline: 2px solid var(--accent-accent); + outline-offset: 2px; +} .theme-preview { width: 100%; height: 100px; @@ -135,6 +142,30 @@ h2 { 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; +} + +.language-option:hover { + background: var(--card-hover); + border-color: var(--accent-accent); +} + +.language-option.active { + background: var(--accent-accent); + border-color: var(--accent-accent); + color: white; +} + +.language-name { + font-weight: 500; + font-size: 14px; +} + .theme-preview.light-blue { background: #DAE4F7; diff --git a/settings/index.html b/settings/index.html index f14de9d..f0653a0 100644 --- a/settings/index.html +++ b/settings/index.html @@ -23,12 +23,12 @@
-

Beállítások

+

Beállítások

palette - Téma + Téma
- Világos Kék + Világos Kék
- Világos Zöld + Világos Zöld
- Sötét Kék + Sötét Kék
- Sötét Zöld + Sötét Zöld + +
+
+ +
+
+ language + Nyelv +
+
+ +
@@ -73,24 +88,24 @@
-

Névjegy

+

Névjegy

-

A Firka egy nyílt forráskódú projekt, amely a KRÉTA rendszerhez készít saját felhasználói felületet.

+

A Firka egy nyílt forráskódú projekt, amely a KRÉTA rendszerhez készít saját felhasználói felületet.

code - GitHub + GitHub
-

Támogatás

+

Támogatás

-

Ha tetszik a munkánk és szeretnéd támogatni a fejlesztést, az alábbi módon teheted meg:

+

Ha tetszik a munkánk és szeretnéd támogatni a fejlesztést, az alábbi módon teheted meg:

@@ -100,6 +115,8 @@
v1.1.0
- + + + \ No newline at end of file diff --git a/settings/index.js b/settings/index.js index 3acaeb5..203b127 100644 --- a/settings/index.js +++ b/settings/index.js @@ -1,4 +1,7 @@ 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'; @@ -59,6 +62,35 @@ document.addEventListener('DOMContentLoaded', async () => { }); updateThemeAvailability(); } + + function getCurrentLanguage() { + 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); + }); + } + + async function applyLanguage(language) { + setCookie('languagePreference', language); + localStorage.setItem('languagePreference', language); + + updateLanguageButtons(language); + + 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); @@ -77,8 +109,6 @@ document.addEventListener('DOMContentLoaded', async () => { action: 'changeTheme', theme: theme }).catch(() => { - - console.log('Tab not ready for theme change:', tab.id); }); }); } @@ -91,7 +121,7 @@ document.addEventListener('DOMContentLoaded', async () => { if (button.hasAttribute('disabled')) { - alert('Ez a téma jelenleg nem elérhető.'); + alert(window.LanguageManager.t('common.warning') + ': ' + window.LanguageManager.t('settings.theme_not_available')); return; } @@ -99,6 +129,14 @@ document.addEventListener('DOMContentLoaded', async () => { }); }); + const languageButtons = document.querySelectorAll('.language-option'); + languageButtons.forEach(button => { + button.addEventListener('click', () => { + const language = button.dataset.language; + applyLanguage(language); + }); + }); + let initialTheme = getCurrentTheme(); @@ -111,6 +149,9 @@ document.addEventListener('DOMContentLoaded', async () => { updateThemeAvailability(); await applyTheme(initialTheme); + const initialLanguage = getCurrentLanguage(); + updateLanguageButtons(initialLanguage); + chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { if (message.action === 'themeChanged') { @@ -148,7 +189,7 @@ document.addEventListener('DOMContentLoaded', async () => { box-shadow: 0 4px 12px rgba(0,0,0,0.15); animation: slideIn 0.3s ease-out; `; - notification.textContent = 'Kék témák feloldva! 🎉'; + notification.textContent = window.LanguageManager.t('common.success') + ': ' + window.LanguageManager.t('settings.blue_themes_unlocked'); const style = document.createElement('style'); @@ -184,4 +225,18 @@ document.addEventListener('DOMContentLoaded', async () => { 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); + }); }); \ No newline at end of file diff --git a/timetable/timetable.css b/timetable/timetable.css index 83af1be..b3a51ff 100644 --- a/timetable/timetable.css +++ b/timetable/timetable.css @@ -55,7 +55,6 @@ body { flex-direction: column; } -/* Update header styles to match dashboard */ .kreta-header { padding: clamp(1rem, 3vw, 2rem); display: grid; @@ -140,7 +139,6 @@ body { } } -/* User profile styles */ .user-profile { position: relative; justify-self: flex-end; @@ -399,24 +397,52 @@ body { .week-controls { display: flex; - gap: 16px; + flex-direction: column; align-items: center; justify-content: center; margin: 16px auto; background: var(--card-card); border-radius: 24px; - max-width: 400px; + max-width: 800px; + padding: 20px; } -.week-select { - flex: 1; - padding: 12px; +.week-selector-container { + width: 100%; + position: relative; +} + +.expand-week-view-btn { + display: flex; + align-items: center; + justify-content: center; + width: 40px; + height: 40px; border: none; - border-radius: 12px; + border-radius: 8px; background: var(--button-secondaryFill); color: var(--text-primary); - font-family: inherit; cursor: pointer; + transition: all 0.2s ease; + margin-left: 12px; +} + +.expand-week-view-btn:hover { + background: var(--accent-15); + color: var(--accent-accent); + transform: scale(1.05); +} + +.expand-week-view-btn .material-icons-round { + font-size: 18px; +} + +.week-selector { + display: flex; + align-items: center; + justify-content: center; + gap: 12px; + max-width: 100%; } .week-nav-btn { @@ -426,19 +452,292 @@ body { width: 40px; height: 40px; border: none; - border-radius: 12px; + border-radius: 8px; background: var(--button-secondaryFill); - color: var(--text-secondary); + color: var(--text-primary); cursor: pointer; transition: all 0.2s ease; } -.week-nav-btn:hover { +.week-nav-btn:hover:not(:disabled) { + background: var(--accent-15); + color: var(--accent-accent); + transform: scale(1.05); +} + +.week-nav-btn .material-icons-round { + font-size: 20px; +} + +.week-display { + display: flex; + gap: 8px; + align-items: center; +} + +.week-cell { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 60px; + height: 50px; + border: 2px solid var(--button-secondaryFill); + border-radius: 8px; + background: var(--button-secondaryFill); + color: var(--text-primary); + font-family: inherit; + font-weight: 500; + cursor: pointer; + transition: all 0.2s ease; + position: relative; + gap: 2px; +} + +.week-cell:hover { + background: var(--accent-15); + border-color: var(--accent-accent); + color: var(--accent-accent); + transform: scale(1.05); +} + +.week-cell.selected { + background: var(--accent-accent); + border-color: var(--accent-accent); + color: white; + font-weight: 600; +} + +.week-cell.selected:hover { + background: var(--accent-accent); + transform: scale(1.05); +} + +.week-cell.current-week { + border-color: var(--accent-accent); + box-shadow: 0 0 0 1px var(--accent-accent); +} + +.week-cell.current-week.selected { + box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.5); +} + +.week-number { + font-size: 14px; + font-weight: inherit; +} + +.current-indicator { + font-size: 8px; + color: var(--accent-accent); + line-height: 1; +} + +.week-cell.selected .current-indicator { + color: white; +} + +.week-tooltip { + position: absolute; + background: var(--card-card); + border: 1px solid var(--border-border); + border-radius: 8px; + padding: 8px 12px; + font-size: 14px; + color: var(--text-primary); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + pointer-events: none; + opacity: 0; + transition: opacity 0.2s ease; + z-index: 1000; + white-space: nowrap; +} + +.week-tooltip.show { + opacity: 1; +} + +.week-modal { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.5); + z-index: 10000; + display: flex; + align-items: center; + justify-content: center; + padding: 20px; +} + +.week-modal-content { + background: var(--card-card); + border-radius: 16px; + max-width: 1000px; + max-height: 70vh; + width: 100%; + overflow: hidden; + box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3); +} + +.week-modal-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 20px 24px; + border-bottom: 1px solid var(--border-border); +} + +.week-modal-grid { + display: grid; + grid-template-columns: repeat(13, 1fr); + gap: 8px; + padding: 20px; + max-height: calc(70vh - 80px); + overflow-y: auto; +} + +.modal-week-cell { + width: 40px; + height: 40px; + font-size: 12px; +} + + + +@media (max-width: 768px) { + .week-modal-content { + max-width: 95vw; + max-height: 80vh; + } + + .week-modal-grid { + grid-template-columns: repeat(10, 1fr); + gap: 6px; + padding: 16px; + max-height: calc(80vh - 80px); + } + + .modal-week-cell { + width: 35px; + height: 35px; + font-size: 11px; + } +} + +.week-modal-header h3 { + margin: 0; + color: var(--text-primary); + font-size: 20px; + font-weight: 600; +} + +.week-modal-close { + display: flex; + align-items: center; + justify-content: center; + width: 40px; + height: 40px; + border: none; + border-radius: 8px; + background: var(--button-secondaryFill); + color: var(--text-primary); + cursor: pointer; + transition: all 0.2s ease; +} + +.week-modal-close:hover { background: var(--accent-15); color: var(--accent-accent); } -/* Day navigation for mobile */ +.week-modal-close .material-icons-round { + font-size: 24px; +} + +.week-modal-grid { + display: grid; + grid-template-columns: repeat(13, 1fr); + gap: 8px; + padding: 24px; + max-height: 70vh; + overflow-y: auto; +} + +.week-modal-grid .week-cell { + width: 60px; + height: 50px; + font-size: 14px; +} + +@media (max-width: 1200px) { + .week-modal-grid { + grid-template-columns: repeat(10, 1fr); + } +} + +@media (max-width: 768px) { + .week-modal-grid { + grid-template-columns: repeat(7, 1fr); + gap: 6px; + } + + .week-modal-grid .week-cell { + width: 50px; + height: 45px; + font-size: 12px; + } + + .week-modal-content { + margin: 10px; + } + + .week-modal-header { + padding: 16px 20px; + } + + .week-modal-grid { + padding: 20px; + } +} + +@media (max-width: 768px) { + .week-grid { + grid-template-columns: repeat(10, 1fr); + gap: 6px; + } + + .week-cell { + width: 40px; + height: 35px; + font-size: 12px; + } + + .week-controls { + max-width: 600px; + padding: 15px; + } +} + +@media (max-width: 480px) { + .week-grid { + grid-template-columns: repeat(8, 1fr); + gap: 4px; + } + + .week-cell { + width: 35px; + height: 30px; + font-size: 11px; + } + + .week-controls { + max-width: 400px; + padding: 12px; + } +} + .day-navigation { display: none; align-items: center; @@ -465,10 +764,7 @@ body { color: var(--accent-accent); } -.day-nav-btn:disabled { - opacity: 0.5; - cursor: not-allowed; -} + .current-day-info { text-align: center; @@ -676,7 +972,6 @@ body { display: none; } -/* Animations */ @keyframes fadeIn { from { opacity: 0; @@ -710,7 +1005,6 @@ body { } } -/* Responsive adjustments */ @media (max-width: 768px) { .kreta-header { flex-direction: column; @@ -726,7 +1020,6 @@ body { } } -/* Scrollbar styling */ ::-webkit-scrollbar { width: 8px; height: 8px; @@ -745,7 +1038,6 @@ body { background: var(--text-primary); } -/* Speciális napok stílusai */ .grid-header.special-day { background: linear-gradient(135deg, #F99F50, #FF8C42); color: white; @@ -790,7 +1082,6 @@ body { font-weight: 400; } -/* Week selector improvements */ .week-select { min-width: 200px; max-width: 300px; diff --git a/timetable/timetable.js b/timetable/timetable.js index 5c6cd07..2f35227 100644 --- a/timetable/timetable.js +++ b/timetable/timetable.js @@ -13,12 +13,12 @@ }); if (!response.ok) { - throw new Error(`API hiba: ${response.status}`); + throw new Error(`${LanguageManager.t('common.api_error')}: ${response.status}`); } return await response.json(); } catch (error) { - console.error('Hiba az API adatok betöltése során:', error); + console.error(LanguageManager.t('common.api_load_error'), error); return []; } } @@ -26,7 +26,7 @@ function generateWeekDates(startDate) { const start = new Date(startDate); const dates = []; - const dayNames = ['Hétfő', 'Kedd', 'Szerda', 'Csütörtök', 'Péntek']; + const dayNames = [LanguageManager.t('common.monday'), LanguageManager.t('common.tuesday'), LanguageManager.t('common.wednesday'), LanguageManager.t('common.thursday'), LanguageManager.t('common.friday')]; for (let i = 0; i < 5; i++) { const date = new Date(start); @@ -47,238 +47,72 @@ function convertAPIDataToLessons(apiData, weekDates) { const lessons = []; - - apiData.forEach(event => { - const eventDate = new Date(event.start); - const dayIndex = weekDates.findIndex(date => - new Date(date.fullDate).toDateString() === eventDate.toDateString() - ); - - if (dayIndex === -1) { - console.log('Nem található nap az eseményhez:', event.start); - return; - } - - if (event.oraType === 5) { - lessons.push({ - startTime: 'Egész nap', - endTime: '', - subject: event.title, - teacher: '', - originalTeacher: '', - room: '', - day: dayIndex, - isSubstituted: false, - isCancelled: false, - hasHomework: false, - testInfo: event.Tema || '', - homeworkDetails: '', - isSpecialDay: true, - color: event.color - }); - } else if (event.oraType === 2) { - const startTime = new Date(event.start); - const endTime = new Date(event.end); - const startTimeStr = startTime.toLocaleTimeString('hu-HU', { hour: '2-digit', minute: '2-digit' }); - const endTimeStr = endTime.toLocaleTimeString('hu-HU', { hour: '2-digit', minute: '2-digit' }); - const titleParts = event.title.split('\n'); - const teacher = titleParts[1] || ''; - const room = titleParts[2] ? titleParts[2].replace(/[()]/g, '') : ''; + apiData.forEach((event, index) => { + try { + const eventDate = new Date(event.start); + const dayIndex = weekDates.findIndex(date => + new Date(date.fullDate).toDateString() === eventDate.toDateString() + ); - lessons.push({ - startTime: startTimeStr, - endTime: endTimeStr, - subject: event.Tantargy || event.TantargyKategoria, - teacher: teacher, - originalTeacher: event.helyettesitoId ? teacher : '', - room: room, - day: dayIndex, - isSubstituted: !!event.helyettesitoId, - isCancelled: event.isElmaradt || false, - hasHomework: event.hasHaziFeladat || false, - testInfo: event.hasBejelentettSzamonkeres ? (event.Tema || 'Számonkérés') : '', - homeworkDetails: '', - isSpecialDay: false, - color: event.color - }); - } - }); - - return lessons; - } - - async function collectTimetableData() { - await helper.waitForElement('#Calendar'); - await helper.waitForElement('.modalBckgroundMain:not(.isOverlayActiv)'); - - const dates = Array.from(document.querySelectorAll('.fc-day-header')).map(header => { - const fullText = header.textContent.trim(); - const dateText = fullText.replace(/^(hétfő|kedd|szerda|csütörtök|péntek)/, '').trim(); - return { - date: fullText, - formattedDate: dateText - }; - }); - if (dates.length === 4) { - const wedDate = dates[2].formattedDate; - const [month, day] = wedDate.split(' '); - const dayNum = parseInt(day.replace('.', '')); - const thursdayDate = `${month} ${dayNum + 1}.`; - - dates.splice(3, 0, { - date: `csütörtök${thursdayDate}`, - formattedDate: thursdayDate - }); - } - const weekOptions = Array.from(document.querySelectorAll('#Calendar_tanevHetek_listbox li')); - - const kendoCombo = document.querySelector('#Calendar_tanevHetek')?.__kendoWidget; - let currentWeekIndex = 0; - - if (kendoCombo) { - const currentValue = kendoCombo.value(); - const selectedIndex = kendoCombo.selectedIndex; - - console.log('Kendo widget értékek:', { currentValue, selectedIndex, weekOptionsLength: weekOptions.length }); - - if (currentValue !== null && currentValue !== undefined && currentValue !== '') { - currentWeekIndex = parseInt(currentValue); - } else if (selectedIndex !== -1) { - currentWeekIndex = selectedIndex; - } else { - const today = new Date(); - let foundWeekIndex = -1; - - for (let i = 0; i < weekOptions.length; i++) { - const weekText = weekOptions[i].textContent.trim(); - console.log(`Vizsgált hét ${i}: ${weekText}`); + if (dayIndex === -1) { + return; + } + + if (event.oraType === 5) { + const lesson = { + startTime: LanguageManager.t('timetable.all_day'), + endTime: '', + subject: event.title || 'Különleges nap', + teacher: '', + originalTeacher: '', + room: '', + day: dayIndex, + isSubstituted: false, + isCancelled: false, + hasHomework: false, + testInfo: event.Tema || '', + homeworkDetails: '', + isSpecialDay: true, + color: event.color + }; + lessons.push(lesson); + } else if (event.oraType === 2 || event.oraType === 1 || event.oraType === 3 || event.oraType === 4) { + const startTime = new Date(event.start); + const endTime = new Date(event.end); + const startTimeStr = startTime.toLocaleTimeString('hu-HU', { hour: '2-digit', minute: '2-digit' }); + const endTimeStr = endTime.toLocaleTimeString('hu-HU', { hour: '2-digit', minute: '2-digit' }); + const titleParts = event.title ? event.title.split('\n') : []; + const teacher = titleParts[1] || ''; + const room = titleParts[2] ? titleParts[2].replace(/[()]/g, '') : ''; + const subject = event.Tantargy || event.TantargyKategoria || titleParts[0] || 'Ismeretlen tantárgy'; - let dateMatch = null; - let year, startMonth, startDay, endMonth, endDay; - - dateMatch = weekText.match(/(\d{4})\. (\w+) (\d{1,2})\. - (\w+) (\d{1,2})\. \((\d+)\. hét\)/); - if (dateMatch) { - [, year, startMonth, startDay, endMonth, endDay] = dateMatch; + if (startTimeStr && subject) { + const lesson = { + startTime: startTimeStr, + endTime: endTimeStr, + subject: subject, + teacher: teacher, + originalTeacher: event.helyettesitoId ? teacher : '', + room: room, + day: dayIndex, + isSubstituted: !!event.helyettesitoId, + isCancelled: event.isElmaradt || false, + hasHomework: event.hasHaziFeladat || false, + testInfo: event.hasBejelentettSzamonkeres ? (event.Tema || LanguageManager.t('timetable.test_indicator')) : '', + homeworkDetails: '', + isSpecialDay: false, + color: event.color + }; + lessons.push(lesson); } else { - dateMatch = weekText.match(/(\d{4})\.(\d{2})\.(\d{2})\. - (\d{4})\.(\d{2})\.(\d{2})\. \((\d+)\. hét\)/); - if (dateMatch) { - const [, startYear, startMonthNum, startDayNum, endYear, endMonthNum, endDayNum] = dateMatch; - year = startYear; - startMonth = parseInt(startMonthNum) - 1; - startDay = startDayNum; - endMonth = parseInt(endMonthNum) - 1; - endDay = endDayNum; - } else { - dateMatch = weekText.match(/(\d+)\. hét \((\d{4})\.(\d{2})\.(\d{2})\. - (\d{4})\.(\d{2})\.(\d{2})\.\)/); - if (dateMatch) { - const [, weekNum, startYear, startMonthNum, startDayNum, endYear, endMonthNum, endDayNum] = dateMatch; - year = startYear; - startMonth = parseInt(startMonthNum) - 1; - startDay = startDayNum; - endMonth = parseInt(endMonthNum) - 1; - endDay = endDayNum; - } - } } - - if (dateMatch) { - if (typeof startMonth === 'string') { - const monthNames = { - 'január': 0, 'február': 1, 'március': 2, 'április': 3, 'május': 4, 'június': 5, - 'július': 6, 'augusztus': 7, 'szeptember': 8, 'október': 9, 'november': 10, 'december': 11 - }; - - const startMonthNum = monthNames[startMonth.toLowerCase()]; - const endMonthNum = monthNames[endMonth.toLowerCase()]; - - if (startMonthNum !== undefined && endMonthNum !== undefined) { - startMonth = startMonthNum; - endMonth = endMonthNum; - } else { - continue; - } - } - - const weekStart = new Date(parseInt(year), startMonth, parseInt(startDay)); - const weekEnd = new Date(parseInt(year), endMonth, parseInt(endDay)); - - if (today >= weekStart && today <= weekEnd) { - foundWeekIndex = i; - console.log(`Megtalált jelenlegi hét: ${i}`); - break; - } - } - } - - if (foundWeekIndex !== -1) { - currentWeekIndex = foundWeekIndex; } else { - currentWeekIndex = Math.min(41, weekOptions.length - 1); - console.log(`Nem találtuk a jelenlegi hetet, fallback: ${currentWeekIndex}`); } - - kendoCombo.value(currentWeekIndex.toString()); - kendoCombo.trigger('change'); + } catch (error) { + console.error(`Hiba az API feldolgozása során (${index}):`, error, event); } - - console.log('Beállított currentWeekIndex:', currentWeekIndex); - } - const timetableData = { - 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' - }, - weekInfo: { - title: document.querySelector('.fc-center h2')?.textContent?.trim() || 'Hét', - options: Array.from(document.querySelectorAll('#Calendar_tanevHetek_listbox li')) - .map((li, i) => ({ - text: li.textContent.trim(), - value: i.toString(), - selected: i === currentWeekIndex - })) - }, - weekDates: dates, - lessons: [] - }; - - for (const event of document.querySelectorAll('.fc-event')) { - const timeEl = event.querySelector('.fc-time'); - const titleEl = event.querySelector('.fc-title'); - - if (timeEl && titleEl) { - const [startTime, endTime] = (timeEl.getAttribute('data-full') || timeEl.textContent || '').split(' - '); - const [fullSubject, teacher, room] = titleEl.innerHTML.split('
').map(str => str.trim()); - const subject = fullSubject.split('-')[0].trim(); - - let originalTeacher = ''; - if (teacher.startsWith('Helyettesítő:')) { - event.click(); - originalTeacher = await helper.waitForElement("#OraAdatokDetailTabStrip-1 > div > div:nth-child(3) > div:nth-child(2)"); - originalTeacher = originalTeacher.innerText; - document.querySelector("body > div.k-widget.k-window > div.k-window-titlebar.k-header > div > a:nth-child(2)").click(); - } - - timetableData.lessons.push({ - startTime, - endTime, - subject: subject || '', - teacher: teacher || '', - originalTeacher: originalTeacher || '', - room: (room || '').replace(/[()]/g, ''), - day: event.closest('td').cellIndex - 1, - isSubstituted: event.querySelector('.fc-bg2') !== null, - isCancelled: event.classList.contains('fc-textline-through'), - hasHomework: titleEl.querySelector('.hasCalendarIcon') !== null, - testInfo: event.getAttribute('data-tooltiptext') || '', - homeworkDetails: event.getAttribute('data-homework') || '' - }); - } - } - return timetableData; + }); + return lessons; } function generateTimeGrid(lessons, weekDates) { @@ -290,7 +124,13 @@ const timeB = helper.convertTimeToMinutes(b); return timeA - timeB; }); - const days = ['Hétfő', 'Kedd', 'Szerda', 'Csütörtök', 'Péntek']; + const days = [ + LanguageManager.t('timetable.monday'), + LanguageManager.t('timetable.tuesday'), + LanguageManager.t('timetable.wednesday'), + LanguageManager.t('timetable.thursday'), + LanguageManager.t('timetable.friday') + ]; return `
@@ -324,17 +164,17 @@
${lesson.teacher}
${lesson.room}
-
${lesson.isCancelled ? 'Elmarad' : lesson.startTime}
+
${lesson.isCancelled ? LanguageManager.t('timetable.cancelled') : lesson.startTime}
${lesson.hasHomework || lesson.testInfo ? `
${lesson.hasHomework ? ` - + assignment ` : ''} ${lesson.testInfo ? ` - + quiz ` : ''} @@ -362,31 +202,31 @@