41 Commits

Author SHA1 Message Date
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
39 changed files with 2457 additions and 2504 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,14 @@
</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>
@@ -34,13 +34,19 @@
## 🚀 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 [Releases](https://github.com/QwIT-Development/firka-extension/releases/) oldalról
### Chromium alapú böngészők esetén
2. Navigálj a `chrome://extensions` oldalra
3. Kapcsold be a "Fejlesztői mód"-ot a jobb felső sarokban
4. Keresd meg a letöltött zip fájlt
5. Húzd a letöltött zip fájlt a böngészőbe
### Firefox alapú böngészők esetén
2. Navigálj az `about:addons` oldalra
3. Kattints rá a fogaskerék ikonra (⚙️) a jobb felső sarokban
4. Ebben a menüben válaszd a(z) "Kiegészítő telepítése fájlból..."/"Install Add-on From File..."
5. Válaszd ki a `.zip` fájlt amit letöltöttél
### Kész!
6. A bővítmény automatikusan működésbe lép, amikor megnyitod az e-KRÉTA oldalt
## ⚙️ Beállítások
@@ -65,8 +71,8 @@ A bővítmény jelenleg az alábbi e-KRÉTA oldalakat támogatja:
## 👥 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 +86,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,65 +1,14 @@
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 helper.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'
}
};
@@ -95,98 +44,12 @@ async function collectAbsencesData() {
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);
}
}
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">
@@ -266,69 +129,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() {
@@ -386,16 +197,6 @@ function setupFilters() {
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}`);
// }
const absenceItems = group.querySelectorAll('.absence-item');
let visibleItems = 0;
@@ -422,15 +223,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 !== filters.dateFilter) {
filter.addEventListener('change', filterAbsences);
}
} catch (err) {

View File

@@ -120,6 +120,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 {

View File

@@ -1,19 +1,10 @@
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)}...`;
},
formatGradeValue(value) {
return value?.trim() || '';
const trimmedValue = value?.trim() || '';
if (trimmedValue.toLowerCase() === 'szöveges') {
return 'Sz';
}
return trimmedValue;
},
parseDate(dateStr) {
@@ -26,11 +17,9 @@ const utils = {
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 = [
@@ -38,7 +27,6 @@ const utils = {
'július', 'augusztus', 'szeptember', 'október', 'november', 'december'
];
return `${hungarianMonths[month - 1]} ${day}.`;
}
};
@@ -192,82 +180,18 @@ class DashboardUI {
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() {
return `
<main class="kreta-main">
@@ -369,59 +293,14 @@ class DashboardUI {
render() {
document.body.innerHTML = `
<div class="kreta-container">
${DashboardUI.generateHeaderHTML(this.data, this.schoolNameFull, this.shortenedSchoolName)}
${createTemplate.header()}
${this.generateMainContentHTML()}
</div>
`;
setupUserDropdown();
setupLogoutTimer();
}
}
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 {
constructor() {
this.initialize();
@@ -433,7 +312,7 @@ class DashboardApp {
try {
const dataExtractor = new DashboardDataExtractor();
const dashboardData = dataExtractor.extractAll();
FontLoader.loadFonts();
createTemplate.importFonts();
const ui = new DashboardUI(dashboardData);
ui.render();
} catch (error) {

View File

@@ -1,9 +1,7 @@
(() => {
const transformForgotPasswordPage = () => {
const isDarkMode = localStorage.getItem('darkMode') === 'true';
document.documentElement.setAttribute('data-theme', isDarkMode ? 'dark' : 'light');
chrome.runtime.onMessage.addListener((message) => {
if (message.action === 'toggleTheme') {
@@ -11,7 +9,6 @@
localStorage.setItem('darkMode', message.darkMode);
}
});
document.body.innerHTML = `
<div class="forgot-container">
@@ -103,7 +100,6 @@
const form = event.target;
const inputs = form.querySelectorAll('.form-control[required]');
let isValid = true;
inputs.forEach(input => {
if (!validateInput(input, true)) {
@@ -144,7 +140,6 @@
submitButton.disabled = false;
}
};
if (window.location.href.includes('/Adminisztracio/ElfelejtettJelszo')) {
transformForgotPasswordPage();

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

@@ -11,26 +11,15 @@ const DEFAULT_VALUES = {
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 it is too large Load Diff

View File

@@ -1,201 +1,144 @@
(() => {
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);
}
async function transformGradesPage() {
try {
await helper.waitForElement('#Osztalyzatok_7895TanuloErtekelesByTanuloGrid');
await new Promise(resolve => setTimeout(resolve, 1000));
const gradesData = extractGradesData();
const studentAverage = calculateOverallAverage(gradesData.subjects);
const classAverage = calculateOverallClassAverage(gradesData.subjects);
document.body.innerHTML = generatePageHTML(gradesData, studentAverage, classAverage);
createTemplate.importFonts();
setupUserDropdown();
setupMobileNavigation();
const script = document.createElement('script');
script.src = chrome.runtime.getURL('grades/chart.js');
document.head.appendChild(script);
script.onload = () => {
setupGradesChart(gradesData.subjects);
};
setupEventListeners();
loadingScreen.hide();
} catch (error) {
console.error('Error transforming grades page:', error);
loadingScreen.hide();
}
}
return null;
}
function showLoadingScreen() {
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/firka_logo.png')}" alt="Firka" class="loading-logo">
<div class="loading-text">Betöltés alatt...</div>
<div class="loading-text2">Kis türelmet!</div>
</div>
`;
document.body.appendChild(loadingScreen);
}
function hideLoadingScreen() {
const loadingScreen = document.querySelector('.loading-screen');
if (loadingScreen) {
loadingScreen.style.opacity = '0';
loadingScreen.addEventListener('transitionend', () => {
loadingScreen.remove();
});
}
}
function extractGradesData() {
const subjects = [];
const rows = document.querySelectorAll('#Osztalyzatok_7895TanuloErtekelesByTanuloGrid tbody tr');
async function transformGradesPage() {
try {
showLoadingScreen();
rows.forEach(row => {
const cells = row.querySelectorAll('td');
if (cells.length >= 17) {
const subjectName = cells[2].textContent.trim();
if (subjectName && subjectName !== 'Magatartás/Szorgalom') {
const grades = [];
const months = ['Szeptember', 'Oktober', 'November', 'December', 'JanuarI', 'JanuarII', 'Februar', 'Marcius', 'Aprilis', 'Majus', 'JuniusI', 'JuniusII'];
await waitForElement('#Osztalyzatok_7895TanuloErtekelesByTanuloGrid');
await new Promise(resolve => setTimeout(resolve, 1000));
months.forEach((month, index) => {
const gradeElements = cells[index + 3].querySelectorAll('span[data-tanuloertekelesid]');
gradeElements.forEach(element => {
const gradeText = element.textContent.trim();
if (gradeText && gradeText !== '-') {
grades.push({
value: gradeText,
date: element.getAttribute('data-datum'),
type: element.getAttribute('data-tipusmod'),
theme: element.getAttribute('data-ertekelestema').replace('Téma: ', ''),
weight: element.getAttribute('data-suly'),
teacher: element.getAttribute('data-ertekelonyomtatasinev'),
isSemesterGrade: (element.getAttribute('data-tipusmod') || '').toLowerCase().includes('félévi') ||
(element.getAttribute('data-ertekelestema') || '').toLowerCase().includes('félévi') ||
(element.getAttribute('data-tipus') || '').toLowerCase().includes('félévi')
});
}
});
});
const gradesData = extractGradesData();
const studentAverage = calculateOverallAverage(gradesData.subjects);
const classAverage = calculateOverallClassAverage(gradesData.subjects);
document.body.innerHTML = generatePageHTML(gradesData, studentAverage, classAverage);
const avgText = cells[16].textContent.trim();
const classAvgText = cells[17].textContent.trim();
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' }
];
const average = avgText !== '-' ? parseFloat(avgText.replace(',', '.')) : 0;
const classAvg = classAvgText !== '-' ? parseFloat(classAvgText.replace(',', '.')) : 0;
const script = document.createElement('script');
script.src = chrome.runtime.getURL('grades/chart.js');
document.head.appendChild(script);
if (grades.length > 0) {
links.forEach(link => {
const linkElement = document.createElement('link');
Object.entries(link).forEach(([key, value]) => {
linkElement[key] = value;
});
document.head.appendChild(linkElement);
subjects.push({
name: subjectName,
grades: grades,
average: average || 0,
classAverage: classAvg || 0
});
}
}
}
});
script.onload = () => {
setupGradesChart(gradesData.subjects);
return {
schoolInfo: {
id: cookieManager.get('schoolCode') || '',
name: cookieManager.get('schoolName') || 'Iskola'
},
userData: {
name: cookieManager.get('userName') || 'Felhasználó',
time: document.querySelector('.usermenu_timer')?.textContent?.trim() || '45:00'
},
subjects: subjects
};
setupEventListeners();
hideLoadingScreen();
} catch (error) {
console.error('Error transforming grades page:', error);
hideLoadingScreen();
}
}
function extractGradesData() {
const subjects = [];
const rows = document.querySelectorAll('#Osztalyzatok_7895TanuloErtekelesByTanuloGrid tbody tr');
rows.forEach(row => {
const cells = row.querySelectorAll('td');
if (cells.length >= 17) {
const subjectName = cells[2].textContent.trim();
if (subjectName && subjectName !== 'Magatartás/Szorgalom') {
const grades = [];
const months = ['Szeptember', 'Oktober', 'November', 'December', 'JanuarI', 'JanuarII', 'Februar', 'Marcius', 'Aprilis', 'Majus', 'JuniusI', 'JuniusII'];
months.forEach((month, index) => {
const gradeElements = cells[index + 3].querySelectorAll('span[data-tanuloertekelesid]');
gradeElements.forEach(element => {
const gradeText = element.textContent.trim();
if (gradeText && gradeText !== '-') {
grades.push({
value: gradeText,
date: element.getAttribute('data-datum'),
type: element.getAttribute('data-tipusmod'),
theme: element.getAttribute('data-ertekelestema').replace('Téma: ', ''),
weight: element.getAttribute('data-suly'),
teacher: element.getAttribute('data-ertekelonyomtatasinev'),
isSemesterGrade: (element.getAttribute('data-tipusmod') || '').toLowerCase().includes('félévi') ||
(element.getAttribute('data-ertekelestema') || '').toLowerCase().includes('félévi') ||
(element.getAttribute('data-tipus') || '').toLowerCase().includes('félévi')
});
}
});
});
function calculateOverallAverage(subjects) {
const validSubjects = subjects.filter(s => s.average > 0);
if (validSubjects.length === 0) return 0;
const avgText = cells[16].textContent.trim();
const classAvgText = cells[17].textContent.trim();
const average = avgText !== '-' ? parseFloat(avgText.replace(',', '.')) : 0;
const classAvg = classAvgText !== '-' ? parseFloat(classAvgText.replace(',', '.')) : 0;
if (grades.length > 0) {
const weightedSum = validSubjects.reduce((sum, subject) => {
const validGrades = subject.grades.filter(grade => !isNaN(parseInt(grade.value)));
const subjectWeightedSum = validGrades.reduce((gradeSum, grade) => {
const value = parseInt(grade.value);
const weight = parseInt(grade.weight?.match(/\d+/)?.[0] || '100') / 100;
return gradeSum + (value * weight);
}, 0);
subjects.push({
name: subjectName,
grades: grades,
average: average || 0,
classAverage: classAvg || 0
});
}
}
}
});
const totalWeight = validGrades.reduce((weightSum, grade) => {
const weight = parseInt(grade.weight?.match(/\d+/)?.[0] || '100') / 100;
return weightSum + weight;
}, 0);
return {
schoolInfo: {
id: getCookie('schoolCode') || '',
name: getCookie('schoolName') || 'Iskola'
},
userData: {
name: getCookie('userName') || 'Felhasználó',
time: document.querySelector('.usermenu_timer')?.textContent?.trim() || '45:00'
},
subjects: subjects
};
}
return sum + (subjectWeightedSum / totalWeight);
}, 0);
function calculateOverallAverage(subjects) {
const validSubjects = subjects.filter(s => s.average > 0);
if (validSubjects.length === 0) return 0;
const weightedSum = validSubjects.reduce((sum, subject) => {
const validGrades = subject.grades.filter(grade => !isNaN(parseInt(grade.value)));
const subjectWeightedSum = validGrades.reduce((gradeSum, grade) => {
const value = parseInt(grade.value);
const weight = parseInt(grade.weight?.match(/\d+/)?.[0] || '100') / 100;
return gradeSum + (value * weight);
}, 0);
const totalWeight = validGrades.reduce((weightSum, grade) => {
const weight = parseInt(grade.weight?.match(/\d+/)?.[0] || '100') / 100;
return weightSum + weight;
}, 0);
return sum + (subjectWeightedSum / totalWeight);
}, 0);
return weightedSum / validSubjects.length;
}
return weightedSum / validSubjects.length;
}
function calculateOverallClassAverage(subjects) {
const validSubjects = subjects.filter(s => s.classAverage > 0);
if (validSubjects.length === 0) return 0;
return validSubjects.reduce((sum, s) => sum + s.classAverage, 0) / validSubjects.length;
}
function calculateOverallClassAverage(subjects) {
const validSubjects = subjects.filter(s => s.classAverage > 0);
if (validSubjects.length === 0) return 0;
return validSubjects.reduce((sum, s) => sum + s.classAverage, 0) / validSubjects.length;
}
function shortenEvaluationName(name, maxLength = 30) {
if (!name) return '';
if (name.length <= maxLength) return name;
return name.substring(0, maxLength - 3) + '...';
}
function shortenEvaluationName(name, maxLength = 30) {
if (!name) return '';
if (name.length <= maxLength) return name;
return name.substring(0, maxLength - 3) + '...';
}
function generateGradeItem(grade) {
const semesterClass = grade.isSemesterGrade ? 'semester-grade' : '';
const dateObj = new Date(grade.date);
const monthNames = ['Január', 'Február', 'Március', 'Április', 'Május', 'Június', 'Július', 'Augusztus', 'Szeptember', 'Október', 'November', 'December'];
const formattedDate = `${monthNames[dateObj.getMonth()]} ${dateObj.getDate()}`;
const shortenedTheme = shortenEvaluationName(grade.theme);
return `
function generateGradeItem(grade) {
const semesterClass = grade.isSemesterGrade ? 'semester-grade' : '';
const dateObj = new Date(grade.date);
const monthNames = ['Január', 'Február', 'Március', 'Április', 'Május', 'Június', 'Július', 'Augusztus', 'Szeptember', 'Október', 'November', 'December'];
const formattedDate = `${monthNames[dateObj.getMonth()]} ${dateObj.getDate()}`;
const shortenedTheme = shortenEvaluationName(grade.theme);
return `
<div class="grade-item grade-${grade.value} ${semesterClass}">
<div class="grade-value">${grade.value}</div>
<div class="grade-details">
@@ -205,89 +148,35 @@
<div class="grade-date">${formattedDate}</div>
</div>
`;
}
}
function calculateGradeDistribution(subjects) {
const distribution = {1: 0, 2: 0, 3: 0, 4: 0, 5: 0};
subjects.forEach(subject => {
subject.grades.forEach(grade => {
const value = parseInt(grade.value);
if (value >= 1 && value <= 5) {
distribution[value]++;
}
function calculateGradeDistribution(subjects) {
const distribution = {1: 0, 2: 0, 3: 0, 4: 0, 5: 0};
subjects.forEach(subject => {
subject.grades.forEach(grade => {
const value = parseInt(grade.value);
if (value >= 1 && value <= 5) {
distribution[value]++;
}
});
});
});
return distribution;
}
return distribution;
}
function generatePageHTML(data, studentAverage, classAverage) {
const totalGrades = data.subjects.reduce((sum, subject) => sum + subject.grades.length, 0);
const gradeDistribution = calculateGradeDistribution(data.subjects);
const semesterGrades = extractSemesterGrades(data.subjects);
const studentGradeLevel = Math.floor(studentAverage) || 0;
const classGradeLevel = Math.floor(classAverage) || 0;
function generatePageHTML(data, studentAverage, classAverage) {
const totalGrades = data.subjects.reduce((sum, subject) => sum + subject.grades.length, 0);
const gradeDistribution = calculateGradeDistribution(data.subjects);
const semesterGrades = extractSemesterGrades(data.subjects);
return `
const studentGradeLevel = Math.floor(studentAverage) || 0;
const classGradeLevel = Math.floor(classAverage) || 0;
schoolNameFull = `${data.schoolInfo.id} - ${data.schoolInfo.name}`;
shortenedSchoolName = helper.shortenSchoolName(schoolNameFull);
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">
<span>${data.schoolInfo.id} - ${data.schoolInfo.name}</span>
</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 active">
<img src="${chrome.runtime.getURL('icons/grades-active.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>
${createTemplate.header()}
<main class="kreta-main">
<div class="grades-overview">
@@ -338,166 +227,168 @@ function generatePageHTML(data, studentAverage, classAverage) {
</main>
</div>
`;
}
}
function extractSemesterGrades(subjects) {
const semesterGrades = [];
subjects.forEach(subject => {
const semesterGrade = subject.grades.find(grade => grade.isSemesterGrade);
if (semesterGrade) {
semesterGrades.push({
subject: subject.name,
value: semesterGrade.value,
date: semesterGrade.date
});
}
});
return semesterGrades;
}
function extractSemesterGrades(subjects) {
const semesterGrades = [];
subjects.forEach(subject => {
const semesterGrade = subject.grades.find(grade => grade.isSemesterGrade);
if (semesterGrade) {
semesterGrades.push({
subject: subject.name,
value: semesterGrade.value,
date: semesterGrade.date
});
}
});
return semesterGrades;
}
function calculateGradePoints(subjects) {
const allGrades = [];
subjects.forEach(subject => {
subject.grades.forEach(grade => {
const date = new Date(grade.date);
const value = parseInt(grade.value);
const weight = parseInt(grade.weight?.match(/\d+/)?.[0] || '100') / 100;
allGrades.push({
date,
value,
weight
});
});
});
function calculateGradePoints(subjects) {
const allGrades = [];
allGrades.sort((a, b) => a.date - b.date);
subjects.forEach(subject => {
subject.grades.forEach(grade => {
const date = new Date(grade.date);
const value = parseInt(grade.value);
const weight = parseInt(grade.weight?.match(/\d+/)?.[0] || '100') / 100;
if (date && value && weight) {
allGrades.push({
date,
value,
weight
});
}
});
});
let totalWeight = 0;
let weightedSum = 0;
return allGrades.map(grade => {
totalWeight += grade.weight;
weightedSum += grade.value * grade.weight;
return {
date: grade.date.toISOString(),
grade: grade.value,
average: weightedSum / totalWeight
};
});
}
function setupGradesChart(subjects) {
const ctx = document.getElementById('gradesChart');
if (!ctx) return;
allGrades.sort((a, b) => a.date - b.date);
const gradePoints = calculateGradePoints(subjects);
new Chart(ctx, {
type: 'line',
data: {
labels: gradePoints.map((_, index) => ''),
datasets: [{
label: 'Átlag',
data: gradePoints.map(p => p.average),
borderWidth: 5,
tension: 0.5,
segment: {
borderColor: ctx => {
const curr = ctx.p1.parsed.y;
if (!curr) return 'transparent';
const color = getComputedStyle(document.documentElement).getPropertyValue(
curr < 2 ? '--grades-1' :
curr < 2.5 ? '--grades-2' :
curr < 3.5 ? '--grades-3' :
curr < 4.5 ? '--grades-4' : '--grades-5'
).trim() + '80';
return color;
}
},
fill: true,
backgroundColor: function(context) {
const chart = context.chart;
const {ctx, chartArea} = chart;
if (!chartArea) return null;
const gradientBg = ctx.createLinearGradient(0, chartArea.bottom, 0, chartArea.top);
gradientBg.addColorStop(0, getComputedStyle(document.documentElement).getPropertyValue('--grades-1').trim() + '30');
gradientBg.addColorStop(0.2, getComputedStyle(document.documentElement).getPropertyValue('--grades-2').trim() + '30');
gradientBg.addColorStop(0.4, getComputedStyle(document.documentElement).getPropertyValue('--grades-3').trim() + '30');
gradientBg.addColorStop(0.6, getComputedStyle(document.documentElement).getPropertyValue('--grades-4').trim() + '30');
gradientBg.addColorStop(0.8, getComputedStyle(document.documentElement).getPropertyValue('--grades-5').trim() + '30');
return gradientBg;
},
pointBackgroundColor: context => {
const value = context.raw;
return getComputedStyle(document.documentElement).getPropertyValue(
value < 2 ? '--grades-1' :
value < 2.5 ? '--grades-2' :
value < 3.5 ? '--grades-3' :
value < 4.5 ? '--grades-4' : '--grades-5'
).trim();
},
pointRadius: 0,
pointHoverRadius: 0
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
min: 1,
max: 5,
ticks: {
stepSize: 1,
color: getComputedStyle(document.documentElement).getPropertyValue('--text-secondary')
},
grid: {
color: getComputedStyle(document.documentElement).getPropertyValue('--text-teritary') + '20',
lineWidth: 1,
borderDash: [5, 5]
}
},
x: {
display: false
}
},
plugins: {
legend: {
display: false
},
tooltip: {
backgroundColor: getComputedStyle(document.documentElement).getPropertyValue('--card-card'),
titleColor: getComputedStyle(document.documentElement).getPropertyValue('--text-primary'),
bodyColor: getComputedStyle(document.documentElement).getPropertyValue('--text-primary'),
borderColor: getComputedStyle(document.documentElement).getPropertyValue('--text-teritary') + '20',
borderWidth: 1,
padding: 12,
displayColors: false,
callbacks: {
title: () => '',
label: context => `Átlag: ${context.raw.toFixed(2)}`
}
}
}
}
});
}
function generateSubjectCards(subjects) {
const sortedSubjects = [...subjects].sort((a, b) => a.grades.length - b.grades.length);
let totalWeight = 0;
let weightedSum = 0;
return allGrades.map(grade => {
totalWeight += grade.weight;
weightedSum += grade.value * grade.weight;
return {
date: grade.date.toISOString(),
grade: grade.value,
average: weightedSum / totalWeight
};
});
}
return sortedSubjects.map(subject => {
const regularGrades = subject.grades.filter(grade => !grade.isSemesterGrade);
const myGrade = Math.floor(subject.average) || 0;
const classGrade = Math.floor(subject.classAverage) || 0;
return `
function setupGradesChart(subjects) {
const ctx = document.getElementById('gradesChart');
if (!ctx) return;
const gradePoints = calculateGradePoints(subjects);
new Chart(ctx, {
type: 'line',
data: {
labels: gradePoints.map((_, index) => ''),
datasets: [{
label: 'Átlag',
data: gradePoints.map(p => p.average),
borderWidth: 5,
tension: 0.5,
segment: {
borderColor: ctx => {
const curr = ctx.p1.parsed.y;
if (!curr) return 'transparent';
const color = getComputedStyle(document.documentElement).getPropertyValue(
curr < 2 ? '--grades-1' :
curr < 2.5 ? '--grades-2' :
curr < 3.5 ? '--grades-3' :
curr < 4.5 ? '--grades-4' : '--grades-5'
).trim() + '80';
return color;
}
},
fill: true,
backgroundColor: function(context) {
const chart = context.chart;
const {ctx, chartArea} = chart;
if (!chartArea) return null;
const gradientBg = ctx.createLinearGradient(0, chartArea.bottom, 0, chartArea.top);
gradientBg.addColorStop(0, getComputedStyle(document.documentElement).getPropertyValue('--grades-1').trim() + '30');
gradientBg.addColorStop(0.2, getComputedStyle(document.documentElement).getPropertyValue('--grades-2').trim() + '30');
gradientBg.addColorStop(0.4, getComputedStyle(document.documentElement).getPropertyValue('--grades-3').trim() + '30');
gradientBg.addColorStop(0.6, getComputedStyle(document.documentElement).getPropertyValue('--grades-4').trim() + '30');
gradientBg.addColorStop(0.8, getComputedStyle(document.documentElement).getPropertyValue('--grades-5').trim() + '30');
return gradientBg;
},
pointBackgroundColor: context => {
const value = context.raw;
return getComputedStyle(document.documentElement).getPropertyValue(
value < 2 ? '--grades-1' :
value < 2.5 ? '--grades-2' :
value < 3.5 ? '--grades-3' :
value < 4.5 ? '--grades-4' : '--grades-5'
).trim();
},
pointRadius: 0,
pointHoverRadius: 0
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
min: 1,
max: 5,
ticks: {
stepSize: 1,
color: getComputedStyle(document.documentElement).getPropertyValue('--text-secondary')
},
grid: {
color: getComputedStyle(document.documentElement).getPropertyValue('--text-teritary') + '20',
lineWidth: 1,
borderDash: [5, 5]
}
},
x: {
display: false
}
},
plugins: {
legend: {
display: false
},
tooltip: {
backgroundColor: getComputedStyle(document.documentElement).getPropertyValue('--card-card'),
titleColor: getComputedStyle(document.documentElement).getPropertyValue('--text-primary'),
bodyColor: getComputedStyle(document.documentElement).getPropertyValue('--text-primary'),
borderColor: getComputedStyle(document.documentElement).getPropertyValue('--text-teritary') + '20',
borderWidth: 1,
padding: 12,
displayColors: false,
callbacks: {
title: () => '',
label: context => `Átlag: ${context.raw.toFixed(2)}`
}
}
}
}
});
}
function generateSubjectCards(subjects) {
const sortedSubjects = [...subjects].sort((a, b) => a.grades.length - b.grades.length);
return sortedSubjects.map(subject => {
const regularGrades = subject.grades.filter(grade => !grade.isSemesterGrade);
const myGrade = Math.floor(subject.average) || 0;
const classGrade = Math.floor(subject.classAverage) || 0;
return `
<div class="subject-card card">
<div class="subject-header">
<div class="subject-title">
@@ -519,68 +410,33 @@ function generateSubjectCards(subjects) {
</div>
</div>
`;
}).join('');
}
function setupEventListeners() {
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] || "45");
let timeLeft = startTime * 60;
const updateTimer = () => {
const minutes = Math.floor(timeLeft / 60);
const seconds = timeLeft % 60;
timerEl.textContent = `${minutes}:${seconds.toString().padStart(2, '0')}`;
if (timeLeft <= 0) {
window.location.href = '/Home/Logout';
} else {
timeLeft--;
}
};
updateTimer();
setInterval(updateTimer, 1000);
}).join('');
}
}
function waitForElement(selector) {
return new Promise(resolve => {
if (document.querySelector(selector)) {
return resolve(document.querySelector(selector));
}
function setupEventListeners() {
const timerEl = document.getElementById('logoutTimer');
if (timerEl) {
const startTime = parseInt(timerEl.textContent?.match(/\d+/)?.[0] || "45");
let timeLeft = startTime * 60;
const observer = new MutationObserver(mutations => {
if (document.querySelector(selector)) {
observer.disconnect();
resolve(document.querySelector(selector));
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);
}
});
}
observer.observe(document.body, {
childList: true,
subtree: true
});
});
}
if (window.location.href.includes('/TanuloErtekeles/Osztalyzatok')) {
transformGradesPage();
}
if (window.location.href.includes('/TanuloErtekeles/Osztalyzatok')) {
transformGradesPage();
}
})();

View File

@@ -67,10 +67,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 +135,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 +164,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 {
@@ -524,4 +444,15 @@ body {
flex-direction: column;
gap: 0.25rem;
}
}
@keyframes dropdownShow {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}

View File

@@ -1,65 +1,14 @@
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 collectHomeworkData() {
await waitForElement('#TanulotHaziFeladatkGrid');
await helper.waitForElement('#TanulotHaziFeladatkGrid');
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'
}
};
@@ -93,29 +42,6 @@ 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>
`;
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);
}
}
function isTomorrow(dateStr) {
if (!dateStr) return false;
@@ -124,7 +50,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,74 +69,11 @@ 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">
@@ -268,8 +131,8 @@ async function transformHomeworkPage() {
setupFilters(homeworkItems, groupedHomework);
setupUserDropdown();
setupLogoutTimer();
hideLoadingScreen();
setupMobileNavigation();
loadingScreen.hide();
}
function renderHomeworkList(groupedHomework) {
@@ -437,11 +300,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);
@@ -519,50 +382,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')) {

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,7 +22,6 @@ async function transformLoginPage() {
kretaId: '',
omCode: ''
};
const spanElement = titleElement?.querySelector('span');
if (spanElement) {
@@ -31,11 +29,9 @@ async function transformLoginPage() {
schoolInfo.kretaId = lines[0] || '';
schoolInfo.omCode = (lines[1] || '').replace('KRÉTA azonosító: ', '');
}
const rawSystemMessage = document.querySelector('.alert-primary')?.textContent?.trim() || '';
const systemMessage = rawSystemMessage.replace('Rendszerértesítés', '').trim();
const newHTML = `
<div class="login-container">
@@ -61,13 +57,13 @@ 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>
placeholder="Felhasználónév" maxlength="256" autocomplete="username" required value="${formData.userName}">
<div class="error-message">Kérjük, add meg a felhasználóneved.</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>
placeholder="Jelszó" maxlength="256" autocomplete="current-password" required value="${formData.password}">
<button type="button" class="show-password" aria-label="Jelszó mutatása">
<img src="${chrome.runtime.getURL('icons/eye-off.svg')}" alt="Show password" class="icon-eye">
</button>
@@ -100,10 +96,8 @@ async function transformLoginPage() {
</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');

326
login/twofactor.css Normal file
View File

@@ -0,0 +1,326 @@
@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;
--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">Kétfaktoros azonosítás</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="Egyszeri jelszó" maxlength="256" autocomplete="off" required autofocus>
<button type="button" class="show-password" aria-label="Jelszó mutatása">
<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 az egyszeri jelszót.</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">
Eszköz megjelölése biztonságosként
</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">Kód ellenőrzése</button>
</div>
<div class="d-flex justify-content-center mt-3">
<span class="subtext">
Nem fér hozzá eszközéhez? Lépjen be
<button type="submit" class="btn-link" formaction="/account/loginwithrecoverycode">
helyreállító kóddal.
</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">Adatkezelési tájékoztató</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">Ellenőrzés...</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

@@ -20,15 +20,16 @@
"icons/*.svg",
"grades/chart.js"
],
"matches": ["https://*.e-kreta.hu/*"]
"matches": ["https://*.e-kreta.hu/*", "https://idp.e-kreta.hu/*"]
}],
"content_scripts": [
{
"matches": [
"https://*.e-kreta.hu/*"
],
"js": ["global/maintenance.js", "global/theme.js", "global/navigation.js"],
"css": ["global/theme.css", "global/navigation.css"],
"js": ["tools/cookieManager.js", "tools/helper.js", "tools/loadingScreen.js", "tools/createTemplate.js",
"global/maintenance.js", "global/theme.js", "global/navigation.js"],
"css": ["tools/loadingScreen.css", "global/theme.css", "global/navigation.css"],
"run_at": "document_start"
},
{
@@ -43,6 +44,11 @@
"js": ["login/login.js"],
"css": ["login/login.css"]
},
{
"matches": ["https://idp.e-kreta.hu/account/loginwithtwofactor*"],
"js": ["login/twofactor.js"],
"css": ["login/twofactor.css"]
},
{
"matches": [
"https://*.e-kreta.hu/Hianyzas/Hianyzasok*"
@@ -114,6 +120,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,8 +166,8 @@
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();
@@ -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,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');
@@ -124,30 +117,18 @@
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();

247
search/search.css Normal file
View File

@@ -0,0 +1,247 @@
@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;
}
/* 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('Kérjük, válasszon egy intézményt a folytatáshoz!');
}
});
}
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

@@ -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">

View File

@@ -1,5 +1,26 @@
document.addEventListener('DOMContentLoaded', async () => {
function isThemeDisabled(theme) {
const blueThemesUnlocked = localStorage.getItem('blueThemesUnlocked') === 'true';
return (theme === 'default' || theme === 'light-blue' || theme === 'dark-blue') && !blueThemesUnlocked;
}
function updateThemeAvailability() {
const blueThemesUnlocked = localStorage.getItem('blueThemesUnlocked') === 'true';
document.querySelectorAll('.theme-option').forEach(button => {
const theme = button.dataset.theme;
if (theme === 'default' || theme === 'light-blue' || theme === 'dark-blue') {
if (blueThemesUnlocked) {
button.style.display = 'block';
button.classList.remove('disabled');
button.removeAttribute('disabled');
} else {
button.style.display = 'none';
}
}
});
}
function getCookie(name) {
const cookieName = `${name}=`;
const decodedCookie = decodeURIComponent(document.cookie);
@@ -25,43 +46,21 @@ 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');
}*/
});
}
function isThemeDisabled(theme) {
return theme === 'default' || theme === 'dark-blue';
updateThemeAvailability();
}
async function applyTheme(theme) {
if (isThemeDisabled(theme)) {
alert('Ez a téma jelenleg nem elérhető.');
return;
}
setCookie('themePreference', theme);
localStorage.setItem('themePreference', theme);
@@ -101,10 +100,7 @@ document.addEventListener('DOMContentLoaded', async () => {
});
let initialTheme = localStorage.getItem('themePreference') ||
getCookie('themePreference') ||
await getCurrentTheme() ||
'light-green';
let initialTheme = getCurrentTheme();
if (isThemeDisabled(initialTheme)) {
@@ -112,6 +108,7 @@ document.addEventListener('DOMContentLoaded', async () => {
}
updateThemeAvailability();
await applyTheme(initialTheme);
@@ -124,7 +121,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 = 'Kék témák feloldva! 🎉';
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 => {

View File

@@ -43,57 +43,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;
@@ -123,10 +72,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,81 +140,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;
@@ -298,19 +172,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 +204,6 @@ body {
background: var(--button-secondaryFill);
}
/* Main content styles */
.kreta-main {
flex: 1;
padding: clamp(1rem, 3vw, 2rem);
@@ -352,7 +212,10 @@ body {
width: 100%;
}
/* Card styles */
.k-overlay, .k-widget.k-window {
display: none !important;
}
.card {
border-radius: 24px;
overflow: hidden;
@@ -360,7 +223,6 @@ body {
margin-bottom: 1rem;
}
/* Timetable specific styles */
.timetable-grid {
display: grid;
grid-template-columns: 80px repeat(5, 1fr);
@@ -419,10 +281,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 {
@@ -537,7 +397,6 @@ body {
font-size: 14px;
}
/* Week selector styling */
.week-controls {
display: flex;
gap: 16px;
@@ -578,7 +437,6 @@ body {
color: var(--accent-accent);
}
/* Responsive adjustments */
@media (max-width: 1024px) {
.timetable-grid {
grid-template-columns: 60px repeat(5, minmax(200px, 1fr));
@@ -609,7 +467,6 @@ body {
}
}
/* Modal styles */
.lesson-modal {
display: none;
position: fixed;
@@ -627,7 +484,7 @@ body {
}
.lesson-modal.show {
display: flex;
display: flex !important;
opacity: 1;
}
@@ -736,6 +593,14 @@ body {
color: var(--text-primary);
}
.detail-item .line-through {
text-decoration: line-through;
}
.detail-item.hidden {
display: none;
}
/* Animations */
@keyframes fadeIn {
from {
@@ -781,27 +646,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;

View File

@@ -1,104 +1,20 @@
(() => {
// Segédfüggvények
function convertTimeToMinutes(timeStr) {
const [hours, minutes] = timeStr.split(':').map(Number);
return hours * 60 + minutes;
}
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) + '...';
}
function showLoadingScreen() {
const loadingScreen = document.createElement('div');
loadingScreen.className = 'loading-screen';
loadingScreen.innerHTML = `
<img src="https://i.imgur.com/JE3LzRc.gif" alt="Firka" class="loading-logo">
<div class="loading-text">Betöltés alatt...</div>
<p class="loading-text2">Kis türelmet!</p>
`;
document.body.appendChild(loadingScreen);
}
function hideLoadingScreen() {
const loadingScreen = document.querySelector('.loading-screen');
if (loadingScreen) {
loadingScreen.style.opacity = '0';
loadingScreen.style.transition = 'opacity 0.3s ease';
setTimeout(() => loadingScreen.remove(), 300);
}
}
// DOM elemek várása
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
});
});
}
// Órarendi adatok gyűjtése
async function collectTimetableData() {
await waitForElement('#Calendar');
await new Promise(resolve => setTimeout(resolve, 1000));
await helper.waitForElement('#Calendar');
await helper.waitForElement('.modalBckgroundMain:not(.isOverlayActiv)');
const calendar = document.querySelector('#Calendar');
const dates = Array.from(document.querySelectorAll('.fc-day-header')).map(header => {
const fullText = header.textContent.trim();
// Remove the day name from the beginning and clean up the format
const dateText = fullText.replace(/^(hétfő|kedd|szerda|csütörtök|péntek)/, '').trim();
return {
date: fullText,
formattedDate: dateText
};
});
// Fix the Thursday issue by ensuring we have all 5 days
if (dates.length === 4) {
// Get Wednesday's date parts
const wedDate = dates[2].formattedDate;
const [month, day] = wedDate.split(' ');
const dayNum = parseInt(day.replace('.', ''));
// Create Thursday's date
const thursdayDate = `${month} ${dayNum + 1}.`;
dates.splice(3, 0, {
@@ -106,9 +22,8 @@
formattedDate: thursdayDate
});
}
// Set week selector based on the current date
const weekOptions = Array.from(document.querySelectorAll('#Calendar_tanevHetek_listbox li'));
const currentDate = dates[0]?.formattedDate; // Using Monday's date
const currentDate = dates[0]?.formattedDate;
const matchingWeek = weekOptions.find(opt => opt.textContent.includes(currentDate));
if (matchingWeek) {
@@ -121,11 +36,11 @@
}
const timetableData = {
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'
},
weekInfo: {
@@ -137,12 +52,11 @@
selected: li.classList.contains('k-state-selected')
}))
},
weekDates: dates, // Add the dates to the data object
weekDates: dates,
lessons: []
};
// Órák adatainak gyűjtése
document.querySelectorAll('.fc-event').forEach(event => {
for (const event of document.querySelectorAll('.fc-event')) {
const timeEl = event.querySelector('.fc-time');
const titleEl = event.querySelector('.fc-title');
@@ -151,11 +65,20 @@
const [fullSubject, teacher, room] = titleEl.innerHTML.split('<br>').map(str => str.trim());
const subject = fullSubject.split('-')[0].trim();
let originalTeacher = '';
if (teacher.startsWith('Helyettesítő:')) {
event.click();
originalTeacher = await helper.waitForElement("#OraAdatokDetailTabStrip-1 > div > div:nth-child(3) > div:nth-child(2)");
originalTeacher = originalTeacher.innerText;
document.querySelector("body > div.k-widget.k-window > div.k-window-titlebar.k-header > div > a:nth-child(2)").click();
}
timetableData.lessons.push({
startTime,
endTime,
subject: subject || '',
teacher: teacher || '',
originalTeacher: originalTeacher || '',
room: (room || '').replace(/[()]/g, ''),
day: event.closest('td').cellIndex - 1,
isSubstituted: event.querySelector('.fc-bg2') !== null,
@@ -165,16 +88,14 @@
homeworkDetails: event.getAttribute('data-homework') || ''
});
}
});
}
return timetableData;
}
// Grid generálása
function generateTimeGrid(lessons, weekDates) {
const times = [...new Set(lessons.map(l => l.startTime))].sort((a, b) => {
const timeA = convertTimeToMinutes(a);
const timeB = convertTimeToMinutes(b);
const timeA = helper.convertTimeToMinutes(a);
const timeB = helper.convertTimeToMinutes(b);
return timeA - timeB;
});
const days = ['Hétfő', 'Kedd', 'Szerda', 'Csütörtök', 'Péntek'];
@@ -226,7 +147,6 @@
`).join('')}
`;
}
// Óra részletek modal
function showLessonModal(lesson) {
const modal = document.createElement('div');
modal.className = 'lesson-modal';
@@ -242,7 +162,11 @@
<div class="lesson-details">
<div class="detail-item">
<span class="detail-label">Tanár:</span>
<span class="detail-value">${lesson.teacher}</span>
<span class="detail-value ${(lesson.originalTeacher != '' ? 'line-through' : '')}">${lesson.originalTeacher != '' ? lesson.originalTeacher : lesson.teacher}</span>
</div>
<div class="detail-item ${(lesson.originalTeacher != '' ? '' : 'hidden')}">
<span class="detail-label">Helyettesítő tanár:</span>
<span class="detail-value">${lesson.teacher.replace('Helyettesítő:', '')}</span>
</div>
<div class="detail-item">
<span class="detail-label">Terem:</span>
@@ -294,7 +218,6 @@
document.body.appendChild(modal);
// Modal bezárás
const closeModal = () => {
modal.classList.remove('show');
setTimeout(() => modal.remove(), 300);
@@ -305,7 +228,6 @@
if (e.target === modal) closeModal();
});
// ESC gomb kezelése
const handleEscape = (e) => {
if (e.key === 'Escape') {
closeModal();
@@ -314,15 +236,12 @@
};
document.addEventListener('keydown', handleEscape);
// Animáció
requestAnimationFrame(() => {
modal.classList.add('show');
});
}
// Eseménykezelők beállítása
function setupEventListeners(data) {
// Órakártyák
document.querySelectorAll('.lesson-card').forEach(card => {
card.addEventListener('click', () => {
const lessonData = JSON.parse(card.dataset.lesson);
@@ -330,26 +249,12 @@
});
});
// Felhasználói menü
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');
});
// Hét navigáció
const prevBtn = document.querySelector('.prev-week');
const nextBtn = document.querySelector('.next-week');
const weekSelect = document.querySelector('.week-select');
prevBtn?.addEventListener('click', async () => {
showLoadingScreen();
loadingScreen.show();
const kendoCalendar = document.querySelector('#Calendar')?.__kendoWidget;
if (kendoCalendar) {
kendoCalendar.prev();
@@ -359,7 +264,7 @@
});
nextBtn?.addEventListener('click', async () => {
showLoadingScreen();
loadingScreen.show();
const kendoCalendar = document.querySelector('#Calendar')?.__kendoWidget;
if (kendoCalendar) {
kendoCalendar.next();
@@ -369,7 +274,6 @@
});
weekSelect?.addEventListener('change', async function() {
showLoadingScreen();
const kendoCombo = document.querySelector('#Calendar_tanevHetek')?.__kendoWidget;
if (kendoCombo) {
kendoCombo.value(this.value);
@@ -378,105 +282,18 @@
await transformTimetablePage();
}
});
// Kijelentkezés időzítő
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--;
}
};
updateTimer();
setInterval(updateTimer, 1000);
}
// Oldal transzformáció
async function transformTimetablePage() {
try {
showLoadingScreen();
const data = await collectTimetableData();
if (!data) {
hideLoadingScreen();
loadingScreen.hide();
return;
}
const schoolNameFull = `${data.schoolInfo.id} - ${data.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 active">
<img src="${chrome.runtime.getURL('icons/timetable-active.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>
${createTemplate.header()}
<main class="kreta-main">
<div class="week-controls">
@@ -504,39 +321,19 @@
</div>
`;
// Szükséges fontok hozzáadása
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(data);
hideLoadingScreen();
loadingScreen.hide();
} catch (error) {
console.error('Hiba az oldal átalakítása során:', error);
hideLoadingScreen();
loadingScreen.hide();
}
}
// Beállítások gomb kezelése
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');
});
if (window.location.href.includes('/Orarend/')) {
transformTimetablePage();
}

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

135
tools/createTemplate.js Normal file
View File

@@ -0,0 +1,135 @@
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="Navigáció megnyitása">
<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="Kezdőlap">
Kezdőlap
</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="Jegyek">
Jegyek
</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="Órarend">
Órarend
</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="Mulasztások">
Mulasztások
</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="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>`
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/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%;
}

47
tools/loadingScreen.js Normal file
View File

@@ -0,0 +1,47 @@
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">Betöltés alatt...</div>
<div class="loading-text2">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';
loadingScreen.addEventListener('transitionend', () => {
loadingScreen.remove();
});
}
}
}
window.addEventListener('DOMContentLoaded', () => {
const manifest = chrome.runtime.getManifest();
const urls = [];
if (manifest.content_scripts) {
manifest.content_scripts.forEach(script => {
if (script.matches) {
urls.push(...script.matches);
}
});
}
if (urls.some(url => url.includes(location.pathname))) {
loadingScreen.show();
}
});