63 Commits

Author SHA1 Message Date
Zan
ec99a3b5c8 Merge pull request #20 from QwIT-Development/firefox
Firefox
2025-08-06 14:12:35 +02:00
Zan
02ffa23e1a Merge branch 'main' into firefox 2025-08-06 14:12:24 +02:00
Zan1456
d7ea449a1b Minimal fixes 2025-08-06 14:06:00 +02:00
Zan1456
e7ec225e18 Updated chart.js 2025-06-14 09:42:33 +02:00
Zan1456
5a9837e655 . 2025-06-14 09:05:07 +02:00
Zan1456
1a340a1950 fixed week select 2025-06-13 14:50:49 +02:00
Zan1456
eef39c28d2 removed unused 2025-06-13 14:49:40 +02:00
Zan1456
89266bc3c9 Fixed week select 2025-06-13 14:41:21 +02:00
Zan1456
5408a1e08a . 2025-06-13 14:02:54 +02:00
Zan1456
6a52c51ece . 2025-06-13 13:59:17 +02:00
Zan1456
107e20f5c1 . 2025-06-13 13:26:21 +02:00
Zan1456
cb54d51b8c Added store logos 2025-06-10 22:58:14 +02:00
Zan1456
8eb7256f5b . 2025-06-10 22:54:27 +02:00
Zan
3510288181 Added firefox addonstore 2025-06-10 22:37:28 +02:00
Zan1456
8c9e1b215f version bump 2025-06-09 16:13:19 +02:00
Zan1456
e930706eb1 Fully working 2025-06-09 16:11:15 +02:00
Zan1456
5340c1dff0 Full rework 2025-06-09 16:10:15 +02:00
Zan1456
f3439a93d0 Merge branch 'main' of https://github.com/QwIT-Development/firka-extension 2025-06-09 13:46:42 +02:00
Zan1456
3e7b7089dd better scrolling 2025-06-09 13:33:44 +02:00
Anchietae
185f486a62 typo 2025-06-09 09:52:03 +02:00
Zan
048f249dc5 Update README.md 2025-06-08 23:29:44 +02:00
Zan1456
5d9ae6971b version dump 2025-06-08 23:24:06 +02:00
Zan1456
42bfa0912f . 2025-06-08 22:47:25 +02:00
Zan1456
0322b31146 Fixed user dropdown 2025-06-08 22:36:02 +02:00
Zan1456
52fc99ca99 navbar fixes 2025-06-08 22:24:13 +02:00
Zan1456
0a65ed3dda Removed logs 2025-06-08 22:23:25 +02:00
Zan1456
5a836947e1 rem cap 2025-06-08 21:42:58 +02:00
Zan1456
ebb291ee87 Title and icon 2025-06-08 21:42:51 +02:00
Zan1456
56dcef30e0 Load back the username at login 2025-06-08 21:32:37 +02:00
Zan1456
cfe6e0fccf search fix 2025-06-04 17:10:55 +02:00
Zan1456
bacf77b506 2fa support 2025-06-04 16:56:54 +02:00
Zan1456
3ee34b90e6 captcha 2025-06-04 16:44:42 +02:00
Zan1456
0e1f97eaaa search 2025-06-04 16:43:32 +02:00
Zan1456
699d2604c6 Update .gitignore 2025-06-04 16:40:14 +02:00
Zan1456
d8f1622b5b search 2025-06-04 16:40:10 +02:00
Zan1456
b69c9f3f6a search 2025-06-04 16:39:50 +02:00
Zan1456
ebf6aa8d61 Revert "typo"
This reverts commit ea5e01ce9c.
2025-06-04 16:38:18 +02:00
Zan1456
0048ebb932 hover fix 2025-06-04 16:35:06 +02:00
Zan1456
a55e40ecf2 rm 2025-06-04 16:30:29 +02:00
Zan1456
ea5e01ce9c typo 2025-06-04 16:29:32 +02:00
Zan1456
c0e738fd8b Merge branch 'main' of https://github.com/QwIT-Development/firka-extension 2025-06-04 16:29:12 +02:00
Zan
842588a0bb Merge pull request #11 from JeromeSchmied/releases-link
ci: add link checker
2025-04-22 15:16:55 +02:00
Jeromos Kovács
be2e7a192b Merge branch 'main' into releases-link 2025-04-21 17:39:09 +02:00
Zan
60ad73ffae Merge pull request #13 from MrS-1302/patch-2
Update build.yml
2025-04-21 09:23:24 +02:00
Mr.S
3a9bbbcb2a Update build.yml 2025-04-03 21:52:39 +02:00
Jeromos Kovács
afb7a3d79b ci: add link checker 2025-03-26 09:40:21 +01:00
Zan
95d50e9297 Merge pull request #12 from JeromeSchmied/firefox-install-docs
add installation instructions for firefox-based browsers
2025-03-25 21:56:33 +01:00
Zan
e88566369a Update README.md 2025-03-25 21:56:04 +01:00
Jeromos Kovács
b9985ccf09 docs(installation): add instructions for firefox-based browsers 2025-03-25 17:46:29 +01:00
Zan
88706017f9 Merge branch 'main' of https://github.com/QwIT-Development/firka-extension 2025-03-25 17:04:44 +01:00
Zan
0aef3950e7 Merge pull request #10 from JeromeSchmied/main
docs: GNU GPLv3 is **not** GNU AGPLv3
2025-03-25 17:01:54 +01:00
Zan
db74cb1a37 Merge pull request #9 from balint1414/main
Hibás fiók linkek szerkesztése
2025-03-25 16:57:05 +01:00
Jeromos Kovács
0d71510c7f docs: GNU GPLv3 is **not** GNU AGPLv3 2025-03-25 16:18:02 +01:00
ee26b6d966 Hibás fiók linkek szerkesztése 2025-03-22 17:12:28 +01:00
Zan
731511d28a gh token fix needed 2025-03-17 21:43:46 +01:00
Zan
79b09cb1ab Automatikus buildelés 2025-03-17 20:49:50 +01:00
Zan
1730c108df Merge pull request #5 from MrS-1302/remove-duplications
duplication fix in css files is not started
removed some enter
2025-03-17 20:34:46 +01:00
MrS-1302
f990e2e899 remove some duplication & faster loading page
duplication fix in css files is not started
removed some enter
2025-03-17 20:03:46 +01:00
Zan
2feef43ef2 Merge pull request #2 from MrS-1302/dev
chart
- fixed incorrect behavior when value is NaN
- the height is don't same with semester grades
subject cards
- i added max height for better appearance
hotfix for grades-overview
- made it responsive
2025-03-17 16:26:41 +01:00
MrS-1302
dfc0c362c7 you can see original teacher too when a substitute is assigned 2025-03-14 22:03:51 +01:00
MrS-1302
367547f67f fix multiple classes in the same hour problem 2025-03-14 19:47:06 +01:00
MrS-1302
003db8569e Fixes for grades page
- chart
   - fixed incorrect behavior when value is NaN
   - the height is don't same with semester grades
- subject cards
  - i added max height for better appearance
- hotfix for grades-overview
  - made it responsive
2025-03-14 18:29:54 +01:00
Zan
4eee8fa7e6 Update README.md 2025-03-14 15:06:41 +01:00
53 changed files with 6573 additions and 3533 deletions

71
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,71 @@
name: Package and Release Extension
on:
workflow_dispatch:
push:
branches:
- test
jobs:
build-and-release:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Get current date
id: date
run: |
echo "DATE=$(date +'%Y.%m.%d. %H:%M')" >> $GITHUB_ENV
echo "DATE_FOR_ZIP=$(date +'%Y%m%d-%H%M')" >> $GITHUB_ENV
- name: Create ZIP file
run: |
zip -r "pre-firxa-${{ env.DATE_FOR_ZIP }}.zip" . -x "*.git*" "*.github*" "*.idea*"
- name: Delete previous pre-release
uses: dev-drprasad/delete-tag-and-release@v0.2.1
with:
delete_release: true
tag_name: pre-release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
continue-on-error: true
- name: Create new pre-release
id: create_release
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: pre-release
release_name: Fejlesztői build
body: |
Ez egy kiadás előtti build, amely minden egyes commit után frissül!
A build automatikusan készült ekkor: ${{ env.DATE }}
draft: false
prerelease: true
- name: Upload ZIP to release
if: steps.create_release.outputs.upload_url != ''
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./pre-firxa-${{ env.DATE_FOR_ZIP }}.zip
asset_name: pre-firxa-${{ env.DATE_FOR_ZIP }}.zip
asset_content_type: application/zip
check-links:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Link Checker
id: lychee
uses: lycheeverse/lychee-action@v2
with:
fail: false

2
.gitignore vendored
View File

@@ -7,3 +7,5 @@ META-INF/cose.sig
META-INF/manifest.mf
META-INF/mozilla.sf
dashboard/KRÉTA Iskolai Alaprendszer.html
*.xml
*.xml

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

6
.idea/misc.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

8
.idea/modules.xml generated
View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/Firkaextension.iml" filepath="$PROJECT_DIR$/.idea/Firkaextension.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

45
.idea/workspace.xml generated
View File

@@ -1,45 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AutoImportSettings">
<option name="autoReloadType" value="NONE" />
</component>
<component name="ChangeListManager">
<list default="true" id="2540850d-5586-4ef8-a1c0-838ec2731d44" name="Changes" comment="" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="ClangdSettings">
<option name="formatViaClangd" value="false" />
</component>
<component name="ProjectColorInfo"><![CDATA[{
"associatedIndex": 0
}]]></component>
<component name="ProjectId" id="2uHD20KrXgQVbKPvZ8rqEw44Sjy" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"RunOnceActivity.ShowReadmeOnStart": "true",
"RunOnceActivity.cidr.known.project.marker": "true",
"RunOnceActivity.readMode.enableVisualFormatting": "true",
"cf.first.check.clang-format": "false",
"cidr.known.project.marker": "true",
"kotlin-language-version-configured": "true"
}
}]]></component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="2540850d-5586-4ef8-a1c0-838ec2731d44" name="Changes" comment="" />
<created>1741896394934</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1741896394934</updated>
</task>
<servers />
</component>
</project>

View File

@@ -8,14 +8,23 @@
</p>
<p align="center">
<a href="https://github.com/Zan1456/Firkaextension/releases">
<img src="https://img.shields.io/github/downloads-pre/Zan1456/Firkaextension/latest/total?style=for-the-badge&logo=github&logoColor=EAF7CC&label=Let%C3%B6lt%C3%A9sek&labelColor=141905&color=A7DC22" alt="Downloads">
<a href="https://github.com/QwIT-Development/firka-extension/releases">
<img src="https://img.shields.io/github/downloads-pre/QwIT-Development/firka-extension/latest/total?style=for-the-badge&logo=github&logoColor=EAF7CC&label=Let%C3%B6lt%C3%A9sek&labelColor=141905&color=A7DC22" alt="Downloads">
</a>
<a href="https://discord.gg/6DvjyPAw2T">
<img src="https://img.shields.io/discord/1111649116020285532?style=for-the-badge&logo=discord&logoColor=EAF7CC&label=Discord&labelColor=0D1202&color=A7DC22" alt="Discord">
</a>
<a href="https://github.com/Zan1456/Firkaextension/blob/main/LICENSE">
<img src="https://img.shields.io/github/license/Zan1456/Firkaextension?style=for-the-badge&logo=discord&logoColor=EAF7CC&label=Discord&labelColor=0D1202&color=A7DC22" alt="License">
<a href="https://github.com/QwIT-Development/firka-extension/blob/main/LICENSE">
<img src="https://img.shields.io/github/license/QwIT-Development/firka-extension?style=for-the-badge&logo=discord&logoColor=EAF7CC&label=Discord&labelColor=0D1202&color=A7DC22" alt="License">
</a>
</p>
<p align="center">
<a href="https://chromewebstore.google.com/detail/firxa/emafoaifbfppcccgfmpcoheonhjnpldj?hl=hu">
<img src="https://github.com/QwIT-Development/firka-extension/blob/main/images/chrome.png?raw=true" alt="Elérhető a Chrome Web Store-on" width="200">
</a>
<a href="https://addons.mozilla.org/hu/firefox/addon/firxa/">
<img src="https://github.com/QwIT-Development/firka-extension/blob/main/images/firefox.png?raw=true" alt="Elérhető a Firefox add-ons oldalon" width="200">
</a>
</p>
@@ -34,13 +43,7 @@
## 🚀 Telepítés
1. Töltsd le a legfrissebb verziót a [Releases](https://github.com/Zan1456/Firkaextension/releases) oldalról
2. Csomagold ki a letöltött fájlt
3. Chrome böngészőben navigálj a `chrome://extensions` oldalra
4. Kapcsold be a "Fejlesztői mód"-ot a jobb felső sarokban
5. Kattints a "Kicsomagolt bővítmény betöltése" gombra
6. Válaszd ki a kicsomagolt mappát
7. Kész! A bővítmény automatikusan működésbe lép, amikor megnyitod az e-KRÉTA oldalt
1. Töltsd le a legfrissebb verziót a fenti gombok segítségével a böngésződnek megfelelően.
## ⚙️ Beállítások
@@ -61,12 +64,13 @@ A bővítmény jelenleg az alábbi e-KRÉTA oldalakat támogatja:
- Hiányzások
- Házi feladatok
- Jegyek
- Intézménykereső
## 👥 Csapat
- **[Zan1456](https://github.com/Zan1456)** - Vezető Fejlesztő
- **[BalazsManus](https://github.com/BalazsManus)** - Fejlesztő
- **[Xou](https://github.com/Xou)** - Designer
- **[BalazsManus](https://github.com/olajcsere)** - Fejlesztő
- **[Xou](https://yoursit.ee/xou)** - Designer
## 🤝 Közreműködés
@@ -80,7 +84,7 @@ A bővítmény jelenleg az alábbi e-KRÉTA oldalakat támogatja:
## 📝 Licensz
A projekt [GNU General Public License v3.0](LICENSE) alatt jelent meg. További információért lásd a LICENSE fájlt.
A projekt [GNU Affero General Public License v3.0](LICENSE) alatt jelent meg. További információért lásd a LICENSE fájlt.
## 💬 Kapcsolat

View File

@@ -42,10 +42,10 @@ body {
@media (max-width: 768px) {
.kreta-header {
grid-template-columns: 1fr auto;
grid-template-columns: 1fr auto auto;
grid-template-areas:
"school user"
"nav nav";
"school toggle user"
"nav nav nav";
padding: 1rem;
gap: 0.5rem;
}
@@ -110,77 +110,6 @@ body {
}
}
.kreta-nav {
padding: 0 clamp(0.5rem, 3vw, 1.5rem);
position: sticky;
top: 0;
z-index: 100;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
-ms-overflow-style: none;
display: flex;
justify-content: center;
}
@media (max-width: 768px) {
.kreta-nav {
grid-area: nav;
padding: 0;
margin-top: 0.5rem;
}
}
.nav-links {
display: flex;
gap: clamp(0.5rem, 2vw, 1rem);
padding: 0.25rem;
justify-content: center;
}
@media (max-width: 768px) {
.nav-links {
justify-content: flex-start;
width: 100%;
gap: 0.25rem;
}
}
.nav-links a {
color: var(--text-secondary);
text-decoration: none;
padding: clamp(0.5rem, 1.5vw, 1rem) 0.5rem;
font-weight: 500;
white-space: nowrap;
transition: all 0.2s ease;
display: flex;
align-items: center;
gap: 0.5rem;
border-radius: 8px;
}
@media (max-width: 768px) {
.nav-links a {
padding: 0.5rem;
font-size: 13px;
}
.nav-links a .material-icons-round {
font-size: 20px;
}
}
.nav-links a:hover {
color: var(--text-primary);
background-color: var(--card-card);
}
.nav-links a.active {
color: var(--accent-accent);
}
.user-profile {
position: relative;
justify-self: flex-end;
@@ -212,19 +141,6 @@ body {
text-align: right;
}
.user-name {
display: block;
color: var(--text-primary);
font-size: 16px;
font-weight: 500;
}
.user-time {
display: block;
color: var(--text-secondary);
font-size: 14px;
}
.user-dropdown {
position: absolute;
top: 100%;

View File

@@ -1,213 +1,101 @@
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 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 function 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
});
});
}
async function collectAbsencesData() {
await waitForElement('#HianyzasGrid');
await new Promise(resolve => setTimeout(resolve, 1000));
const basicData = {
schoolInfo: {
name: getCookie('schoolName') || 'Iskola',
id: getCookie('schoolCode') || ''
name: cookieManager.get('schoolName') || 'Iskola',
id: cookieManager.get('schoolCode') || ''
},
userData: {
name: getCookie('userName') || 'Felhasználó',
name: cookieManager.get('userName') || 'Felhasználó',
time: document.querySelector('.usermenu_timer')?.textContent?.trim() || '45:00'
}
};
const absences = [];
const rows = document.querySelectorAll('#HianyzasGrid .k-grid-content tr');
rows.forEach(row => {
const cells = row.querySelectorAll('td');
if (cells.length >= 9) {
absences.push({
date: cells[1]?.textContent?.trim() || '',
lesson: cells[2]?.textContent?.trim() || '',
subject: cells[3]?.textContent?.trim() || '',
topic: cells[4]?.textContent?.trim() || '',
type: cells[5]?.textContent?.trim() || '',
justified: cells[6]?.textContent?.trim() === 'Igen',
justificationStatus: cells[6]?.textContent?.trim() === 'Igen' ? 'justified' :
cells[6]?.textContent?.trim() === 'Nem' ? 'unjustified' : 'pending',
purposeful: cells[7]?.textContent?.trim() || '',
justificationType: cells[8]?.textContent?.trim() || ''
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'
}
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const apiData = await response.json();
const absences = [];
if (apiData.Data && Array.isArray(apiData.Data)) {
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')}.`;
let justificationStatus = 'pending';
if (item.Igazolt_BOOL === true) {
justificationStatus = 'justified';
} else if (item.Igazolt_BOOL === false && item.IgazolasTipus !== null) {
justificationStatus = 'unjustified';
}
absences.push({
date: formattedDate,
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 || ''
});
});
}
});
const groupedAbsences = {};
absences.forEach(absence => {
if (!groupedAbsences[absence.date]) {
groupedAbsences[absence.date] = [];
}
groupedAbsences[absence.date].push(absence);
});
const groupedAbsences = {};
absences.forEach(absence => {
if (!groupedAbsences[absence.date]) {
groupedAbsences[absence.date] = [];
}
groupedAbsences[absence.date].push(absence);
});
return { basicData, absences, groupedAbsences };
}
function showLoadingScreen() {
const loadingHTML = `
<div class="loading-overlay">
<div class="loading-container">
<img src="https://i.imgur.com/JE3LzRc.gif" alt="Firka" class="loading-logo"><!--logó csere-->
<div class="loading-text">Betöltés alatt...</div>
<p class="loading-text2">Kis türelmet</p>
</div>
</div>
`;
document.body.insertAdjacentHTML('beforeend', loadingHTML);
}
function hideLoadingScreen() {
const loadingOverlay = document.querySelector('.loading-overlay');
if (loadingOverlay) {
loadingOverlay.style.opacity = '0';
loadingOverlay.style.transition = 'opacity 0.3s ease';
setTimeout(() => loadingOverlay.remove(), 300);
return { basicData, absences, groupedAbsences };
} catch (error) {
console.error('Hiba az API hívás során:', error);
return { basicData, absences: [], groupedAbsences: {} };
}
}
async function transformAbsencesPage() {
showLoadingScreen();
const { basicData, absences, groupedAbsences } = await collectAbsencesData();
const schoolNameFull = `${basicData.schoolInfo.id} - ${basicData.schoolInfo.name}`;
const shortenedSchoolName = shortenSchoolName(schoolNameFull);
document.body.innerHTML = `
<div class="kreta-container">
<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">
Firka
</p>
<div class="school-details" title="${schoolNameFull}">
${shortenedSchoolName}
</div>
</div>
<nav class="kreta-nav">
<div class="nav-links">
<a href="/Intezmeny/Faliujsag" data-page="dashboard" class="nav-item">
<img src="${chrome.runtime.getURL('icons/dashboard-inactive.svg')}" alt="Kezdőlap">
Kezdőlap
</a>
<a href="/TanuloErtekeles/Osztalyzatok" data-page="grades" class="nav-item">
<img src="${chrome.runtime.getURL('icons/grades-inactive.svg')}" alt="Jegyek">
Jegyek
</a>
<a href="/Orarend/InformaciokOrarend" data-page="timetable" class="nav-item">
<img src="${chrome.runtime.getURL('icons/timetable-inactive.svg')}" alt="Órarend">
Órarend
</a>
<a href="/Hianyzas/Hianyzasok" data-page="absences" class="nav-item active">
<img src="${chrome.runtime.getURL('icons/absences-active.svg')}" alt="Mulasztások">
Mulasztások
</a>
<a href="/Tanulo/TanuloHaziFeladat" data-page="other" class="nav-item">
<img src="${chrome.runtime.getURL('icons/others.svg')}" alt="Egyéb">
Egyéb
</a>
</div>
</nav>
<div class="user-profile">
<button class="user-dropdown-btn">
<div class="user-info">
<span class="user-name">${basicData.userData.name}</span>
<span class="nav-logout-timer" id="logoutTimer">${basicData.userData.time}</span>
</div>
</button>
<div class="user-dropdown">
<a href="/Adminisztracio/Profil" data-page="profile" class="dropdown-item">
<img src="${chrome.runtime.getURL('icons/profile.svg')}" alt="Profil">
Profil
</a>
<a href="#" class="dropdown-item" id="settingsBtn">
<img src="${chrome.runtime.getURL('icons/settings.svg')}" alt="Beállítások">
Beállítások
</a>
<a href="/Home/Logout" data-page="logout" class="dropdown-item">
<img src="${chrome.runtime.getURL('icons/logout.svg')}" alt="Kijelentkezés">
Kijelentkezés
</a>
</div>
</div>
</header>
${createTemplate.header()}
<main class="kreta-main">
<div class="filter-card">
<div class="filter-header">
<h2>Szűrés</h2>
<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>
Dátum
${LanguageManager.t('absences.date')}
</label>
<input type="date" id="dateFilter" class="filter-input" disabled>
<input type="date" id="dateFilter" class="filter-input">
</div>
<div class="filter-group">
<label>
<span class="material-icons-round">school</span>
Tantárgy
${LanguageManager.t('absences.subject')}
</label>
<select id="subjectFilter" class="filter-input">
<option value="">Minden tantárgy</option>
<option value="">${LanguageManager.t('absences.all_subjects')}</option>
${[...new Set(absences.map(a => a.subject))].sort().map(subject =>
`<option value="${subject}">${subject}</option>`
).join('')}
@@ -216,13 +104,13 @@ async function transformAbsencesPage() {
<div class="filter-group">
<label>
<span class="material-icons-round">check_circle</span>
Igazolás
${LanguageManager.t('absences.justification')}
</label>
<select id="justificationFilter" class="filter-input">
<option value="">Mindegy</option>
<option value="justified">Igazolt</option>
<option value="unjustified">Igazolatlan</option>
<option value="pending">Igazolásra vár</option>
<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>
@@ -234,7 +122,7 @@ async function transformAbsencesPage() {
<div class="absence-date">
<span class="material-icons-round">event</span>
${date}
<span class="absence-count">${dayAbsences.length} óra</span>
<span class="absence-count">${dayAbsences.length} ${LanguageManager.t('absences.hours')}</span>
</div>
<div class="absence-list">
${dayAbsences.map(absence => `
@@ -243,7 +131,7 @@ async function transformAbsencesPage() {
data-justified="${absence.justified}">
<div class="absence-time">
<span class="material-icons-round">schedule</span>
${absence.lesson}. óra
${absence.lesson}. ${LanguageManager.t('absences.lesson').toLowerCase()}
</div>
<div class="absence-details">
<div class="absence-subject">${absence.subject}</div>
@@ -251,10 +139,10 @@ async function transformAbsencesPage() {
</div>
<div class="absence-status ${absence.justificationStatus}">
${absence.justificationStatus === 'justified' ?
`Igazolt <span class="material-icons-round">check_circle</span>` :
`${LanguageManager.t('absences.justified')} <span class="material-icons-round">check_circle</span>` :
absence.justificationStatus === 'unjustified' ?
`Igazolatlan <span class="material-icons-round">cancel</span>` :
`Igazolásra vár <span class="material-icons-round">pending</span>`}
`${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('')}
@@ -266,69 +154,17 @@ async function transformAbsencesPage() {
</div>
`;
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/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);
});
createTemplate.importFonts();
setupUserDropdown();
setupMobileNavigation();
setupEventListeners();
setupFilters();
hideLoadingScreen();
loadingScreen.hide();
}
function setupEventListeners(data) {
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');
});
const timerEl = document.getElementById('logoutTimer');
if (timerEl) {
const startTime = parseInt(timerEl.textContent?.match(/\d+/)?.[0] || "30");
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);
}
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 setupEventListeners() {
}
function setupFilters() {
@@ -345,56 +181,42 @@ function setupFilters() {
return;
}
if (filters.dateFilter) {
filters.dateFilter.disabled = true;
}
const filterAbsences = () => {
try {
const dateFilterValue = filters.dateFilter.value;
const subject = filters.subject.value;
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('.');
if (dateParts.length < 3) {
console.error(`Invalid date format: ${dateStr}`);
return;
}
const parsedDay = parseInt(dateParts[0].trim(), 10);
const parsedYear = parseInt(dateParts[0].trim(), 10);
const parsedMonth = parseInt(dateParts[1].trim(), 10) - 1;
const parsedYear = parseInt(dateParts[2].trim(), 10);
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;
// if (selectedDate && dateFilterValue) {
// // Compare year, month, and day to ignore time
// showGroup = groupDate.getFullYear() === selectedDate.getFullYear() &&
// groupDate.getMonth() === selectedDate.getMonth() &&
// groupDate.getDate() === selectedDate.getDate();
//
// console.log(`Comparing dates: ${groupDate.toDateString()} vs ${selectedDate.toDateString()}, match: ${showGroup}`);
// }
if (selectedDate) {
if (groupDate.getFullYear() !== selectedDate.getFullYear() ||
groupDate.getMonth() !== selectedDate.getMonth() ||
groupDate.getDate() !== selectedDate.getDate()) {
showGroup = false;
}
}
const absenceItems = group.querySelectorAll('.absence-item');
let visibleItems = 0;
@@ -422,15 +244,9 @@ function setupFilters() {
};
// if (!filters.dateFilter.value) {
// const today = new Date();
// filters.dateFilter.value = today.toISOString().split('T')[0]; // Set date to today by default
// }
Object.values(filters).forEach(filter => {
try {
if (filter && filter !== filters.dateFilter) { // Don't add event listener to dateFilter
if (filter) {
filter.addEventListener('change', filterAbsences);
}
} catch (err) {
@@ -457,6 +273,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);
});
}

View File

@@ -14,6 +14,10 @@ body {
font-size: 16px;
}
h2 {
background-color: #00000000 !important;
}
.kreta-container {
min-height: 100vh;
display: flex;
@@ -35,42 +39,185 @@ 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);
display: flex;
flex-direction: column;
margin-bottom: 12px;
padding: 12px;
padding: 8px;
position: relative;
min-height: 80px;
}
.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 +231,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;
@@ -120,6 +277,7 @@ body {
.grade-3 {color: var(--grades-3); background-color: var(--grades-background-3);}
.grade-4 {color: var(--grades-4); background-color: var(--grades-background-4);}
.grade-5 {color: var(--grades-5); background-color: var(--grades-background-5);}
.grade-Sz {color: var(--grades-3); background-color: var(--grades-background-3);}
@keyframes fadeIn {
from {
@@ -179,15 +337,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;
@@ -211,22 +379,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 {

View File

@@ -1,52 +1,49 @@
const utils = {
shortenSchoolName(name, maxLength = 50) {
if (!name || name.length <= maxLength) return name || '';
const [code, fullName] = name.split(' - ');
if (fullName) {
const maxFullNameLength = maxLength - code.length - 3;
if (fullName.length > maxFullNameLength) {
return `${code} - ${fullName.substring(0, maxFullNameLength)}...`;
}
}
return `${name.substring(0, maxLength - 3)}...`;
},
const DashboardUtils = {
formatGradeValue(value) {
return value?.trim() || '';
const trimmedValue = value?.trim() || '';
if (trimmedValue.toLowerCase() === 'szöveges') {
return 'Sz';
}
return trimmedValue;
},
parseDate(dateStr) {
return dateStr?.trim() || '';
},
formatHungarianDate(dateStr) {
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;
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: [],
@@ -55,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;
@@ -107,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;
@@ -122,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;
@@ -138,309 +158,294 @@ 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,
schoolInfo: {
name: cookies.getCookie(COOKIE_KEYS.SCHOOL_NAME) || DEFAULT_VALUES.SCHOOL,
id: cookies.getCookie(COOKIE_KEYS.SCHOOL_CODE) || ''
name: cookieManager.get(COOKIE_KEYS.SCHOOL_NAME) || DEFAULT_VALUES.SCHOOL,
id: cookieManager.get(COOKIE_KEYS.SCHOOL_CODE) || ''
},
userData: {
name: cookies.getCookie(COOKIE_KEYS.USER_NAME) || DEFAULT_VALUES.USER,
name: cookieManager.get(COOKIE_KEYS.USER_NAME) || DEFAULT_VALUES.USER,
time: document.querySelector('.usermenu_timer')?.textContent?.trim() || DEFAULT_VALUES.TIMER
}
};
this.schoolNameFull = `${this.data.schoolInfo.id} - ${this.data.schoolInfo.name}`;
this.shortenedSchoolName = utils.shortenSchoolName(this.schoolNameFull);
this.shortenedSchoolName = helper.shortenSchoolName(this.schoolNameFull);
}
static generateHeaderHTML(data, schoolNameFull, shortenedSchoolName) {
return `
<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">
Firka
</p>
<div class="school-details" title="${schoolNameFull}">
${shortenedSchoolName}
</div>
</div>
<nav class="kreta-nav">
<div class="nav-links">
<a href="/Intezmeny/Faliujsag" data-page="dashboard" class="nav-item active">
<img src="${chrome.runtime.getURL('icons/dashboard-active.svg')}" alt="Kezdőlap">
Kezdőlap
</a>
<a href="/TanuloErtekeles/Osztalyzatok" data-page="grades" class="nav-item">
<img src="${chrome.runtime.getURL('icons/grades-inactive.svg')}" alt="Jegyek">
Jegyek
</a>
<a href="/Orarend/InformaciokOrarend" data-page="timetable" class="nav-item">
<img src="${chrome.runtime.getURL('icons/timetable-inactive.svg')}" alt="Órarend">
Órarend
</a>
<a href="/Hianyzas/Hianyzasok" data-page="absences" class="nav-item">
<img src="${chrome.runtime.getURL('icons/absences-inactive.svg')}" alt="Mulasztások">
Mulasztások
</a>
<a href="/Tanulo/TanuloHaziFeladat" data-page="other" class="nav-item">
<img src="${chrome.runtime.getURL('icons/others.svg')}" alt="Egyéb">
Egyéb
</a>
</div>
</nav>
<div class="user-profile">
<button class="user-dropdown-btn">
<div class="user-info">
<span class="user-name">${data.userData.name}</span>
<span class="nav-logout-timer" id="logoutTimer">${data.userData.time}</span>
</div>
</button>
<div class="user-dropdown">
<a href="/Adminisztracio/Profil" data-page="profile" class="dropdown-item">
<img src="${chrome.runtime.getURL('icons/profile.svg')}" alt="Profil">
Profil
</a>
<a href="#" class="dropdown-item" id="settingsBtn">
<img src="${chrome.runtime.getURL('icons/settings.svg')}" alt="Beállítások">
Beállítások
</a>
<a href="/Home/Logout" data-page="logout" class="dropdown-item">
<img src="${chrome.runtime.getURL('icons/logout.svg')}" alt="Kijelentkezés">
Kijelentkezés
</a>
</div>
</div>
</header>
`;
}
generateMainContentHTML() {
generateMainContent() {
return `
<main class="kreta-main">
<div class="grid-container">
${this.generateGradeCard()}
${this.generateAbsenceCard()}
${this.generateNoteCard()}
${this.generateExamCard()}
${this.generateNewsCard()}
${this.createGradeCard()}
${this.createAbsenceCard()}
${this.createNoteCard()}
${this.createExamCard()}
${this.createNewsCard()}
</div>
</main>
`;
}
generateNewsCard() {
createNewsCard() {
const newsItems = this.data.news.map(news => `
<div class="news-item">
<div class="news-header">
<div class="news-date">${news.date}</div>
${news.author ? `<div class="news-author">${news.author}</div>` : ''}
</div>
<div class="news-details">
<h3 class="news-title">${news.title}</h3>
<div class="news-content">${news.content}</div>
</div>
</div>
`).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 => `
<div class="grade-item">
<div class="grade-row">
<div class="grade grade-${grade.value}">${grade.value}</div>
<div class="grade-details">
<div class="subject-name">${grade.subject}</div>
<div class="grade-type">${grade.type}</div>
<div class="widget-item news-item">
<div class="widget-row">
<div class="widget-details news-details">
<div class="widget-title news-title">${news.title}</div>
<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>` : ''}
</div>
${grade.date ? `<div class="grade-date">${grade.date}</div>` : ''}
</div>
</div>
`).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 => `
<div class="widget-item grade-item">
<div class="widget-row grade-row">
<div class="grade grade-${grade.value}">${grade.value}</div>
<div class="widget-details grade-details">
<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>` : ''}
</div>
</div>
</div>
</div>
`).join('');
return this.createCard(LanguageManager.t('dashboard.grades'), gradeItems, '/TanuloErtekeles/Osztalyzatok', LanguageManager.t('dashboard.all_grades'));
}
createAbsenceCard() {
const absenceItems = this.data.absences.map(absence => `
<div class="absence-item">
<div class="absence-details">
<div class="absence-type">${absence.type}</div>
<div class="absence-date">${absence.date}</div>
<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>` : ''}
</div>
</div>
`).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 => `
<div class="note-item">
<div class="note-details">
<div class="note-title">${note.title}</div>
<div class="note-date">${note.date}</div>
<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>` : ''}
</div>
</div>
`).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 => `
<div class="exam-item">
<div class="exam-details">
<div class="exam-subject">${exam.subject}</div>
<div class="exam-date">${utils.formatHungarianDate(exam.date)}</div>
<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>
<div class="widget-date exam-date">${DashboardUtils.formatHungarianDate(exam.date)}</div>
</div>
</div>
`).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 `
<div class="card">
<h2>${title}</h2>
<div class="card-content">
${content || `Jelenleg ez egy nem támogatott funkció`}
<a href="${linkHref}" class="more-link">
<div class="widget-card card">
<div class="widget-header">
<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>`}
</div>
<div class="widget-footer">
<a href="${linkHref}" class="widget-link more-link">
${linkText}
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="17" viewBox="0 0 16 17" fill="none">
<path d="M11.2997 5.19947L5.64282 5.19947M11.2997 5.19947L11.2997 10.8563M11.2997 5.19947L4.70001 11.7991" stroke="var(--accent-accent)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</svg>
</a>
</div>
</div>
`;
}
render() {
document.body.innerHTML = `
<div class="kreta-container">
${DashboardUI.generateHeaderHTML(this.data, this.schoolNameFull, this.shortenedSchoolName)}
${this.generateMainContentHTML()}
${createTemplate.header()}
${this.generateMainContent()}
</div>
`;
setupUserDropdown();
setupLogoutTimer();
setupMobileNavigation();
}
}
function setupLogoutTimer() {
const timerElement = document.querySelector('.nav-logout-timer');
if (!timerElement) return;
const timeString = timerElement.textContent;
const startTime = parseInt(timeString?.match(/\d+/)?.[0] || "45");
let timeLeft = startTime * 60;
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);
}
class FontLoader {
static loadFonts() {
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/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);
});
}
}
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();
FontLoader.loadFonts();
const ui = new DashboardUI(dashboardData);
ui.render();
const dataManager = new DashboardDataManager();
const dashboardData = await dataManager.extractAllData();
createTemplate.importFonts();
const renderer = new DashboardRenderer(dashboardData);
renderer.render();
} catch (error) {
console.error('Error initializing dashboard:', error);
}
}
}
new DashboardApp();
new DashboardApplication();

View File

@@ -1,202 +1,292 @@
:root {
--primary: #050B15;
--secondary: #3F444F;
--tertiary: #1C469A;
--icon: #0A2456;
--accent: #3673EE;
--bg: #DAE4F7;
--card: #EDF3FF;
--cardsec: #FBFCFF;
--error: #E32D2D;
--error-bg: rgba(227, 45, 45, 0.05);
}
:root[data-theme="dark"] {
--primary: #EBF1FD;
--secondary: #CFD8E9;
--tertiary: #AEC8FC;
--icon: #BAD1FF;
--accent: #3673ed;
--bg: #070A0E;
--card: #0F131B;
--cardsec: #131822;
--error: #FF4444;
--error-bg: rgba(255, 68, 68, 0.1);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
margin: 0;
padding: 0;
color: var(--primary);
background-color: var(--bg) !important;
font-family: "Montserrat", serif !important;
min-height: 100vh;
font-size: 16px;
display: flex;
align-items: center;
justify-content: center;
}
* {
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;
}
.forgot-container {
width: 90%;
max-width: 500px;
padding: 20px;
margin: 0 auto;
}
.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);
}
.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;
}
.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;
}
.logo {
width: 48px;
height: 48px;
border-radius: 12px;
}
.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;
}
.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 {
width: 100%;
max-width: 500px;
padding: 20px;
margin: 0 auto;
}
.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;
padding: 16px;
}
.forgot-card {
background: var(--card);
padding: 24px;
border-radius: 24px;
margin-bottom: 16px;
padding: 20px;
}
.forgot-header {
margin-bottom: 20px;
}
.logo-text {
font-size: 18px;
}
.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;
color: var(--secondary);
font-size: 14px;
margin-bottom: 8px;
font-size: 20px;
}
.form-control {
width: 100%;
padding: 12px 16px;
border: 2px solid transparent;
border-radius: 12px;
font-size: 16px;
font-family: "Montserrat", serif;
background: var(--cardsec);
color: var(--primary);
transition: all 0.2s ease;
}
.form-control:focus {
outline: none;
border-color: var(--accent);
}
.form-control::placeholder {
color: var(--secondary);
}
.form-actions {
margin-top: 24px;
display: flex;
justify-content: space-between;
align-items: center;
}
.help-link {
color: var(--accent);
text-decoration: none;
height: 44px;
font-size: 14px;
transition: color 0.2s ease;
}
.help-link:hover {
color: var(--tertiary);
}
.btn-submit {
padding: 12px 24px;
background: var(--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;
}
.btn-submit:hover {
background: var(--tertiary);
}
.btn-submit:disabled {
opacity: 0.7;
cursor: not-allowed;
}
.error-message {
color: var(--error);
padding: 10px;
font-size: 14px;
margin-top: 4px;
display: none;
}
.error-message.show {
display: block;
animation: fadeIn 0.2s ease;
.help-link {
font-size: 12px;
}
}
@media (max-width: 600px) {
.forgot-container {
padding: 16px;
}
.g-recaptcha {
margin-top: 24px;
display: flex;
justify-content: center;
.forgot-card {
padding: 20px;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(-4px); }
to { opacity: 1; transform: translateY(0); }
.form-actions {
flex-direction: column;
gap: 16px;
align-items: stretch;
}
@media (max-width: 600px) {
.forgot-container {
padding: 16px;
}
.forgot-card {
padding: 20px;
}
.form-actions {
flex-direction: column;
gap: 16px;
align-items: stretch;
}
.btn-submit {
width: 100%;
}
}
}

View File

@@ -1,67 +1,169 @@
(() => {
const transformForgotPasswordPage = () => {
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);
}
}
};
const loadDependencies = async () => {
if (typeof cookieManager === 'undefined') {
const cookieScript = document.createElement('script');
cookieScript.src = chrome.runtime.getURL('tools/cookieManager.js');
document.head.appendChild(cookieScript);
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);
}
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);
document.body.innerHTML = `
<div class="forgot-container">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons+Round" rel="stylesheet">
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);
});
}
};
const createPageStructure = () => {
document.body.innerHTML = `
<div class="forgot-container">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons+Round" rel="stylesheet">
<style>
.g-recaptcha {
margin-top: 5px;
display: flex;
justify-content: center;
}
</style>
<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">
Firka
</p>
</header>
<div class="forgot-card">
<h1 class="forgot-title">Elfelejtett jelszó</h1>
<form id="forgotForm" novalidate>
<div class="form-group">
<label class="form-label" for="username">OM azonosítód</label>
<input type="text" id="username" name="username" class="form-control"
placeholder="Add meg az OM azonosítód" required>
<div class="error-message">Kérjük, add meg az OM azonosítód.</div>
</div>
<div class="form-group">
<label class="form-label" for="email">E-mail cím</label>
<input type="email" id="email" name="email" class="form-control"
placeholder="Add meg az e-mail címed" required>
<div class="error-message">Kérjük, add meg az e-mail címed.</div>
</div>
<div class="g-recaptcha" data-sitekey="6LcmPB8dAAAAACJPQBj7WfpBoBsEfyibZeIG5Vbl"></div>
<div class="form-actions">
<a href="/Adminisztracio/Login" class="help-link">
Vissza a bejelentkezéshez
</a>
<button type="submit" class="btn-submit">
Jelszó visszaállítása
</button>
</div>
</form>
</div>
<h1 class="forgot-title" data-i18n="forgotpassword.title">Elfelejtett jelszó</h1>
<form id="forgotForm" novalidate>
<div class="form-group">
<label class="form-label" for="BejelentkezesiNev" data-i18n="forgotpassword.om_id_label">OM azonosító</label>
<input type="text" id="BejelentkezesiNev" name="BejelentkezesiNev" class="form-control"
data-i18n-attr="placeholder" data-i18n="forgotpassword.om_id_placeholder"
placeholder="Adja meg az OM azonosítóját" required>
<div class="error-message" data-i18n="forgotpassword.om_id_required">Az OM azonosító megadása kötelező</div>
</div>
<div class="form-group">
<label class="form-label" for="EmailCim" data-i18n="forgotpassword.email_label">E-mail cím</label>
<input type="email" id="EmailCim" name="EmailCim" class="form-control"
data-i18n-attr="placeholder" data-i18n="forgotpassword.email_placeholder"
placeholder="Adja meg az e-mail címét" required>
<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>
<div class="form-actions">
<a href="/Adminisztracio/Login" class="help-link" data-i18n="forgotpassword.back_to_login">
Vissza a bejelentkezéshez
</a>
<button type="submit" class="btn-submit" data-i18n="forgotpassword.reset_button">
Jelszó visszaállítása
</button>
</div>
</form>
</div>
`;
setupFormValidation();
</div>
`;
};
const transformForgotPasswordPage = async () => {
await loadDependencies();
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);
}
});
createPageStructure();
let attempts = 0;
const maxAttempts = 50;
const waitForLanguageManager = () => {
return new Promise((resolve) => {
const checkLanguageManager = () => {
attempts++;
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');
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');
const translation = LanguageManager.t(key);
if (translation && translation !== key) {
const attr = element.getAttribute('data-i18n-attr');
if (attr) {
element.setAttribute(attr, translation);
} else {
element.textContent = translation;
}
}
});
}
setTimeout(() => {
renderRecaptcha();
}, 500);
setupFormValidation();
};
const setupFormValidation = () => {
const form = document.getElementById('forgotForm');
@@ -97,29 +199,83 @@
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;
}
});
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;
}
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;
}
if (!isValid) {
return;
}
const submitButton = form.querySelector('.btn-submit');
const originalText = submitButton.textContent;
submitButton.disabled = true;
submitButton.textContent = LanguageManager.t('loading.text') || 'Küldés...';
try {
const formData = new FormData(form);
if (typeof grecaptcha !== 'undefined') {
formData.append('ReCaptcha', grecaptcha.getResponse());
}
const response = await fetch('/Adminisztracio/ElfelejtettJelszo/LinkKuldes', {
method: 'POST',
body: formData,
@@ -127,26 +283,46 @@
'X-Requested-With': 'XMLHttpRequest'
}
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
if (result.Success) {
window.location.href = '/Adminisztracio/Login';
showMessage(LanguageManager.t('forgotpassword.success_message'));
form.reset();
if (typeof grecaptcha !== 'undefined') {
grecaptcha.reset();
}
setTimeout(() => {
window.location.href = '/Adminisztracio/Login';
}, 3000);
} 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)');
grecaptcha.reset();
showMessage(result.Message || LanguageManager.t('forgotpassword.error_message'), true);
if (typeof grecaptcha !== 'undefined') {
grecaptcha.reset();
}
}
} catch (error) {
//alert('Hiba történt a jelszó visszaállítása során.');
grecaptcha.reset();
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 (window.location.href.includes('/Adminisztracio/ElfelejtettJelszo')) {
transformForgotPasswordPage();
transformForgotPasswordPage().catch(console.error);
}
})();

131
global/language.js Normal file
View File

@@ -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' }
]
};
})();

View File

@@ -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;
}

View File

@@ -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);
}
}

View File

@@ -191,16 +191,42 @@
}
}
/* Hamburger menu styles */
.nav-toggle {
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);
}
.nav-toggle svg {
width: 24px;
height: 24px;
fill: var(--text-primary);
}
@media (max-width: 768px) {
.kreta-header {
grid-template-columns: 1fr auto;
grid-template-columns: 1fr auto auto;
grid-template-areas:
"school user"
"nav nav";
"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;
@@ -211,21 +237,24 @@
.logo-text {
margin: 0;
font-size: 20px;
font-size: 18px;
}
.school-details {
font-size: 12px;
font-size: 11px;
max-width: 200px;
}
.kreta-nav {
grid-area: nav;
padding: 0;
margin-top: 0.5rem;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
-ms-overflow-style: none;
display: none;
}
.kreta-nav.show {
display: flex;
animation: slideDown 0.3s ease;
}
.kreta-nav::-webkit-scrollbar {
@@ -233,25 +262,140 @@
}
.nav-links {
justify-content: flex-start;
flex-direction: column;
width: 100%;
gap: 0.25rem;
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 {
padding: 0.5rem;
font-size: 13px;
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: 14px;
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"
"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;
}
}
@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);
}
}

View File

@@ -6,31 +6,20 @@ 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'
};
const cookies = {
getCookie(name) {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
return parts.length === 2 ? parts.pop().split(';').shift() : null;
}
};
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: cookies.getCookie(COOKIE_KEYS.SCHOOL_NAME) || DEFAULT_VALUES.SCHOOL,
schoolId: cookies.getCookie(COOKIE_KEYS.SCHOOL_CODE) || '',
name: cookies.getCookie(COOKIE_KEYS.USER_NAME) || DEFAULT_VALUES.USER,
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
};
@@ -95,9 +84,39 @@ function setupSettingsButton() {
});
}
function setupMobileNavigation() {
setTimeout(() => {
const navToggle = document.querySelector('.nav-toggle');
const nav = document.querySelector('.kreta-nav');
if (!navToggle || !nav) {
return;
}
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');
}
});
const navItems = document.querySelectorAll('.nav-item');
navItems.forEach(item => {
item.addEventListener('click', () => {
nav.classList.remove('show');
});
});
}, 100);
}
document.addEventListener('DOMContentLoaded', () => {
updateHeaderInfo();
setupUserDropdown();
setupSettingsButton();
setupMobileNavigation();
});

View File

@@ -1,87 +1,69 @@
(() => {
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`;
}
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 setTheme(theme) {
try {
const actualTheme = theme === 'default' ? 'light-blue' : theme;
document.documentElement.setAttribute('data-theme', actualTheme);
setCookie('themePreference', actualTheme);
cookieManager.set('themePreference', actualTheme);
localStorage.setItem('themePreference', actualTheme);
chrome.runtime.sendMessage({
action: 'themeChanged',
theme: actualTheme
}).catch(() => {
console.log('Extension context not available for theme sync');
});
console.log('Theme set to:', actualTheme);
} 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 initializeTheme() {
const cookieTheme = getCookie('themePreference');
const cookieTheme = cookieManager.get('themePreference');
const localStorageTheme = localStorage.getItem('themePreference');
const theme = cookieTheme || localStorageTheme || 'light-blue';
const theme = cookieTheme || localStorageTheme || 'light-green';
setTheme(theme);
setPageTitleAndFavicon();
if (cookieTheme !== localStorageTheme) {
if (cookieTheme) {
localStorage.setItem('themePreference', cookieTheme);
} else if (localStorageTheme) {
setCookie('themePreference', localStorageTheme);
cookieManager.set('themePreference', localStorageTheme);
}
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
initializeTheme();
});
initializeTheme();
document.addEventListener('DOMContentLoaded', initializeTheme);
} else {
initializeTheme();
}
@@ -93,35 +75,58 @@
}
if (message.action === 'getTheme') {
const currentTheme = document.documentElement.getAttribute('data-theme') || 'light-blue';
const currentTheme = document.documentElement.getAttribute('data-theme') || 'light-green';
sendResponse({ theme: currentTheme });
}
return true;
});
let titleCheckTimeout;
const observer = new MutationObserver((mutations) => {
const currentTheme = document.documentElement.getAttribute('data-theme');
const savedTheme = getCookie('themePreference') || localStorage.getItem('themePreference');
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);
}
});
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
});
}
})();

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,28 +1,3 @@
@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;
}
* {
box-sizing: border-box;
margin: 0;
@@ -67,10 +42,10 @@ body {
@media (max-width: 768px) {
.kreta-header {
grid-template-columns: 1fr auto;
grid-template-columns: 1fr auto auto;
grid-template-areas:
"school user"
"nav nav";
"school toggle user"
"nav nav nav";
padding: 1rem;
gap: 0.5rem;
}
@@ -135,77 +110,6 @@ body {
}
}
.kreta-nav {
padding: 0 clamp(0.5rem, 3vw, 1.5rem);
position: sticky;
top: 0;
z-index: 100;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
-ms-overflow-style: none;
display: flex;
justify-content: center;
}
@media (max-width: 768px) {
.kreta-nav {
grid-area: nav;
padding: 0;
margin-top: 0.5rem;
}
}
.nav-links {
display: flex;
gap: clamp(0.5rem, 2vw, 1rem);
padding: 0.25rem;
justify-content: center;
}
@media (max-width: 768px) {
.nav-links {
justify-content: flex-start;
width: 100%;
gap: 0.25rem;
}
}
.nav-links a {
color: var(--text-secondary);
text-decoration: none;
padding: clamp(0.5rem, 1.5vw, 1rem) 0.5rem;
font-weight: 500;
white-space: nowrap;
transition: all 0.2s ease;
display: flex;
align-items: center;
gap: 0.5rem;
border-radius: 8px;
}
@media (max-width: 768px) {
.nav-links a {
padding: 0.5rem;
font-size: 13px;
}
.nav-links a .material-icons-round {
font-size: 20px;
}
}
.nav-links a:hover {
color: var(--text-primary);
background-color: var(--card-card);
}
.nav-links a.active {
color: var(--accent-accent);
}
.user-profile {
position: relative;
justify-self: flex-end;
@@ -235,31 +139,22 @@ body {
gap: 0.25rem;
}
.user-name {
font-weight: 600;
font-size: 14px;
}
.nav-logout-timer {
font-size: 12px;
color: var(--text-secondary);
}
.user-dropdown {
position: absolute;
top: 100%;
right: 0;
margin-top: 0.5rem;
background: var(--card-card);
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
min-width: 200px;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
width: 200px;
display: none;
z-index: 1000;
overflow: hidden;
}
.user-dropdown.show {
display: block;
animation: dropdownShow 0.2s ease;
}
.dropdown-item {
@@ -289,13 +184,13 @@ body {
.filter-card {
background: var(--card-card);
border-radius: 24px;
padding: 1.5rem;
margin-bottom: 1.5rem;
box-shadow: 0px 1px 3px 0px var(--accent-shadow);
padding: 20px;
margin-bottom: 24px;
box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow);
}
.filter-header {
margin-bottom: 1rem;
margin-bottom: 16px;
}
.filter-header h2 {
@@ -307,43 +202,40 @@ body {
.filter-content {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 1rem;
width: 100%;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 16px;
}
.filter-group {
display: flex;
flex-direction: column;
gap: 0.5rem;
gap: 8px;
}
.filter-group label {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 14px;
gap: 8px;
color: var(--text-secondary);
font-size: 14px;
}
.filter-group select,
.filter-group input {
padding: 0.75rem;
border-radius: 12px;
border: 1px solid var(--accent-15);
background-color: var(--background);
padding: 10px;
border: none;
border-radius: 8px;
background: var(--button-secondaryFill);
color: var(--text-primary);
font-family: inherit;
font-size: 14px;
width: 100%;
transition: border-color 0.2s ease, box-shadow 0.2s ease;
transition: all 0.2s ease;
}
.filter-group select:focus,
.filter-group input:focus {
outline: none;
border-color: var(--accent-accent);
box-shadow: 0 0 0 2px var(--accent-15);
box-shadow: 0 0 0 2px var(--accent-accent);
}
.filter-actions {
@@ -379,134 +271,116 @@ body {
.homework-list {
display: grid;
grid-template-columns: 1fr;
gap: 1rem;
display: flex;
flex-direction: column;
gap: 16px;
}
.homework-date-group {
margin-bottom: 2rem;
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: 0.5rem;
margin-bottom: 0.5rem;
padding-bottom: 0.5rem;
border-bottom: 1px solid var(--accent-15);
gap: 8px;
}
.homework-count {
margin-left: auto;
background: var(--accent-accent);
color: var(--button-secondaryFill);
padding: 4px 8px;
border-radius: 12px;
font-size: 14px;
}
.homework-list-items {
padding: 16px;
display: flex;
flex-direction: column;
gap: 12px;
}
.date-header h3 {
font-size: 16px;
font-weight: 600;
color: var(--text-primary);
margin: 0;
}
.homework-item {
background: var(--card-card);
display: flex;
flex-direction: column;
gap: 8px;
padding: 12px;
margin: 0 16px 12px 16px;
background: var(--accent-15);
border-radius: 12px;
padding: 1rem;
margin-bottom: 0.5rem;
box-shadow: 0px 1px 2px 0px var(--accent-shadow);
transition: transform 0.2s ease;
}
.homework-item:hover {
transform: translateY(-2px);
transform: translateX(4px);
}
.homework-item.due-tomorrow {
border-left: 4px solid var(--accent-accent);
background-color: var(--accent-5);
background: var(--accent-accent);
color: white;
}
.homework-header {
.homework-item.due-tomorrow .homework-subject,
.homework-item.due-tomorrow .homework-content,
.homework-item.due-tomorrow .homework-teacher {
color: white;
}
.homework-details {
display: flex;
justify-content: space-between;
margin-bottom: 0.5rem;
flex-direction: column;
gap: 4px;
}
.homework-subject {
font-weight: 600;
font-size: 16px;
color: var(--text-primary);
}
.homework-deadline {
font-size: 14px;
color: var(--text-secondary);
}
.homework-deadline.urgent {
color: var(--accent-accent);
font-weight: 500;
margin-bottom: 4px;
}
.homework-content {
margin-bottom: 0.5rem;
color: var(--text-primary);
font-size: 14px;
}
.homework-footer {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 12px;
color: var(--text-secondary);
margin-bottom: 8px;
line-height: 1.4;
word-wrap: break-word;
overflow-wrap: break-word;
white-space: pre-wrap;
}
.homework-teacher {
color: var(--text-secondary);
font-size: 12px;
font-style: italic;
}
.loading-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.7);
display: flex;
justify-content: center;
align-items: center;
z-index: 9999;
}
.loading-container {
background-color: var(--background);
padding: 2rem;
border-radius: 16px;
text-align: center;
max-width: 90%;
width: 300px;
}
.loading-logo {
width: 80px;
margin-bottom: 1rem;
}
.loading-text {
font-size: 18px;
font-weight: 600;
margin-bottom: 0.5rem;
color: var(--text-primary);
}
.loading-text2 {
font-size: 14px;
color: var(--text-secondary);
}
.empty-state {
text-align: center;
padding: 2rem;
color: var(--text-secondary);
display: none;
background: var(--card-card);
border-radius: 24px;
box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow);
}
.empty-state p {
@@ -524,4 +398,48 @@ body {
flex-direction: column;
gap: 0.25rem;
}
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes dropdownShow {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@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,89 +1,63 @@
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 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 function 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));
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',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
});
if (!response.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);
return { Data: [], Total: 0 };
}
}
async function collectHomeworkData() {
await waitForElement('#TanulotHaziFeladatkGrid');
await new Promise(resolve => setTimeout(resolve, 1000));
const apiData = await fetchHomeworkData();
const basicData = {
schoolInfo: {
name: getCookie('schoolName') || 'Iskola',
id: getCookie('schoolCode') || ''
name: cookieManager.get('schoolName') || 'Iskola',
id: cookieManager.get('schoolCode') || ''
},
userData: {
name: getCookie('userName') || 'Felhasználó',
name: cookieManager.get('userName') || 'Felhasználó',
time: document.querySelector('.usermenu_timer')?.textContent?.trim() || '45:00'
}
};
const homeworkItems = [];
const rows = document.querySelectorAll('#TanulotHaziFeladatkGrid .k-grid-content tr');
rows.forEach(row => {
const cells = row.querySelectorAll('td');
if (cells.length >= 7) {
homeworkItems.push({
subject: cells[3]?.textContent?.trim() || '',
teacher: cells[4]?.textContent?.trim() || '',
description: cells[5]?.textContent?.trim() || '',
createdDate: cells[6]?.textContent?.trim() || '',
deadline: cells[7]?.textContent?.trim() || ''
});
}
});
if (apiData.Data && Array.isArray(apiData.Data)) {
apiData.Data.forEach(item => {
homeworkItems.push({
id: item.ID,
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 || ''
});
});
}
const groupedHomework = {};
homeworkItems.forEach(homework => {
const deadlineDate = homework.deadline.split(' ').slice(0, 3).join(' ');
const deadlineDate = homework.deadline.split(' ')[0];
if (!groupedHomework[deadlineDate]) {
groupedHomework[deadlineDate] = [];
}
@@ -93,26 +67,28 @@ async function collectHomeworkData() {
return { basicData, homeworkItems, groupedHomework };
}
function showLoadingScreen() {
const loadingHTML = `
<div class="loading-overlay">
<div class="loading-container">
<img src="${chrome.runtime.getURL('images/firka_logo.png')}" alt="Firka" class="loading-logo">
<div class="loading-text">Betöltés alatt...</div>
<p class="loading-text2">Kis türelmet</p>
</div>
</div>
`;
function formatApiDate(dateString) {
if (!dateString) return '';
document.body.insertAdjacentHTML('beforeend', loadingHTML);
}
function hideLoadingScreen() {
const loadingOverlay = document.querySelector('.loading-overlay');
if (loadingOverlay) {
loadingOverlay.style.opacity = '0';
loadingOverlay.style.transition = 'opacity 0.3s ease';
setTimeout(() => loadingOverlay.remove(), 300);
try {
const date = new Date(dateString);
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')
];
const dayName = dayNames[date.getDay()];
return `${month}.${day}. (${dayName})`;
} catch (error) {
return dateString;
}
}
@@ -124,7 +100,7 @@ function isTomorrow(dateStr) {
if (parts.length < 3) return false;
const year = parseInt(parts[0].trim());
const month = parseInt(parts[1].trim()) - 1; // JS months are 0-indexed
const month = parseInt(parts[1].trim()) - 1;
const day = parseInt(parts[2].trim());
const homeworkDate = new Date(year, month, day);
@@ -143,88 +119,25 @@ function isTomorrow(dateStr) {
}
async function transformHomeworkPage() {
showLoadingScreen();
const { basicData, homeworkItems, groupedHomework } = await collectHomeworkData();
const schoolNameFull = `${basicData.schoolInfo.id} - ${basicData.schoolInfo.name}`;
const shortenedSchoolName = shortenSchoolName(schoolNameFull);
document.body.innerHTML = `
<div class="kreta-container">
<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">
Firka
</p>
<div class="school-details" title="${schoolNameFull}">
${shortenedSchoolName}
</div>
</div>
<nav class="kreta-nav">
<div class="nav-links">
<a href="/Intezmeny/Faliujsag" data-page="dashboard" class="nav-item">
<img src="${chrome.runtime.getURL('icons/dashboard-inactive.svg')}" alt="Kezdőlap">
Kezdőlap
</a>
<a href="/TanuloErtekeles/Osztalyzatok" data-page="grades" class="nav-item">
<img src="${chrome.runtime.getURL('icons/grades-inactive.svg')}" alt="Jegyek">
Jegyek
</a>
<a href="/Orarend/InformaciokOrarend" data-page="timetable" class="nav-item">
<img src="${chrome.runtime.getURL('icons/timetable-inactive.svg')}" alt="Órarend">
Órarend
</a>
<a href="/Hianyzas/Hianyzasok" data-page="absences" class="nav-item">
<img src="${chrome.runtime.getURL('icons/absences-inactive.svg')}" alt="Mulasztások">
Mulasztások
</a>
<a href="/Tanulo/TanuloHaziFeladat" data-page="other" class="nav-item active">
<img src="${chrome.runtime.getURL('icons/others.svg')}" alt="Egyéb">
Egyéb
</a>
</div>
</nav>
<div class="user-profile">
<button class="user-dropdown-btn">
<div class="user-info">
<span class="user-name">${basicData.userData.name}</span>
<span class="nav-logout-timer" id="logoutTimer">${basicData.userData.time}</span>
</div>
</button>
<div class="user-dropdown">
<a href="/Adminisztracio/Profil" data-page="profile" class="dropdown-item">
<img src="${chrome.runtime.getURL('icons/profile.svg')}" alt="Profil">
Profil
</a>
<a href="#" class="dropdown-item" id="settingsBtn">
<img src="${chrome.runtime.getURL('icons/settings.svg')}" alt="Beállítások">
Beállítások
</a>
<a href="/Home/Logout" data-page="logout" class="dropdown-item">
<img src="${chrome.runtime.getURL('icons/logout.svg')}" alt="Kijelentkezés">
Kijelentkezés
</a>
</div>
</div>
</header>
${createTemplate.header()}
<main class="kreta-main">
<div class="filter-card">
<div class="filter-header">
<h2>Szűrés</h2>
<h2>${LanguageManager.t('homework.filter_title')}</h2>
</div>
<div class="filter-content">
<div class="filter-group">
<label>
<!--<span class="material-icons-round">subject</span>-->
Tantárgy
${LanguageManager.t('homework.subject')}
</label>
<select id="subjectFilter">
<option value="">Összes tantárgy</option>
<option value="">${LanguageManager.t('homework.all_subjects')}</option>
${[...new Set(homeworkItems.map(item => item.subject))]
.sort()
.map(subject => `<option value="${subject}">${subject}</option>`)
@@ -234,10 +147,10 @@ async function transformHomeworkPage() {
<div class="filter-group">
<label>
<!--<span class="material-icons-round">person</span>-->
Tanár
${LanguageManager.t('homework.teacher')}
</label>
<select id="teacherFilter">
<option value="">Összes tanár</option>
<option value="">${LanguageManager.t('homework.all_teachers')}</option>
${[...new Set(homeworkItems.map(item => item.teacher))]
.sort()
.map(teacher => `<option value="${teacher}">${teacher}</option>`)
@@ -247,13 +160,13 @@ async function transformHomeworkPage() {
<div class="filter-group">
<label>
<!--<span class="material-icons-round">date_range</span>-->
Határidő
${LanguageManager.t('homework.due_date')}
</label>
<select id="deadlineFilter">
<option value="">Összes határidő</option>
<option value="tomorrow">Holnapi határidő</option>
<option value="thisWeek">Ezen a héten</option>
<option value="nextWeek">Jövő héten</option>
<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>
@@ -268,22 +181,36 @@ async function transformHomeworkPage() {
setupFilters(homeworkItems, groupedHomework);
setupUserDropdown();
setupLogoutTimer();
hideLoadingScreen();
setupMobileNavigation();
loadingScreen.hide();
}
function renderHomeworkList(groupedHomework) {
const sortedDates = Object.keys(groupedHomework).sort((a, b) => {
const dateA = new Date(a.replace(/\./g, ''));
const dateB = new Date(b.replace(/\./g, ''));
return dateA - dateB;
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;
});
if (sortedDates.length === 0) {
return `
<div class="empty-state">
<p>Nincs megjeleníthető házi feladat.</p>
<p>${LanguageManager.t('homework.no_homework')}</p>
</div>
`;
}
@@ -294,24 +221,24 @@ function renderHomeworkList(groupedHomework) {
<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>
${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-header">
<div class="homework-subject">${homework.subject}</div>
<div class="homework-deadline ${urgentClass}">${formatDeadline(homework.deadline)}</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>
<div class="homework-content">${formatHomeworkDescription(homework.description)}</div>
<div class="homework-footer">
<div class="homework-teacher">${homework.teacher}</div>
</div>
</div>
`;
}).join('')}
`;
}).join('')}
</div>
</div>
`;
}).join('');
@@ -327,58 +254,37 @@ function formatDateHeader(dateStr) {
tomorrow.setDate(tomorrow.getDate() + 1);
const parts = dateStr.split('.');
if (parts.length < 3) return dateStr;
if (parts.length < 2) return dateStr;
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 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 '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}`;
}
function formatDeadline(dateStr) {
if (!dateStr) return '';
if (isTomorrow(dateStr)) {
return `Határidő: ${dateStr} (holnap!)`;
}
return `Határidő: ${dateStr}`;
}
function formatDate(dateStr) {
if (!dateStr) return '';
return dateStr;
}
function formatHomeworkDescription(description) {
if (!description) return '';
description = description.replace(/(\d+\.)\s*(\w[^\n.]*)/g, '<strong>$1 $2</strong>');
description = description.replace(/(Határidő:)\s*([^\n]+)/g, '<div class="homework-requirement"><span class="requirement-label">$1</span> $2</div>');
description = description.replace(/(MS\s+[^\n.]+szerint\s+adható\s+be\.)/g, '<div class="homework-requirement"><span class="requirement-label">Beadás:</span> $1</div>');
description = description.replace(/\n/g, '<br>');
return description;
}
function setupFilters(homeworkItems, groupedHomework) {
const subjectFilter = document.getElementById('subjectFilter');
const teacherFilter = document.getElementById('teacherFilter');
@@ -437,11 +343,11 @@ function setupFilters(homeworkItems, groupedHomework) {
const startOfWeek = new Date(today);
const dayOfWeek = today.getDay() || 7; // Convert Sunday from 0 to 7
startOfWeek.setDate(today.getDate() - dayOfWeek + 1); // Monday
const dayOfWeek = today.getDay() || 7;
startOfWeek.setDate(today.getDate() - dayOfWeek + 1);
const endOfWeek = new Date(startOfWeek);
endOfWeek.setDate(startOfWeek.getDate() + 6); // Sunday
endOfWeek.setDate(startOfWeek.getDate() + 6);
const startOfNextWeek = new Date(endOfWeek);
@@ -478,7 +384,7 @@ function setupFilters(homeworkItems, groupedHomework) {
if (!emptyState) {
emptyState = document.createElement('div');
emptyState.className = 'empty-state';
emptyState.innerHTML = '<p>Nincs a szűrési feltételeknek megfelelő házi feladat.</p>';
emptyState.innerHTML = `<p>${LanguageManager.t('homework.no_matching_homework')}</p>`;
homeworkList.appendChild(emptyState);
}
@@ -519,50 +425,6 @@ function setupFilters(homeworkItems, groupedHomework) {
deadlineFilter.addEventListener('change', applyFilters);
}
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');
});
document.addEventListener('click', () => {
userDropdown?.classList.remove('show');
});
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 setupLogoutTimer() {
const timerElement = document.querySelector('.nav-logout-timer');
if (!timerElement) return;
const timeString = timerElement.textContent;
const startTime = parseInt(timeString?.match(/\d+/)?.[0] || "45");
let timeLeft = startTime * 60;
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);
}
if (window.location.href.includes('/Tanulo/TanuloHaziFeladat')) {

343
i18n/en.json Normal file
View File

@@ -0,0 +1,343 @@
{
"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",
"messages": "Messages",
"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.",
"items": "items"
},
"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",
"time_period": "Time period",
"all_periods": "All periods",
"current_month": "Current month",
"last_month": "Last month",
"current_semester": "Current semester",
"last_30_days": "Last 30 days"
},
"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"
},
"forgotpassword": {
"title": "Forgot Password",
"om_id_label": "OM ID",
"om_id_placeholder": "Enter your OM ID",
"om_id_required": "OM ID is required",
"email_label": "Email address",
"email_placeholder": "Enter your email address",
"email_required": "Email address is required",
"back_to_login": "Back to login",
"reset_button": "Reset password",
"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",
"recaptcha_required": "Please complete the reCAPTCHA"
}
}

343
i18n/hu.json Normal file
View File

@@ -0,0 +1,343 @@
{
"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",
"messages": "Üzenetek",
"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.",
"items": "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",
"time_period": "Időszak",
"all_periods": "Összes időszak",
"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"
},
"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"
},
"forgotpassword": {
"title": "Elfelejtett jelszó",
"om_id_label": "OM azonosító",
"om_id_placeholder": "Adja meg az OM azonosítóját",
"om_id_required": "Az OM azonosító megadása kötelező",
"email_label": "E-mail cím",
"email_placeholder": "Adja meg az e-mail címét",
"email_required": "Az e-mail cím megadása kötelező",
"back_to_login": "Vissza a bejelentkezéshez",
"reset_button": "Jelszó visszaállítása",
"error_message": "Hiba történt a jelszó visszaállítása során",
"success_message": "A jelszó visszaállítási link elküldve az e-mail címére",
"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"
}
}

1
icons/messages.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><g fill="none"><path fill-rule="evenodd" clip-rule="evenodd" d="M6 21a3 3 0 0 1-3-3v-3h5a2 2 0 0 0 2 2h4a2 2 0 0 0 2-2h5v3a3 3 0 0 1-3 3H6zm15-8h-5a2 2 0 0 0-2 2h-4a2 2 0 0 0-2-2H3V6a3 3 0 0 1 3-3h12a3 3 0 0 1 3 3v7z" fill="#A7DC22"/></g></svg>

After

Width:  |  Height:  |  Size: 327 B

BIN
images/cactus.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
images/chrome.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
images/firefox.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View File

@@ -1,28 +1,3 @@
@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;
}
:root {
--icon-invert: 0.1;
--icon-sepia: 0.1;

View File

@@ -1,21 +1,20 @@
async function transformLoginPage() {
try {
if (document.readyState !== 'complete') {
await new Promise(resolve => {
window.addEventListener('load', resolve);
});
}
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 || ''
requestToken: document.querySelector('input[name="__RequestVerificationToken"]')?.value || '',
userName: document.querySelector('#UserName')?.value || '',
password: document.querySelector('#Password')?.value || ''
};
const titleElement = document.querySelector('.page-title');
const schoolInfo = {
@@ -23,19 +22,16 @@ async function transformLoginPage() {
kretaId: '',
omCode: ''
};
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('KRÉTA azonosító: ', '');
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 newHTML = `
<div class="login-container">
@@ -48,7 +44,7 @@ async function transformLoginPage() {
<h1 class="school-name">${schoolInfo.name}</h1>
<div class="school-details">
${schoolInfo.kretaId ? `<div>${schoolInfo.kretaId}</div>` : ''}
${schoolInfo.omCode ? `<div>KRÉTA azonosító: ${schoolInfo.omCode}</div>` : ''}
${schoolInfo.omCode ? `<div>${LanguageManager.t('login.kreta_id')}: ${schoolInfo.omCode}</div>` : ''}
</div>
</div>
@@ -61,27 +57,27 @@ async function transformLoginPage() {
<div class="form-group">
<input class="form-control" type="text" id="UserName" name="UserName"
placeholder="Felhasználónév" maxlength="256" autocomplete="username" required>
<div class="error-message">Kérjük, add meg a felhasználóneved.</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="Jelszó" maxlength="256" autocomplete="current-password" required>
<button type="button" class="show-password" aria-label="Jelszó mutatása">
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">Kérjük, add meg a jelszavad.</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">Bejelentkezés</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">Elfelejtettem a jelszavam</a>
<a href="https://tudasbazis.ekreta.hu/pages/viewpage.action?pageId=2425086" target="_blank" class="help-link">Nem tudsz bejelentkezni?</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>
@@ -89,21 +85,19 @@ async function transformLoginPage() {
${systemMessage ? `
<div class="system-message">
<h4>Rendszerértesítés</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">Adatkezelési tájékoztató</a>
target="_blank" class="privacy-link">${LanguageManager.t('login.privacy_policy')}</a>
</footer>
</div>
`;
document.body.innerHTML = newHTML;
setupEventListeners();
@@ -117,7 +111,6 @@ function setupEventListeners() {
const passwordInput = document.getElementById('Password');
const togglePasswordBtn = document.querySelector('.show-password');
const formInputs = document.querySelectorAll('.form-control');
if (togglePasswordBtn && passwordInput) {
togglePasswordBtn.addEventListener('click', () => {
@@ -175,11 +168,6 @@ function handleSubmit(event) {
isValid = false;
}
});
if (!isValid) {
return;
}
const submitButton = form.querySelector('.btn-login');
const spinner = submitButton.querySelector('.spinner');

301
login/twofactor.css Normal file
View File

@@ -0,0 +1,301 @@
:root {
--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;
}
:root[data-theme="dark-blue"] {
--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;
}
* {
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;
}
.login-container {
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);
}
.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;
}
.logo-text {
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;
}
.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;
}
.twofactor-form {
width: 100%;
}
.form-group {
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;
}
.form-control:focus {
outline: none;
border-color: var(--accent-accent) !important;
}
.form-control::placeholder {
color: var(--text-secondary) !important;
}
.password-group {
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;
}
.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));
}
.show-password:hover .icon-eye {
opacity: 1;
}
.form-check {
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;
}
.form-check-input:checked {
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;
}
.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;
}
.btn-kreta:hover {
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;
}
.btn-link:hover {
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;
}
.login-footer {
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;
}
.privacy-link:hover {
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;
}
.error-message.show {
display: block;
}
.form-control.error {
border: 1px solid var(--error-accent) !important;
}
/* Hide original elements */
header, main > .container-fluid, footer {
display: none !important;
}
/* Responsive adjustments */
@media (max-width: 576px) {
.login-container {
width: 100%;
padding: 16px;
}
.login-card {
padding: 16px;
}
}

171
login/twofactor.js Normal file
View File

@@ -0,0 +1,171 @@
async function transformTwoFactorPage() {
try {
if (document.readyState !== 'complete') {
await new Promise(resolve => {
window.addEventListener('load', resolve);
});
}
if (typeof loadingScreen !== 'undefined') {
loadingScreen.show();
}
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'
};
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">
Firka
</p>
<h1 class="twofactor-title">${LanguageManager.t('twofactor.title')}</h1>
</div>
<form class="twofactor-form" action="${formData.action}" method="post" id="twoFactorForm">
<input type="hidden" id="ClientId" name="ClientId" value="${formData.clientId}">
<input type="hidden" id="RememberLogin" name="RememberLogin" value="${formData.rememberLogin}">
<input type="hidden" id="ReturnUrl" name="ReturnUrl" value="${formData.returnUrl}">
<input type="hidden" id="IsRecoveryCode" name="IsRecoveryCode" value="${formData.isRecoveryCode}">
<input name="__RequestVerificationToken" type="hidden" value="${formData.requestToken}">
<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">
</button>
<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')}
</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>
</div>
<div class="d-flex justify-content-center mt-3">
<span class="subtext">
${LanguageManager.t('twofactor.no_access')}
<button type="submit" class="btn-link" formaction="/account/loginwithrecoverycode">
${LanguageManager.t('twofactor.recovery_code')}
</button>
</span>
</div>
</form>
</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>
</footer>
</div>
`;
document.body.innerHTML = newHTML;
applyTheme();
setupEventListeners();
if (typeof loadingScreen !== 'undefined') {
loadingScreen.hide();
}
} catch (error) {
console.error('Error transforming two-factor page:', error);
if (typeof loadingScreen !== 'undefined') {
loadingScreen.hide();
}
}
}
function applyTheme() {
try {
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');
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`);
});
}
formInputs.forEach(input => {
input.addEventListener('input', () => {
validateInput(input);
});
input.addEventListener('blur', () => {
validateInput(input, true);
});
});
if (twoFactorForm) {
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');
} else {
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]');
let isValid = true;
inputs.forEach(input => {
if (!validateInput(input, true)) {
isValid = false;
}
});
if (isValid) {
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>`;
}
form.submit();
}
}
transformTwoFactorPage();

View File

@@ -1,21 +1,4 @@
(() => {
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 loadFonts() {
// Create a new style element
const style = document.createElement('style');
@@ -27,8 +10,8 @@
}
function transformLogoutPage() {
// Get current theme and school ID from cookies
const theme = getCookie('themePreference') || localStorage.getItem('themePreference') || 'light-blue';
const instituteCode = getCookie('schoolSubdomain');
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

View File

@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "Firxa",
"version": "1.1.0",
"version": "1.2.3",
"description": "KRÉTA webes verziójának újraírása",
"icons": {
"128": "images/firka_logo_128.png"
@@ -12,80 +12,75 @@
"128": "images/firka_logo_128.png"
}
},
"browser_specific_settings": {
"gecko": {
"id": "firxa@zan1456.hu",
"strict_min_version": "58.0"
}
},
"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/*"]
"matches": ["<all_urls>"]
}],
"content_scripts": [
{
"matches": [
"https://*.e-kreta.hu/*"
],
"js": ["global/maintenance.js", "global/theme.js", "global/navigation.js"],
"css": ["global/theme.css", "global/navigation.css"],
"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"],
"run_at": "document_start"
},
{
"matches": [
"https://*.e-kreta.hu/*"
],
"css": ["global/maintenance.css"],
"run_at": "document_end"
},
{
"matches": ["https://idp.e-kreta.hu/Account/Login*"],
"js": ["login/login.js"],
"css": ["login/login.css"]
},
{
"matches": [
"https://*.e-kreta.hu/Hianyzas/Hianyzasok*"
],
"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*"
],
"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*"
],
"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*"
],
"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*"
],
"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://*.e-kreta.hu/TanuloErtekeles/Osztalyzatok*"
],
"js": ["grades/grades.js", "grades/chart.js"],
"css": ["grades/grades.css"],
@@ -114,6 +109,14 @@
"js": ["homework/homework.js"],
"css": ["homework/homework.css"],
"run_at": "document_end"
},
{
"matches": [
"https://intezmenykereso.e-kreta.hu/"
],
"js": ["search/search.js"],
"css": ["search/search.css"],
"run_at": "document_end"
}
]
}

View File

@@ -59,37 +59,6 @@ body {
max-width: 300px;
}
.nav-links {
display: flex;
gap: clamp(0.5rem, 2vw, 1rem);
padding: 0.25rem;
justify-content: center;
}
.nav-links a {
color: var(--text-secondary);
text-decoration: none;
padding: clamp(0.5rem, 1.5vw, 1rem) 0.5rem;
font-weight: 500;
white-space: nowrap;
transition: all 0.2s ease;
display: flex;
align-items: center;
gap: 0.5rem;
border-radius: 8px;
}
.nav-links a:hover {
color: var(--text-primary);
background-color: var(--card-card);
}
.nav-links a.active {
color: var(--accent-accent);
}
.user-profile {
position: relative;
justify-self: flex-end;
@@ -115,19 +84,6 @@ body {
text-align: right;
}
.user-name {
display: block;
color: var(--text-primary);
font-size: 16px;
font-weight: 500;
}
.user-time {
display: block;
color: var(--text-secondary);
font-size: 14px;
}
.user-dropdown {
position: absolute;
top: 100%;
@@ -426,10 +382,10 @@ body {
@media (max-width: 768px) {
.kreta-header {
grid-template-columns: 1fr auto;
grid-template-columns: 1fr auto auto;
grid-template-areas:
"school user"
"nav nav";
"school toggle user"
"nav nav nav";
padding: 1rem;
gap: 0.5rem;
}
@@ -438,12 +394,6 @@ body {
grid-area: school;
}
.nav-links {
grid-area: nav;
margin-top: 0.5rem;
justify-content: flex-start;
}
.user-profile {
grid-area: user;
}

View File

@@ -1,34 +1,4 @@
(() => {
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 shortenSchoolName(name) {
if (!name) return '';
const maxLength = 30;
if (name.length <= maxLength) return name;
const parts = name.split(' - ');
if (parts.length === 2) {
const [code, fullName] = parts;
return `${code} - ${fullName.substring(0, maxLength - code.length - 5)}...`;
}
return name.substring(0, maxLength - 3) + '...';
}
(() => {
function createSecurityTab() {
return `
<div class="security-content">
@@ -196,25 +166,25 @@
const saveButton = form.querySelector('#saveContacts');
emailInput.value = getCookie('userEmail') || '';
phoneInput.value = getCookie('userPhone') || '';
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('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;
}
@@ -229,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'));
}
});
}
@@ -289,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'));
}
});
@@ -306,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;
}
@@ -335,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'));
}
});
@@ -371,67 +341,10 @@
}
}
function createProfileHTML(data) {
const schoolNameFull = `${data.schoolInfo.id} - ${data.schoolInfo.name}`;
const shortenedSchoolName = shortenSchoolName(schoolNameFull);
function createProfileHTML() {
return `
<div class="kreta-container">
<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">
Firka
</p>
<div class="school-details" title="${schoolNameFull}">
${shortenedSchoolName}
</div>
</div>
<nav class="kreta-nav">
<div class="nav-links">
<a href="/Intezmeny/Faliujsag">
<span class="material-icons-round">calendar_today</span>
Kezdőlap
</a>
<a href="/TanuloErtekeles/Osztalyzatok">
<span class="material-icons-round">bookmark_border</span>
Jegyek
</a>
<a href="/Orarend/InformaciokOrarend">
<span class="material-icons-round">home</span>
Órarend
</a>
<a href="/Hianyzas/Hianyzasok">
<span class="material-icons-round">schedule</span>
Hiányok
</a>
</div>
</nav>
<div class="user-profile">
<button class="user-dropdown-btn">
<div class="user-info">
<span class="user-name">${data.userData.name}</span>
<span class="user-time" id="logoutTimer">${data.userData.time}</span>
</div>
</button>
<div class="user-dropdown">
<a href="/Adminisztracio/Profil" class="dropdown-item">
<span class="material-icons-round">person</span>
Profil
</a>
<a href="#" class="dropdown-item" id="settingsBtn">
<span class="material-icons-round">settings</span>
Beállítások
</a>
<a href="/Home/Logout" class="dropdown-item">
<span class="material-icons-round">logout</span>
Kijelentkezés
</a>
</div>
</div>
</header>
${createTemplate.header()}
<main class="kreta-main">
<div class="card">
@@ -469,34 +382,11 @@
async function init() {
if (window.location.pathname.includes('/Adminisztracio/Profil')) {
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/icon?family=Material+Icons+Round' }
];
createTemplate.importFonts();
links.forEach(link => {
const linkElement = document.createElement('link');
Object.entries(link).forEach(([key, value]) => {
linkElement[key] = value;
});
document.head.appendChild(linkElement);
});
const userData = {
schoolInfo: {
name: getCookie('schoolName') || 'Iskola',
id: getCookie('schoolCode') || ''
},
userData: {
name: getCookie('userName') || 'Felhasználó',
time: document.querySelector('.usermenu_timer')?.textContent?.trim() || '45:00',
email: getCookie('userEmail') || ''
}
};
document.body.innerHTML = createProfileHTML(userData);
document.body.innerHTML = createProfileHTML();
setupUserDropdown();
setupMobileNavigation();
setupEventListeners();
setupContactForm();
}

View File

@@ -1,29 +1,3 @@
@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;
}
* {
box-sizing: border-box;
margin: 0;

View File

@@ -1,11 +1,4 @@
(() => {
const setCookie = (name, value, days = 365) => {
const date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
document.cookie = `${name}=${value}; expires=${date.toUTCString()}; path=/; domain=.e-kreta.hu`;
};
const startLogoutTimer = () => {
let timeLeft = 45 * 60;
const timerElement = document.getElementById('logoutTimer');
@@ -41,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'));
}
};
@@ -73,8 +66,8 @@
<img src="${chrome.runtime.getURL('icons/naplo.svg')}" alt="Napló ikon">
</div>
<div class="role-text">
Ellenőrzőkönyv
<div class="role-description">Jegyek, hiányzások, órarended és egyéb információk megtekintése.</div>
${LanguageManager.t('roleselect.student_book')}
<div class="role-description">${LanguageManager.t('roleselect.student_description')}</div>
</div>
</div>
</div>
@@ -85,8 +78,8 @@
<img src="${chrome.runtime.getURL('icons/dkt.svg')}" alt="DKT ikon">
</div>
<div class="role-text">
Digitális Kollaborációs Tér (DKT)
<div class="role-description">Osztálytermi kommunikáció és feladatok.</div>
${LanguageManager.t('roleselect.dkt_title')}
<div class="role-description">${LanguageManager.t('roleselect.dkt_description')}</div>
</div>
</div>
@@ -95,8 +88,8 @@
<img src="${chrome.runtime.getURL('icons/logout.svg')}" alt="Kijelentkezés ikon">
</div>
<div class="role-text">
Kijelentkezés
<div class="role-description">Kilépés a rendszerből</div>
${LanguageManager.t('roleselect.logout_title')}
<div class="role-description">${LanguageManager.t('roleselect.logout_description')}</div>
</div>
</div>
</div>
@@ -120,34 +113,22 @@
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) {
setCookie('schoolCode', schoolCode);
setCookie('schoolName', fullSchoolName);
setCookie('schoolSubdomain', schoolSubdomain);
cookieManager.set('schoolCode', schoolCode);
cookieManager.set('schoolName', fullSchoolName);
cookieManager.set('schoolSubdomain', schoolSubdomain);
}
if (userName) {
setCookie('userName', userName);
cookieManager.set('userName', userName);
}
document.body.innerHTML = createHTML(schoolCode, fullSchoolName, userName);
const links = [
{ rel: 'preconnect', href: 'https://fonts.googleapis.com' },
{ rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: true },
{ href: 'https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&family=Figtree:wght@300..900&display=swap', rel: 'stylesheet' }
];
links.forEach(link => {
const linkElement = document.createElement('link');
Object.entries(link).forEach(([key, value]) => linkElement[key] = value);
document.head.appendChild(linkElement);
});
createTemplate.importFonts();
const timerInterval = startLogoutTimer();

222
search/search.css Normal file
View File

@@ -0,0 +1,222 @@
/* Hide original elements */
header, footer, .page-title, .card-kreta {
display: none !important;
}
* {
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;
}
/* 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%);
}
/* 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);
}
.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;
}
.logo {
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;
}
/* 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);
}
/* Form styling */
form {
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;
}
.form-control:focus {
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;
}
/* 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;
}
.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;
}
li.dropdown-item:hover, li.dropdown-item:focus {
background-color: var(--accent-15) !important;
color: var(--text-primary) !important;
}
a.dropdown-item:hover, a.dropdown-item:focus {
background-color: #00000000 !important;
}
.dropdown-item.active {
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;
}
.btn-kreta:hover {
background-color: var(--accent-secondary) !important;
transform: translateY(-1px) !important;
}
.btn-kreta:active {
transform: translateY(1px) !important;
}
.btn-kreta:disabled {
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%;
}
.privacy-link {
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;
}
/* Responsive adjustments */
@media (max-width: 576px) {
.firka-search-wrapper {
width: 95%;
}
.search-title {
font-size: 20px;
}
.btn-kreta {
padding: 10px 20px !important;
font-size: 14px !important;
}
}

124
search/search.js Normal file
View File

@@ -0,0 +1,124 @@
function initializeTransformation() {
const form = document.querySelector('form');
const autocomplete = document.querySelector('.autocomplete');
if (form && autocomplete) {
applyFirkaStyling();
} else {
setTimeout(initializeTransformation, 500);
}
}
document.addEventListener('DOMContentLoaded', () => {
setTimeout(initializeTransformation, 1000);
});
if (document.readyState === 'complete' || document.readyState === 'interactive') {
setTimeout(initializeTransformation, 1000);
}
function applyFirkaStyling() {
try {
const theme = cookieManager.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');
if (existingWrapper) {
existingWrapper.remove();
}
searchWrapper.appendChild(firkaHeader);
if (originalForm) {
formContainer.appendChild(originalForm);
searchWrapper.appendChild(formContainer);
}
searchWrapper.appendChild(firkaFooter);
document.body.appendChild(searchWrapper);
setupAutocompleteListeners();
if (redirectButton) {
redirectButton.addEventListener('click', function(event) {
if (!instituteCodeInput.value) {
event.preventDefault();
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');
if (autocompleteInput && autocompleteValue) {
const observer = new MutationObserver((mutations) => {
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', () => {
if (redirectButton) {
redirectButton.disabled = false;
}
});
});
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
}
}
function observeAutocompleteValue(valueInput, button) {
if (!valueInput || !button) return;
const observer = new MutationObserver((mutations) => {
button.disabled = !valueInput.value;
});
observer.observe(valueInput, {
attributes: true,
attributeFilter: ['value']
});
const checkInterval = setInterval(() => {
if (valueInput.value) {
button.disabled = false;
clearInterval(checkInterval);
}
}, 500);
}

View File

@@ -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,31 @@ 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 {
color: var(--text-primary);
font-size: 12px;
font-weight: 500;
}
.theme-preview.light-blue {
background: #DAE4F7;

View File

@@ -3,7 +3,9 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Firxa Beállítások</title>
<title>Firxa - Beállítások</title>
<link rel="icon" type="image/png" href="../images/firka_logo_128.png">
<link rel="shortcut icon" type="image/png" href="../images/firka_logo_128.png">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap" rel="stylesheet">
@@ -21,12 +23,12 @@
</header>
<div class="settings-card">
<h2>Beállítások</h2>
<h2 data-i18n="settings.title">Beállítások</h2>
<div class="settings-group">
<div class="setting-section">
<div class="setting-header">
<span class="material-icons-round">palette</span>
Téma
<span data-i18n="settings.theme">Téma</span>
</div>
<div class="theme-grid">
<button class="theme-option" data-theme="default">
@@ -36,7 +38,7 @@
<div class="preview-card"></div>
</div>
</div>
<span class="theme-name">Világos Kék</span>
<span class="theme-name" data-i18n="settings.themes.light_blue">Világos Kék</span>
</button>
<button class="theme-option" data-theme="light-green">
<div class="theme-preview light-green">
@@ -45,7 +47,7 @@
<div class="preview-card"></div>
</div>
</div>
<span class="theme-name">Világos Zöld</span>
<span class="theme-name" data-i18n="settings.themes.light_green">Világos Zöld</span>
</button>
<button class="theme-option" data-theme="dark-blue">
<div class="theme-preview dark-blue">
@@ -54,7 +56,7 @@
<div class="preview-card"></div>
</div>
</div>
<span class="theme-name">Sötét Kék</span>
<span class="theme-name" data-i18n="settings.themes.dark_blue">Sötét Kék</span>
</button>
<button class="theme-option" data-theme="dark-green">
<div class="theme-preview dark-green">
@@ -63,7 +65,22 @@
<div class="preview-card"></div>
</div>
</div>
<span class="theme-name">Sötét Zöld</span>
<span class="theme-name" data-i18n="settings.themes.dark_green">Sötét Zöld</span>
</button>
</div>
</div>
<div class="setting-section">
<div class="setting-header">
<span class="material-icons-round">language</span>
<span data-i18n="settings.language">Nyelv</span>
</div>
<div class="language-grid">
<button class="language-option" data-language="hu">
<span class="language-name" data-i18n="settings.languages.hu">Magyar</span>
</button>
<button class="language-option" data-language="en">
<span class="language-name" data-i18n="settings.languages.en">English</span>
</button>
</div>
</div>
@@ -71,24 +88,24 @@
</div>
<div class="about-card">
<h2>Névjegy</h2>
<h2 data-i18n="settings.about.title">Névjegy</h2>
<div class="about-content">
<p>A Firka egy nyílt forráskódú projekt, amely a KRÉTA rendszerhez készít saját felhasználói felületet.</p>
<p data-i18n="settings.about.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.</p>
<a href="https://github.com/QwIT-Development/" target="_blank" class="github-link">
<span class="material-icons-round">code</span>
GitHub
<span data-i18n="settings.about.github">GitHub</span>
</a>
</div>
</div>
<div class="support-card">
<h2>Támogatás</h2>
<h2 data-i18n="settings.support.title">Támogatás</h2>
<div class="support-content">
<p>Ha tetszik a munkánk és szeretnéd támogatni a fejlesztést, az alábbi módon teheted meg:</p>
<p data-i18n="settings.support.description">Ha tetszik a munkánk és szeretnéd támogatni a fejlesztést, az alábbi módon teheted meg:</p>
<div class="support-buttons">
<a href="https://ko-fi.com/zan1456" target="_blank" class="support-button">
<span class="material-icons-round">coffee</span>
Ko-Fi
<span data-i18n="settings.support.kofi">Ko-Fi</span>
</a>
</div>
</div>
@@ -98,6 +115,8 @@
<div class="version-info" id="version">v1.1.0</div>
</footer>
</div>
<script src="index.js"></script>
<script src="../tools/cookieManager.js"></script>
<script src="../global/language.js"></script>
<script src="index.js"></script>
</body>
</html>

View File

@@ -1,4 +1,28 @@
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}=`;
@@ -25,43 +49,50 @@ document.addEventListener('DOMContentLoaded', async () => {
document.cookie = `${name}=${value}; ${expires}; path=/; domain=.e-kreta.hu`;
}
async function getCurrentTheme() {
try {
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
const response = await chrome.tabs.sendMessage(tab.id, { action: 'getTheme' });
return response.theme;
} catch (error) {
console.error('Error getting current theme:', error);
return 'default';
}
function getCurrentTheme() {
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);
/*if (theme === 'light-blue' || theme === 'dark-blue' || theme === 'default') {
button.classList.add('disabled');
button.setAttribute('disabled', 'true');
}*/
});
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);
});
}
function isThemeDisabled(theme) {
return theme === 'default' || theme === 'dark-blue';
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) {
if (isThemeDisabled(theme)) {
alert('Ez a téma jelenleg nem elérhető.');
return;
}
setCookie('themePreference', theme);
localStorage.setItem('themePreference', theme);
@@ -78,8 +109,6 @@ document.addEventListener('DOMContentLoaded', async () => {
action: 'changeTheme',
theme: theme
}).catch(() => {
console.log('Tab not ready for theme change:', tab.id);
});
});
}
@@ -92,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;
}
@@ -100,11 +129,16 @@ 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 = localStorage.getItem('themePreference') ||
getCookie('themePreference') ||
await getCurrentTheme() ||
'light-green';
let initialTheme = getCurrentTheme();
if (isThemeDisabled(initialTheme)) {
@@ -112,8 +146,12 @@ document.addEventListener('DOMContentLoaded', async () => {
}
updateThemeAvailability();
await applyTheme(initialTheme);
const initialLanguage = getCurrentLanguage();
updateLanguageButtons(initialLanguage);
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === 'themeChanged') {
@@ -124,7 +162,56 @@ document.addEventListener('DOMContentLoaded', async () => {
const manifest = chrome.runtime.getManifest();
document.getElementById('version').textContent = `v${manifest.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 = `
position: fixed;
top: 20px;
right: 20px;
background: var(--accent-accent);
color: white;
padding: 12px 20px;
border-radius: 8px;
font-family: 'Montserrat', sans-serif;
font-weight: 500;
z-index: 10000;
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 = `
@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;
}
});
themeButtons.forEach(button => {
@@ -138,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);
});
});

View File

@@ -1,32 +1,3 @@
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 400;
src: url(https://fonts.gstatic.com/s/montserrat/v25/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Hw5aXp-p7K4KLg.woff2) format('woff2');
}
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 500;
src: url(https://fonts.gstatic.com/s/montserrat/v25/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtZ6Hw5aXp-p7K4KLg.woff2) format('woff2');
}
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 600;
src: url(https://fonts.gstatic.com/s/montserrat/v25/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCu173w5aXp-p7K4KLg.woff2) format('woff2');
}
@font-face {
font-family: 'Figtree';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Figtree-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
}
* {
box-sizing: border-box;
margin: 0;
@@ -43,57 +14,6 @@ body {
font-size: 16px;
}
/* Loading Screen */
.loading-screen {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: var(--background);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 9999;
}
.loading-logo {
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;
}
.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%;
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@media (max-width: 768px) {
body {
font-size: 14px;
@@ -106,7 +26,6 @@ body {
flex-direction: column;
}
/* Update header styles to match dashboard */
.kreta-header {
padding: clamp(1rem, 3vw, 2rem);
display: grid;
@@ -123,10 +42,10 @@ body {
@media (max-width: 768px) {
.kreta-header {
grid-template-columns: 1fr auto;
grid-template-columns: 1fr auto auto;
grid-template-areas:
"school user"
"nav nav";
"school toggle user"
"nav nav nav";
padding: 1rem;
gap: 0.5rem;
}
@@ -191,82 +110,6 @@ body {
}
}
/* Updated navigation styles */
.kreta-nav {
padding: 0 clamp(0.5rem, 3vw, 1.5rem);
position: sticky;
top: 0;
z-index: 100;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
-ms-overflow-style: none;
display: flex;
justify-content: center;
}
@media (max-width: 768px) {
.kreta-nav {
grid-area: nav;
padding: 0;
margin-top: 0.5rem;
}
}
.kreta-nav::-webkit-scrollbar {
display: none;
}
.nav-links {
display: flex;
gap: clamp(0.5rem, 2vw, 1rem);
padding: 0.25rem;
justify-content: center;
}
@media (max-width: 768px) {
.nav-links {
justify-content: flex-start;
width: 100%;
gap: 0.25rem;
}
}
.nav-links a {
color: var(--text-secondary);
text-decoration: none;
padding: clamp(0.5rem, 1.5vw, 1rem) 0.5rem;
font-weight: 500;
white-space: nowrap;
transition: all 0.2s ease;
display: flex;
align-items: center;
gap: 0.5rem;
border-radius: 8px;
}
@media (max-width: 768px) {
.nav-links a {
padding: 0.5rem;
font-size: 13px;
}
.nav-links a .material-icons-round {
font-size: 20px;
}
}
.nav-links a:hover {
color: var(--text-primary);
text-decoration: none;
background-color: var(--card-card);
}
.nav-links a.active {
color: var(--accent-accent);
}
/* User profile styles */
.user-profile {
position: relative;
justify-self: flex-end;
@@ -298,19 +141,6 @@ body {
text-align: right;
}
.user-name {
display: block;
color: var(--text-primary);
font-size: 16px;
font-weight: 500;
}
.user-time {
display: block;
color: var(--text-secondary);
font-size: 14px;
}
.user-dropdown {
position: absolute;
top: 100%;
@@ -343,7 +173,6 @@ body {
background: var(--button-secondaryFill);
}
/* Main content styles */
.kreta-main {
flex: 1;
padding: clamp(1rem, 3vw, 2rem);
@@ -352,7 +181,10 @@ body {
width: 100%;
}
/* Card styles */
.k-overlay, .k-widget.k-window {
display: none !important;
}
.card {
border-radius: 24px;
overflow: hidden;
@@ -360,7 +192,6 @@ body {
margin-bottom: 1rem;
}
/* Timetable specific styles */
.timetable-grid {
display: grid;
grid-template-columns: 80px repeat(5, 1fr);
@@ -419,10 +250,8 @@ body {
border-radius: 12px;
padding: 8px;
transition: transform 0.2s ease;
}
.lesson-slot:hover {
transform: scale(1.02);
display: grid;
grid-gap: 16px;
}
.lesson-card {
@@ -516,8 +345,8 @@ body {
display: flex;
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
width: 28px;
height: 28px;
border-radius: 50%;
background: var(--accent-15);
color: var(--accent-accent);
@@ -534,29 +363,57 @@ body {
}
.lesson-indicator .material-icons-round {
font-size: 14px;
font-size: 18px;
}
/* Week selector styling */
.week-controls {
display: flex;
gap: 16px;
flex-direction: column;
align-items: center;
margin: 16px;
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 {
@@ -566,19 +423,338 @@ 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);
}
/* Responsive adjustments */
.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;
justify-content: space-between;
margin-bottom: 1rem;
padding: 0 1rem;
}
.day-nav-btn {
background: var(--card-card);
border: 1px solid var(--accent-15);
border-radius: 12px;
padding: 12px 16px;
color: var(--text-secondary);
cursor: pointer;
transition: all 0.2s ease;
display: flex;
align-items: center;
gap: 8px;
}
.day-nav-btn:hover {
background: var(--accent-15);
color: var(--accent-accent);
}
.current-day-info {
text-align: center;
flex: 1;
margin: 0 1rem;
}
.current-day-name {
font-size: 18px;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 4px;
}
.current-day-date {
font-size: 14px;
color: var(--text-secondary);
}
@media (max-width: 1024px) {
.timetable-grid {
grid-template-columns: 60px repeat(5, minmax(200px, 1fr));
@@ -590,9 +766,33 @@ body {
}
@media (max-width: 768px) {
.day-navigation {
display: flex;
}
.timetable-container {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
overflow: hidden;
}
.timetable-grid {
grid-template-columns: 60px 1fr;
overflow: visible;
}
.grid-header:not(:first-child) {
display: none;
}
.grid-header.active {
display: flex !important;
}
.lesson-slot {
display: none;
}
.lesson-slot.active {
display: block;
}
.lesson-card {
@@ -609,7 +809,6 @@ body {
}
}
/* Modal styles */
.lesson-modal {
display: none;
position: fixed;
@@ -627,7 +826,7 @@ body {
}
.lesson-modal.show {
display: flex;
display: flex !important;
opacity: 1;
}
@@ -736,7 +935,14 @@ body {
color: var(--text-primary);
}
/* Animations */
.detail-item .line-through {
text-decoration: line-through;
}
.detail-item.hidden {
display: none;
}
@keyframes fadeIn {
from {
opacity: 0;
@@ -770,7 +976,6 @@ body {
}
}
/* Responsive adjustments */
@media (max-width: 768px) {
.kreta-header {
flex-direction: column;
@@ -781,28 +986,11 @@ body {
text-align: center;
}
.nav-links {
justify-content: start;
overflow-x: auto;
padding-bottom: 0.5rem;
}
.nav-links::-webkit-scrollbar {
display: none;
}
.lesson-cell {
min-width: 200px;
}
}
/* Material Icons */
.material-icons-round {
font-size: 20px;
vertical-align: middle;
}
/* Scrollbar styling */
::-webkit-scrollbar {
width: 8px;
height: 8px;
@@ -819,4 +1007,85 @@ body {
::-webkit-scrollbar-thumb:hover {
background: var(--text-primary);
}
.grid-header.special-day {
background: linear-gradient(135deg, #F99F50, #FF8C42);
color: white;
position: relative;
}
.special-day-indicator {
display: block;
font-size: 0.7rem;
font-weight: 500;
margin-top: 2px;
opacity: 0.9;
text-align: center;
}
.special-day-card {
background: #F99F50;
color: white;
padding: 12px;
border-radius: 8px;
margin: 4px;
text-align: center;
cursor: pointer;
transition: all 0.2s ease;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.special-day-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
}
.special-day-title {
font-weight: 600;
font-size: 1.1rem;
margin-bottom: 4px;
}
.special-day-subtitle {
font-size: 0.9rem;
opacity: 0.9;
font-weight: 400;
}
.week-select {
min-width: 200px;
max-width: 300px;
}
@media (max-width: 768px) {
.special-day-indicator {
font-size: 0.6rem;
}
.special-day-card {
padding: 8px;
margin: 2px;
}
.special-day-title {
font-size: 0.8rem;
}
.special-day-subtitle {
font-size: 0.7rem;
}
}
.more-link {
margin-top: auto;
display: inline-flex;
align-items: center;
gap: 0.5rem;
color: var(--accent-accent);
text-decoration: none;
font-weight: 500;
padding-top: 16px;
transition: gap 0.2s ease;
font-size: clamp(0.875rem, 1.5vw, 1rem);
}

File diff suppressed because it is too large Load Diff

25
tools/cookieManager.js Normal file
View File

@@ -0,0 +1,25 @@
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`;
}
}

140
tools/createTemplate.js Normal file
View File

@@ -0,0 +1,140 @@
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') || ''
}
};
const schoolNameFull = `${data.schoolInfo.id} - ${data.schoolInfo.name}`;
const shortenedSchoolName = helper.shortenSchoolName(schoolNameFull);
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">
Firka
</p>
<div class="school-details" title="${schoolNameFull}">
${shortenedSchoolName}
</div>
</div>
<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>
</button>
<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>
<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>
<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>
</div>
</nav>
<div class="user-profile">
<button class="user-dropdown-btn">
<div class="user-info">
<span class="user-name">${data.userData.name}</span>
<span class="nav-logout-timer" id="logoutTimer">${data.userData.time}</span>
</div>
</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')}
</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')}
</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')}
</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')}
</a>
</div>
</div>
</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--;
}
};
setInterval(updateTimer, 1000);
return element;
},
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);
});
}
}
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');
});
});

40
tools/helper.js Normal file
View File

@@ -0,0 +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));
}
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;
}
}

59
tools/loadingScreen.css Normal file
View File

@@ -0,0 +1,59 @@
.modalBckgroundMain {
display: none !important;
}
body:not(.loaded) {
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;
}
.loading-content {
display: flex;
flex-direction: column;
align-items: center;
gap: 1rem;
}
.loading-logo {
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;
}
.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%;
}

53
tools/loadingScreen.js Normal file
View File

@@ -0,0 +1,53 @@
const loadingScreen = {
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');
},
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);
}
}
}
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);
}
});
}
if (urls.some(url => url.includes(location.pathname))) {
loadingScreen.show();
}
});