mirror of
https://github.com/QwIT-Development/firka-extension.git
synced 2026-06-12 11:51:39 +02:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a94c06d893 | ||
|
|
7cd8c065b3 | ||
|
|
d44be3b029 | ||
|
|
3243ebdc2e | ||
|
|
0f69a1583b | ||
|
|
15ab433064 | ||
|
|
4aab9afebd | ||
|
|
e0df578dca | ||
|
|
dd320d3dc4 | ||
|
|
5248cfc12e | ||
|
|
1f34cacf25 | ||
|
|
f35d29f56c | ||
|
|
1429943dbe | ||
|
|
2ca1c9949a |
@@ -1,5 +1,5 @@
|
||||
<p align="center">
|
||||
<img width="150" height="150" alt="firka_logo_128" src="https://github.com/user-attachments/assets/089b37c8-bdb1-48af-93e5-9fc656fe8c15" />
|
||||
<img width="150" height="150" alt="firka_logo_128" src="https://github.com/QwIT-Development/firka-extension/blob/main/images/firka_logo_128.png?raw=true" />
|
||||
<h1 align="center">Firka extension</h1>
|
||||
</p>
|
||||
|
||||
|
||||
1
icons/contact.svg
Normal file
1
icons/contact.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 3.223a9.003 9.003 0 0 0-5.605 13.592L3 21l4.185-1.395A9.003 9.003 0 0 0 20.777 14m0-4A9.01 9.01 0 0 0 14 3.223M17 12a5 5 0 0 0-5-5m1 5a1 1 0 0 0-1-1"/></svg>
|
||||
|
After Width: | Height: | Size: 353 B |
1
icons/project.svg
Normal file
1
icons/project.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 24 24"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="M3 20h.01M7 20a4 4 0 0 0-4-4m8 4a8 8 0 0 0-8-8"/><path fill="currentColor" d="M19 4H5a2 2 0 0 0-2 2v2.5c4 .167 12 2.7 12 11.5h4a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2"/></g></svg>
|
||||
|
After Width: | Height: | Size: 365 B |
@@ -40,9 +40,7 @@
|
||||
"grades/chart.js",
|
||||
"i18n/*.json",
|
||||
"tools/storageManager.js",
|
||||
"tools/storageTest.js",
|
||||
"tools/sentry.js",
|
||||
"tools/sentry-browser.min.js"
|
||||
"tools/storageTest.js"
|
||||
],
|
||||
"matches": [
|
||||
"<all_urls>"
|
||||
@@ -67,8 +65,6 @@
|
||||
"https://eugyintezes.e-kreta.hu/*"
|
||||
],
|
||||
"js": [
|
||||
"tools/sentry-browser.min.js",
|
||||
"tools/sentry.js",
|
||||
"global/language.js",
|
||||
"global/theme.js",
|
||||
"tools/loadingScreen.js",
|
||||
|
||||
@@ -40,9 +40,7 @@
|
||||
"grades/chart.js",
|
||||
"i18n/*.json",
|
||||
"tools/storageManager.js",
|
||||
"tools/storageTest.js",
|
||||
"tools/sentry.js",
|
||||
"tools/sentry-browser.min.js"
|
||||
"tools/storageTest.js"
|
||||
],
|
||||
"matches": [
|
||||
"<all_urls>"
|
||||
@@ -67,8 +65,6 @@
|
||||
"https://eugyintezes.e-kreta.hu/*"
|
||||
],
|
||||
"js": [
|
||||
"tools/sentry-browser.min.js",
|
||||
"tools/sentry.js",
|
||||
"global/language.js",
|
||||
"global/theme.js",
|
||||
"tools/loadingScreen.js",
|
||||
|
||||
@@ -440,7 +440,6 @@ body.modal-open {
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
border-bottom: 1px solid var(--background-0);
|
||||
background: var(--background);
|
||||
border-radius: 12px 12px 0 0;
|
||||
}
|
||||
|
||||
@@ -525,7 +524,7 @@ body.modal-open {
|
||||
}
|
||||
|
||||
.message-info {
|
||||
background-color: var(--card-card);
|
||||
background-color: var(--button-secondaryFill);
|
||||
padding: 15px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 20px;
|
||||
@@ -564,7 +563,7 @@ body.modal-open {
|
||||
}
|
||||
|
||||
.message-text {
|
||||
background-color: var(--card-card);
|
||||
background-color: var(--button-secondaryFill);
|
||||
border-radius: 6px;
|
||||
padding: 15px;
|
||||
line-height: 1.6;
|
||||
@@ -591,14 +590,14 @@ body.modal-open {
|
||||
}
|
||||
|
||||
.message-attachments {
|
||||
background: #f9f9f9;
|
||||
background: var(--button-secondaryFill);
|
||||
padding: 15px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.message-attachments h4 {
|
||||
margin: 0 0 10px 0;
|
||||
color: #333;
|
||||
color: var(--text-secondary);
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
|
||||
@@ -310,7 +310,8 @@
|
||||
messageContent.appendChild(contentTitle);
|
||||
const messageText = document.createElement('div');
|
||||
messageText.className = 'message-text';
|
||||
messageText.textContent = content;
|
||||
messageText.innerHTML = content;
|
||||
|
||||
messageContent.appendChild(messageText);
|
||||
messageDetails.appendChild(messageContent);
|
||||
|
||||
@@ -320,14 +321,17 @@
|
||||
const attachTitle = document.createElement('h4');
|
||||
attachTitle.textContent = 'Mellékletek:';
|
||||
messageAttachments.appendChild(attachTitle);
|
||||
|
||||
|
||||
const attachList = document.createElement('ul');
|
||||
message.csatolmanyok.forEach(attachment => {
|
||||
const li = document.createElement('li');
|
||||
const a = document.createElement('a');
|
||||
a.href = '#';
|
||||
a.textContent = sanitizeHTML(attachment.nev);
|
||||
a.onclick = () => downloadAttachment(attachment.azonosito);
|
||||
a.textContent = sanitizeHTML(attachment.fajlNev || attachment.nev || 'Ismeretlen fájl');
|
||||
a.onclick = (e) => {
|
||||
e.preventDefault();
|
||||
downloadAttachment(attachment.azonosito, attachment.fajlNev || attachment.nev);
|
||||
};
|
||||
li.appendChild(a);
|
||||
attachList.appendChild(li);
|
||||
});
|
||||
@@ -345,6 +349,32 @@
|
||||
}
|
||||
document.body.classList.remove('modal-open');
|
||||
}
|
||||
|
||||
async function downloadAttachment(azonosito, fileName) {
|
||||
try {
|
||||
const response = await chrome.runtime.sendMessage({
|
||||
action: 'download_attachment',
|
||||
azonosito: azonosito,
|
||||
fileName: fileName
|
||||
});
|
||||
|
||||
if (response.success && response.data) {
|
||||
const a = document.createElement('a');
|
||||
a.href = response.data;
|
||||
a.download = response.fileName || 'letoltes';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
} else {
|
||||
console.error('Melléklet letöltési hiba:', response.error);
|
||||
alert('Nem sikerült letölteni a mellékletet.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Melléklet letöltési hiba:', error);
|
||||
alert('Hiba történt a melléklet letöltése során.');
|
||||
}
|
||||
}
|
||||
|
||||
window.openMessageModal = openMessageModal;
|
||||
window.closeMessageModal = closeMessageModal;
|
||||
|
||||
|
||||
@@ -593,29 +593,6 @@ h2 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.modal-close {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
background: var(--button-secondaryFill);
|
||||
color: var(--text-secondary);
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.modal-close:hover {
|
||||
background: var(--accent-15);
|
||||
color: var(--accent-accent);
|
||||
}
|
||||
|
||||
.modal-close .material-icons-round {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding: 16px;
|
||||
}
|
||||
@@ -1150,3 +1127,183 @@ h2 {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.update-modal .modal-content {
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
.update-version-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
margin-bottom: 20px;
|
||||
padding: 16px;
|
||||
background: var(--button-secondaryFill);
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.version-badge {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.version-badge.current {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.version-badge.latest {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.version-label {
|
||||
font-size: 11px;
|
||||
color: var(--text-secondary);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.version-number {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: var(--text-primary);
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.version-badge.latest .version-number {
|
||||
color: var(--accent-accent);
|
||||
}
|
||||
|
||||
.version-arrow {
|
||||
color: var(--accent-accent);
|
||||
font-size: 24px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.update-changelog-section {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.update-changelog-section h4 {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
margin: 0 0 12px 0;
|
||||
}
|
||||
|
||||
.update-changelog {
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
padding: 12px;
|
||||
background: var(--button-secondaryFill);
|
||||
border-radius: 8px;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.update-changelog p {
|
||||
margin: 0 0 8px 0;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.update-changelog p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.update-changelog h1,
|
||||
.update-changelog h2,
|
||||
.update-changelog h3 {
|
||||
color: var(--text-primary);
|
||||
margin: 12px 0 8px 0;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.update-changelog h1 {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.update-changelog h2 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.update-changelog h3 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.update-changelog ul,
|
||||
.update-changelog ol {
|
||||
margin: 8px 0;
|
||||
padding-left: 24px;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.update-changelog li {
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.update-changelog code {
|
||||
background: var(--accent-15);
|
||||
color: var(--accent-accent);
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.update-changelog pre {
|
||||
background: var(--background);
|
||||
color: var(--text-primary);
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
overflow-x: auto;
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.update-changelog pre code {
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.update-changelog a {
|
||||
color: var(--accent-accent);
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.update-changelog a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.update-changelog blockquote {
|
||||
border-left: 3px solid var(--accent-accent);
|
||||
padding-left: 12px;
|
||||
margin: 8px 0;
|
||||
color: var(--text-secondary);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.update-changelog strong {
|
||||
color: var(--text-primary);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.update-changelog em {
|
||||
font-style: italic;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.update-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
text-decoration: none;
|
||||
justify-content: center;
|
||||
border-radius: 8px;
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
.update-button .material-icons-round {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
@@ -188,6 +188,39 @@
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-overlay" id="updateModal">
|
||||
<div class="modal-content update-modal">
|
||||
<div class="modal-header">
|
||||
<h3 data-i18n="settings.update.title">Új verzió érhető el!</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="update-version-info">
|
||||
<div class="version-badge current">
|
||||
<span class="version-label" data-i18n="settings.update.current_version">Jelenlegi verzió:</span>
|
||||
<span class="version-number" id="currentVersion">-</span>
|
||||
</div>
|
||||
<span class="material-icons-round version-arrow">arrow_forward</span>
|
||||
<div class="version-badge latest">
|
||||
<span class="version-label" data-i18n="settings.update.latest_version">Legújabb verzió:</span>
|
||||
<span class="version-number" id="latestVersion">-</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="update-changelog-section">
|
||||
<h4 data-i18n="settings.update.whats_new">Újdonságok:</h4>
|
||||
<div class="update-changelog" id="updateChangelog">
|
||||
<p data-i18n="settings.update.loading">Betöltés...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn-secondary" id="dismissUpdate" data-i18n="settings.update.dismiss">Bezárás</button>
|
||||
<a class="btn-primary update-button" id="updateButton" href="#" target="_blank">
|
||||
<span data-i18n="settings.update.download">Letöltés</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-overlay" id="themeEditorModal">
|
||||
<div class="modal-content theme-editor-modal">
|
||||
<div class="modal-header">
|
||||
@@ -304,8 +337,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="../tools/sentry-browser.min.js"></script>
|
||||
<script src="../tools/sentry.js"></script>
|
||||
<script src="../tools/helper.js"></script>
|
||||
<script src="../tools/storageManager.js"></script>
|
||||
<script src="../global/language.js"></script>
|
||||
|
||||
@@ -1048,6 +1048,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
|
||||
await initTabs();
|
||||
await initErrorReporting();
|
||||
await checkForUpdates();
|
||||
});
|
||||
|
||||
async function initErrorReporting() {
|
||||
@@ -1067,3 +1068,101 @@ async function initErrorReporting() {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function checkForUpdates() {
|
||||
try {
|
||||
const manifest = chrome.runtime.getManifest();
|
||||
const currentVersion = manifest.version;
|
||||
|
||||
const response = await fetch('https://api.github.com/repos/QwIT-Development/firka-extension/releases/latest');
|
||||
if (!response.ok) {
|
||||
console.error('Failed to fetch latest release');
|
||||
return;
|
||||
}
|
||||
|
||||
const latestRelease = await response.json();
|
||||
const latestVersion = latestRelease.tag_name.replace(/^v/, '');
|
||||
|
||||
if (compareVersions(latestVersion, currentVersion) > 0) {
|
||||
showUpdateModal(currentVersion, latestVersion, latestRelease);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error checking for updates:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function compareVersions(v1, v2) {
|
||||
const parts1 = v1.split('.').map(Number);
|
||||
const parts2 = v2.split('.').map(Number);
|
||||
|
||||
for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
|
||||
const part1 = parts1[i] || 0;
|
||||
const part2 = parts2[i] || 0;
|
||||
|
||||
if (part1 > part2) return 1;
|
||||
if (part1 < part2) return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function parseMarkdown(markdown) {
|
||||
let html = markdown;
|
||||
|
||||
html = html.replace(/^### (.*$)/gim, '<h3>$1</h3>');
|
||||
html = html.replace(/^## (.*$)/gim, '<h2>$1</h2>');
|
||||
html = html.replace(/^# (.*$)/gim, '<h1>$1</h1>');
|
||||
|
||||
html = html.replace(/\*\*\*(.+?)\*\*\*/g, '<strong><em>$1</em></strong>');
|
||||
html = html.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
|
||||
html = html.replace(/\*(.+?)\*/g, '<em>$1</em>');
|
||||
html = html.replace(/__(.+?)__/g, '<strong>$1</strong>');
|
||||
html = html.replace(/_(.+?)_/g, '<em>$1</em>');
|
||||
|
||||
html = html.replace(/`([^`]+)`/g, '<code>$1</code>');
|
||||
|
||||
html = html.replace(/```([^```]+)```/g, '<pre><code>$1</code></pre>');
|
||||
|
||||
html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" target="_blank">$1</a>');
|
||||
|
||||
html = html.replace(/^> (.+)/gim, '<blockquote>$1</blockquote>');
|
||||
|
||||
html = html.replace(/^\* (.+)$/gim, '<li>$1</li>');
|
||||
html = html.replace(/^- (.+)$/gim, '<li>$1</li>');
|
||||
html = html.replace(/(<li>.*<\/li>)/s, '<ul>$1</ul>');
|
||||
|
||||
html = html.replace(/^\d+\. (.+)$/gim, '<li>$1</li>');
|
||||
|
||||
html = html.replace(/\n\n/g, '</p><p>');
|
||||
html = html.replace(/^(?!<[hou]|<li|<pre|<blockquote)(.+)$/gim, '<p>$1</p>');
|
||||
|
||||
html = html.replace(/<p><\/p>/g, '');
|
||||
html = html.replace(/<p>(<[hou])/g, '$1');
|
||||
html = html.replace(/(<\/[hou]l?>)<\/p>/g, '$1');
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
function showUpdateModal(currentVersion, latestVersion, releaseData) {
|
||||
const modal = document.getElementById('updateModal');
|
||||
const currentVersionEl = document.getElementById('currentVersion');
|
||||
const latestVersionEl = document.getElementById('latestVersion');
|
||||
const changelogEl = document.getElementById('updateChangelog');
|
||||
const updateButton = document.getElementById('updateButton');
|
||||
|
||||
currentVersionEl.textContent = `v${currentVersion}`;
|
||||
latestVersionEl.textContent = `v${latestVersion}`;
|
||||
|
||||
const changelog = releaseData.body || 'Nincs elérhető változásnapló.';
|
||||
changelogEl.innerHTML = parseMarkdown(changelog);
|
||||
|
||||
updateButton.href = releaseData.html_url;
|
||||
|
||||
modal.classList.add('active');
|
||||
document.getElementById('dismissUpdate').addEventListener('click', closeUpdateModal);
|
||||
}
|
||||
|
||||
function closeUpdateModal() {
|
||||
const modal = document.getElementById('updateModal');
|
||||
modal.classList.remove('active');
|
||||
}
|
||||
|
||||
@@ -152,8 +152,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="../tools/sentry-browser.min.js"></script>
|
||||
<script src="../tools/sentry.js"></script>
|
||||
<script src="../tools/storageManager.js"></script>
|
||||
<script src="../global/language.js"></script>
|
||||
<script src="setup.js"></script>
|
||||
|
||||
@@ -147,7 +147,8 @@ body {
|
||||
transition:all 0.3s cubic-bezier(0.4,0,0.2,1);
|
||||
transform:translateY(0);
|
||||
}
|
||||
.lesson-card:hover {
|
||||
.lesson-card:hover,
|
||||
.lesson-card.group-hover {
|
||||
transform:translateY(-4px);
|
||||
box-shadow:0 8px 12px var(--accent-shadow);
|
||||
}
|
||||
@@ -162,6 +163,28 @@ body {
|
||||
opacity:0.5;
|
||||
text-decoration:line-through;
|
||||
}
|
||||
|
||||
.lesson-card.lesson-spans-multiple {
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.lesson-card.lesson-continuation.continuation-middle {
|
||||
border-radius: 0;
|
||||
}
|
||||
.lesson-card.lesson-continuation.continuation-end {
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
|
||||
.lesson-slot.has-multi-start {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.lesson-slot.has-continuation {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.lesson-subject {
|
||||
align-self:stretch;
|
||||
color:var(--text-primary);
|
||||
|
||||
@@ -160,7 +160,7 @@
|
||||
}
|
||||
|
||||
function getLessonKey(lesson) {
|
||||
return `${lesson.subject}_${lesson.startTime}_${lesson.day}`;
|
||||
return `${lesson.subject}_${lesson.startTime}_${lesson.date}`;
|
||||
}
|
||||
|
||||
async function updateHomeworkIconsFromCookie() {
|
||||
@@ -313,7 +313,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function loadTestDetailsFromAPI(testId) {
|
||||
async function loadAllTestDataFromAPI() {
|
||||
const now = Date.now();
|
||||
if (cachedTestData && (now - testDataTimestamp) < TEST_DATA_CACHE_DURATION) {
|
||||
return cachedTestData;
|
||||
}
|
||||
|
||||
try {
|
||||
const timestamp = Date.now();
|
||||
const apiUrl = `https://${window.location.hostname}/api/TanuloBejelentettSzamonkeresekApi/GetBejelentettSzamonkeresekGrid?sort=SzamonkeresDatuma-asc~Oraszam-asc&page=1&pageSize=1000&group=&filter=&data=%7B%22RegiSzamonkeresekElrejtese%22%3Afalse%7D&_=${timestamp}`;
|
||||
@@ -327,15 +332,30 @@
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
`Számonkérés API hiba: ${response.status}`,
|
||||
);
|
||||
throw new Error(`Számonkérés API hiba: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const testData = data.Data || [];
|
||||
cachedTestData = data.Data || [];
|
||||
testDataTimestamp = now;
|
||||
return cachedTestData;
|
||||
} catch (error) {
|
||||
console.error("Számonkérés adatok betöltési hiba:", error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async function getTestTypeById(testId) {
|
||||
const testData = await loadAllTestDataFromAPI();
|
||||
const testDetail = testData.find(test => test.ID === testId.toString());
|
||||
return testDetail ? testDetail.ErtekelesModNev : null;
|
||||
}
|
||||
|
||||
async function loadTestDetailsFromAPI(testId) {
|
||||
try {
|
||||
const testData = await loadAllTestDataFromAPI();
|
||||
const testDetail = testData.find(test => test.ID === testId.toString());
|
||||
|
||||
|
||||
if (testDetail) {
|
||||
return {
|
||||
name: testDetail.SzamonkeresMegnevezes || 'Nincs megnevezés',
|
||||
@@ -343,7 +363,7 @@
|
||||
announceDate: testDetail.BejelentesDatuma ? new Date(testDetail.BejelentesDatuma).toLocaleDateString('hu-HU') : 'Nincs dátum'
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.error("Számonkérés adatok betöltési hiba:", error);
|
||||
@@ -410,6 +430,7 @@
|
||||
originalTeacher: "",
|
||||
room: "",
|
||||
day: dayIndex,
|
||||
date: weekDates[dayIndex]?.fullDate || eventDate.toISOString().split('T')[0],
|
||||
isSubstituted: false,
|
||||
isCancelled: false,
|
||||
hasHomework: false,
|
||||
@@ -446,9 +467,9 @@
|
||||
"Ismeretlen tantárgy";
|
||||
|
||||
if (startTimeStr && subject) {
|
||||
const isCancelled = event.isElmaradt || event.Elmaradt || event.cancelled || event.isCancelled ||
|
||||
const isCancelled = event.isElmaradt || event.Elmaradt || event.cancelled || event.isCancelled ||
|
||||
event.oraType === 6 || (event.title && event.title.toLowerCase().includes('elmarad'));
|
||||
|
||||
|
||||
const lesson = {
|
||||
startTime: startTimeStr,
|
||||
endTime: endTimeStr,
|
||||
@@ -457,14 +478,15 @@
|
||||
originalTeacher: event.helyettesitoId ? teacher : "",
|
||||
room: room,
|
||||
day: dayIndex,
|
||||
date: weekDates[dayIndex]?.fullDate || eventDate.toISOString().split('T')[0],
|
||||
isSubstituted: !!event.helyettesitoId,
|
||||
isCancelled: isCancelled,
|
||||
hasHomework: event.hasHaziFeladat || false,
|
||||
testInfo: event.hasBejelentettSzamonkeres
|
||||
? event.Tema || LanguageManager.t("timetable.test_indicator")
|
||||
: "",
|
||||
testId: event.hasBejelentettSzamonkeres && event.BejelentettSzamonkeresIdList && event.BejelentettSzamonkeresIdList.length > 0
|
||||
? event.BejelentettSzamonkeresIdList[0]
|
||||
testId: event.hasBejelentettSzamonkeres && event.BejelentettSzamonkeresIdList && event.BejelentettSzamonkeresIdList.length > 0
|
||||
? event.BejelentettSzamonkeresIdList[0]
|
||||
: null,
|
||||
testDetails: "",
|
||||
homeworkDetails: "",
|
||||
@@ -497,6 +519,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
const testTypeMap = {};
|
||||
const lessonsWithTests = lessons.filter(l => l.testId);
|
||||
if (lessonsWithTests.length > 0) {
|
||||
await loadAllTestDataFromAPI();
|
||||
for (const lesson of lessonsWithTests) {
|
||||
testTypeMap[lesson.testId] = await getTestTypeById(lesson.testId);
|
||||
}
|
||||
}
|
||||
|
||||
const times = [...new Set(regularLessons.map((l) => l.startTime))].sort(
|
||||
(a, b) => {
|
||||
const timeA = helper.convertTimeToMinutes(a);
|
||||
@@ -504,6 +535,26 @@
|
||||
return timeA - timeB;
|
||||
},
|
||||
);
|
||||
|
||||
function getLessonTimeSlots(lesson, allTimes) {
|
||||
const startMinutes = helper.convertTimeToMinutes(lesson.startTime);
|
||||
const endMinutes = helper.convertTimeToMinutes(lesson.endTime);
|
||||
const slots = [];
|
||||
for (let i = 0; i < allTimes.length; i++) {
|
||||
const slotMinutes = helper.convertTimeToMinutes(allTimes[i]);
|
||||
if (slotMinutes >= startMinutes && slotMinutes < endMinutes) {
|
||||
slots.push(i);
|
||||
}
|
||||
}
|
||||
return slots.length > 0 ? slots : [allTimes.indexOf(lesson.startTime)];
|
||||
}
|
||||
|
||||
const lessonSlotMap = new Map();
|
||||
regularLessons.forEach(lesson => {
|
||||
const slots = getLessonTimeSlots(lesson, times);
|
||||
lessonSlotMap.set(lesson, slots);
|
||||
});
|
||||
|
||||
const days = [
|
||||
LanguageManager.t("timetable.monday"),
|
||||
LanguageManager.t("timetable.tuesday"),
|
||||
@@ -569,38 +620,84 @@
|
||||
const dayLessons = regularLessons.filter(
|
||||
(l) => l.startTime === time && l.day === dayIndex,
|
||||
);
|
||||
|
||||
const continuingInSlot = regularLessons.filter(lesson => {
|
||||
if (lesson.day !== dayIndex) return false;
|
||||
const slots = lessonSlotMap.get(lesson);
|
||||
return slots && slots.includes(timeIndex) && slots[0] !== timeIndex;
|
||||
});
|
||||
|
||||
const hasMultiLesson = dayLessons.some(lesson => {
|
||||
const slots = lessonSlotMap.get(lesson);
|
||||
return slots && slots.length > 1;
|
||||
});
|
||||
|
||||
const lastLessonTime = lastLessonTimes[dayIndex];
|
||||
const isAfterLastLesson = lastLessonTime && helper.convertTimeToMinutes(time) > helper.convertTimeToMinutes(lastLessonTime);
|
||||
|
||||
if (dayLessons.length === 0 && isAfterLastLesson) {
|
||||
|
||||
if (dayLessons.length === 0 && continuingInSlot.length === 0 && isAfterLastLesson) {
|
||||
return `<div class="lesson-slot"></div>`;
|
||||
}
|
||||
|
||||
|
||||
if (continuingInSlot.length > 0) {
|
||||
return `
|
||||
<div class="lesson-slot ${dayLessons.length === 0 ? 'empty-slot' : ''}">
|
||||
${dayLessons.length === 0 ? '<div class="empty-lesson-placeholder"></div>' : ''}
|
||||
${dayLessons
|
||||
.map(
|
||||
(lesson) => `
|
||||
<div class="lesson-card ${lesson.isSubstituted ? "substituted" : ""}
|
||||
<div class="lesson-slot has-continuation">
|
||||
${continuingInSlot.map(lesson => {
|
||||
const slots = lessonSlotMap.get(lesson);
|
||||
const isLastSlot = slots[slots.length - 1] === timeIndex;
|
||||
const lessonGroupId = `${lesson.subject}_${lesson.day}_${lesson.date}_${lesson.startTime}`;
|
||||
return `
|
||||
<div class="lesson-card ${lesson.isSubstituted ? "substituted" : ""}
|
||||
${lesson.isCancelled ? "cancelled" : ""}
|
||||
${lesson.hasHomework ? "has-homework" : ""}"
|
||||
lesson-continuation ${isLastSlot ? 'continuation-end' : 'continuation-middle'}"
|
||||
data-lesson='${JSON.stringify(lesson)}'
|
||||
data-lesson-id='${lesson.lessonId || ""}'>
|
||||
<div class="lesson-subject">${lesson.subject}</div>
|
||||
<div class="lesson-teacher">${lesson.teacher}</div>
|
||||
data-lesson-id='${lesson.lessonId || ""}'
|
||||
data-lesson-group='${lessonGroupId}'>
|
||||
<div class="lesson-bottom">
|
||||
<div class="lesson-room">${lesson.room}</div>
|
||||
<div class="lesson-time">${lesson.isCancelled ? LanguageManager.t("timetable.cancelled") : lesson.startTime}</div>
|
||||
</div>
|
||||
</div>
|
||||
`}).join('')}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
return `
|
||||
<div class="lesson-slot ${dayLessons.length === 0 ? 'empty-slot' : ''} ${hasMultiLesson ? 'has-multi-start' : ''}">
|
||||
${dayLessons.length === 0 ? '<div class="empty-lesson-placeholder"></div>' : ''}
|
||||
${dayLessons
|
||||
.map(
|
||||
(lesson) => {
|
||||
const slots = lessonSlotMap.get(lesson);
|
||||
const spansMultiple = slots && slots.length > 1;
|
||||
const lessonGroupId = `${lesson.subject}_${lesson.day}_${lesson.date}_${lesson.startTime}`;
|
||||
return `
|
||||
<div class="lesson-card ${lesson.isSubstituted ? "substituted" : ""}
|
||||
${lesson.isCancelled ? "cancelled" : ""}
|
||||
${lesson.hasHomework ? "has-homework" : ""}
|
||||
${spansMultiple ? "lesson-spans-multiple" : ""}"
|
||||
data-lesson='${JSON.stringify(lesson)}'
|
||||
data-lesson-id='${lesson.lessonId || ""}'
|
||||
data-spans='${slots ? slots.length : 1}'
|
||||
data-lesson-group='${lessonGroupId}'>
|
||||
<div class="lesson-subject">${lesson.subject}</div>
|
||||
<div class="lesson-teacher">${lesson.teacher}</div>
|
||||
${!spansMultiple ? `<div class="lesson-bottom">
|
||||
<div class="lesson-room">${lesson.room}</div>
|
||||
<div class="lesson-time">${lesson.isCancelled ? LanguageManager.t("timetable.cancelled") : lesson.startTime}</div>
|
||||
</div>` : ''}
|
||||
${
|
||||
(() => {
|
||||
const lessonKey = `${lesson.subject}_${lesson.startTime}_${lesson.day}`;
|
||||
const hasCustomHomework = customHomework[lessonKey] && customHomework[lessonKey].length > 0;
|
||||
const hasCustomTests = customTests[lessonKey] && customTests[lessonKey].length > 0;
|
||||
const lessonKey = `${lesson.subject}_${lesson.startTime}_${lesson.date}`;
|
||||
const customHomeworkItems = customHomework[lessonKey] || [];
|
||||
const customTestItems = customTests[lessonKey] || [];
|
||||
const hasCustomHomework = customHomeworkItems.length > 0;
|
||||
const hasCustomTests = customTestItems.length > 0;
|
||||
const allCustomHomeworkCompleted = hasCustomHomework && customHomeworkItems.every(hw => hw.completed);
|
||||
const allCustomTestsCompleted = hasCustomTests && customTestItems.every(test => test.completed);
|
||||
const hasAnyIndicators = lesson.hasHomework || lesson.testInfo || hasCustomHomework || hasCustomTests;
|
||||
|
||||
|
||||
return hasAnyIndicators ? `
|
||||
<div class="lesson-indicators">
|
||||
${
|
||||
@@ -614,18 +711,40 @@
|
||||
}
|
||||
${
|
||||
lesson.testInfo
|
||||
? `
|
||||
<span class="lesson-indicator test-indicator" title="${LanguageManager.t("timetable.test_indicator")}">
|
||||
<img src="${chrome.runtime.getURL("icons/assigment.svg")}" alt="Teszt" style="width: 20px; height: 20px;">
|
||||
? (() => {
|
||||
const testType = lesson.testId ? testTypeMap[lesson.testId] : null;
|
||||
const isKontaktOra = testType === "KONTAKT ÓRA";
|
||||
const isProjektOra = testType === "PROJEKT ÓRA";
|
||||
let indicatorClass = "test-indicator";
|
||||
let iconPath = "icons/assigment.svg";
|
||||
let titleText = LanguageManager.t("timetable.test_indicator");
|
||||
let altText = "Teszt";
|
||||
|
||||
if (isKontaktOra) {
|
||||
indicatorClass = "homework-indicator";
|
||||
iconPath = "icons/contact.svg";
|
||||
titleText = "Kontakt óra";
|
||||
altText = "Kontakt óra";
|
||||
} else if (isProjektOra) {
|
||||
indicatorClass = "homework-indicator";
|
||||
iconPath = "icons/project.svg";
|
||||
titleText = "Projekt óra";
|
||||
altText = "Projekt óra";
|
||||
}
|
||||
|
||||
return `
|
||||
<span class="lesson-indicator ${indicatorClass}" title="${titleText}">
|
||||
<img src="${chrome.runtime.getURL(iconPath)}" alt="${altText}" style="width: 20px; height: 20px;">
|
||||
</span>
|
||||
`
|
||||
`;
|
||||
})()
|
||||
: ""
|
||||
}
|
||||
${
|
||||
hasCustomHomework
|
||||
? `
|
||||
<span class="lesson-indicator custom-homework-indicator" title="Saját házi feladat">
|
||||
<img src="${chrome.runtime.getURL("icons/homework.svg")}" alt="Saját házi feladat" style="width: 20px; height: 20px; opacity: 0.7;">
|
||||
<img src="${chrome.runtime.getURL(allCustomHomeworkCompleted ? "icons/pipa.svg" : "icons/homework.svg")}" alt="${allCustomHomeworkCompleted ? 'Megoldott saját házi feladat' : 'Saját házi feladat'}" style="width: 20px; height: 20px; opacity: 0.7;">
|
||||
</span>
|
||||
`
|
||||
: ""
|
||||
@@ -634,7 +753,7 @@
|
||||
hasCustomTests
|
||||
? `
|
||||
<span class="lesson-indicator custom-test-indicator" title="Saját számonkérés">
|
||||
<img src="${chrome.runtime.getURL("icons/assigment.svg")}" alt="Saját számonkérés" style="width: 20px; height: 20px; opacity: 0.7;">
|
||||
<img src="${chrome.runtime.getURL(allCustomTestsCompleted ? "icons/pipa.svg" : "icons/assigment.svg")}" alt="${allCustomTestsCompleted ? 'Megoldott saját számonkérés' : 'Saját számonkérés'}" style="width: 20px; height: 20px; opacity: 0.7;">
|
||||
</span>
|
||||
`
|
||||
: ""
|
||||
@@ -644,8 +763,8 @@
|
||||
})()
|
||||
}
|
||||
</div>
|
||||
`,
|
||||
)
|
||||
`;
|
||||
})
|
||||
.join("")
|
||||
}
|
||||
</div>
|
||||
@@ -1196,83 +1315,92 @@
|
||||
}
|
||||
|
||||
if (lesson.testInfo) {
|
||||
let testDetails = null;
|
||||
if (lesson.testId) {
|
||||
testDetails = await loadTestDetailsFromAPI(lesson.testId);
|
||||
}
|
||||
|
||||
const isKontaktOra = testDetails && testDetails.type === "KONTAKT ÓRA";
|
||||
const isProjektOra = testDetails && testDetails.type === "PROJEKT ÓRA";
|
||||
const isSpecialType = isKontaktOra || isProjektOra;
|
||||
|
||||
const testSection = document.createElement('div');
|
||||
testSection.className = 'modal-section test-section';
|
||||
|
||||
testSection.className = isSpecialType ? 'modal-section homework-section' : 'modal-section test-section';
|
||||
|
||||
const testH4 = document.createElement('h4');
|
||||
const testIcon = document.createElement('img');
|
||||
testIcon.src = chrome.runtime.getURL('icons/assigment.svg');
|
||||
testIcon.alt = 'Teszt';
|
||||
|
||||
let iconPath = 'icons/assigment.svg';
|
||||
let sectionTitle = LanguageManager.t('timetable.test_indicator');
|
||||
let altText = 'Teszt';
|
||||
|
||||
if (isKontaktOra) {
|
||||
iconPath = 'icons/contact.svg';
|
||||
sectionTitle = 'Kontakt óra';
|
||||
altText = 'Kontakt óra';
|
||||
} else if (isProjektOra) {
|
||||
iconPath = 'icons/project.svg';
|
||||
sectionTitle = 'Projekt óra';
|
||||
altText = 'Projekt óra';
|
||||
}
|
||||
|
||||
testIcon.src = chrome.runtime.getURL(iconPath);
|
||||
testIcon.alt = altText;
|
||||
testIcon.style.width = '20px';
|
||||
testIcon.style.height = '20px';
|
||||
testH4.appendChild(testIcon);
|
||||
testH4.appendChild(document.createTextNode(LanguageManager.t('timetable.test_indicator')));
|
||||
|
||||
testH4.appendChild(document.createTextNode(sectionTitle));
|
||||
if (isSpecialType) {
|
||||
testH4.style.color = 'var(--accent-accent)';
|
||||
}
|
||||
|
||||
const testContent = document.createElement('div');
|
||||
testContent.className = 'test-content';
|
||||
|
||||
if (lesson.testId) {
|
||||
const loadingDiv = document.createElement('div');
|
||||
loadingDiv.className = 'test-details-loading';
|
||||
loadingDiv.textContent = 'Részletek betöltése...';
|
||||
testContent.appendChild(loadingDiv);
|
||||
if (testDetails) {
|
||||
const detailsDiv = document.createElement('div');
|
||||
detailsDiv.className = 'test-details';
|
||||
|
||||
loadTestDetailsFromAPI(lesson.testId).then(testDetails => {
|
||||
loadingDiv.remove();
|
||||
|
||||
if (testDetails) {
|
||||
const detailsDiv = document.createElement('div');
|
||||
detailsDiv.className = 'test-details';
|
||||
|
||||
const nameP = document.createElement('p');
|
||||
const nameStrong = document.createElement('strong');
|
||||
nameStrong.textContent = 'Megnevezés: ';
|
||||
nameP.appendChild(nameStrong);
|
||||
nameP.appendChild(document.createTextNode(testDetails.name));
|
||||
detailsDiv.appendChild(nameP);
|
||||
|
||||
const typeP = document.createElement('p');
|
||||
const typeStrong = document.createElement('strong');
|
||||
typeStrong.textContent = 'Típus: ';
|
||||
typeP.appendChild(typeStrong);
|
||||
typeP.appendChild(document.createTextNode(testDetails.type));
|
||||
detailsDiv.appendChild(typeP);
|
||||
|
||||
const dateP = document.createElement('p');
|
||||
const dateStrong = document.createElement('strong');
|
||||
dateStrong.textContent = 'Bejelentés dátuma: ';
|
||||
dateP.appendChild(dateStrong);
|
||||
dateP.appendChild(document.createTextNode(testDetails.announceDate));
|
||||
detailsDiv.appendChild(dateP);
|
||||
|
||||
testContent.appendChild(detailsDiv);
|
||||
} else {
|
||||
const errorP = document.createElement('p');
|
||||
errorP.className = 'test-details-error';
|
||||
errorP.textContent = 'Nem sikerült betölteni a számonkérés részleteit.';
|
||||
testContent.appendChild(errorP);
|
||||
}
|
||||
}).catch(error => {
|
||||
loadingDiv.remove();
|
||||
const errorP = document.createElement('p');
|
||||
errorP.className = 'test-details-error';
|
||||
errorP.textContent = 'Hiba történt a számonkérés részletek betöltése során.';
|
||||
testContent.appendChild(errorP);
|
||||
});
|
||||
const nameP = document.createElement('p');
|
||||
const nameStrong = document.createElement('strong');
|
||||
nameStrong.textContent = 'Megnevezés: ';
|
||||
nameP.appendChild(nameStrong);
|
||||
nameP.appendChild(document.createTextNode(testDetails.name));
|
||||
detailsDiv.appendChild(nameP);
|
||||
|
||||
const typeP = document.createElement('p');
|
||||
const typeStrong = document.createElement('strong');
|
||||
typeStrong.textContent = 'Típus: ';
|
||||
typeP.appendChild(typeStrong);
|
||||
typeP.appendChild(document.createTextNode(testDetails.type));
|
||||
detailsDiv.appendChild(typeP);
|
||||
|
||||
const dateP = document.createElement('p');
|
||||
const dateStrong = document.createElement('strong');
|
||||
dateStrong.textContent = 'Bejelentés dátuma: ';
|
||||
dateP.appendChild(dateStrong);
|
||||
dateP.appendChild(document.createTextNode(testDetails.announceDate));
|
||||
detailsDiv.appendChild(dateP);
|
||||
|
||||
testContent.appendChild(detailsDiv);
|
||||
} else if (lesson.testId) {
|
||||
const errorP = document.createElement('p');
|
||||
errorP.className = 'test-details-error';
|
||||
errorP.textContent = 'Nem sikerült betölteni a számonkérés részleteit.';
|
||||
testContent.appendChild(errorP);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const lessonKey = getLessonKey(lesson);
|
||||
const customTests = await getCustomTests();
|
||||
const customTestItems = customTests[lessonKey] || [];
|
||||
|
||||
|
||||
if (customTestItems.length > 0) {
|
||||
const customTestsDiv = document.createElement('div');
|
||||
customTestsDiv.className = 'custom-tests-in-section';
|
||||
customTestsDiv.style.marginTop = '1rem';
|
||||
customTestsDiv.style.paddingTop = '1rem';
|
||||
customTestsDiv.style.borderTop = '1px solid var(--background-0)';
|
||||
|
||||
|
||||
const customTestsTitle = document.createElement('h5');
|
||||
customTestsTitle.textContent = 'Saját számonkérések:';
|
||||
customTestsTitle.style.fontSize = '14px';
|
||||
@@ -1280,10 +1408,10 @@
|
||||
customTestsTitle.style.color = 'var(--warning-accent)';
|
||||
customTestsTitle.style.marginBottom = '0.5rem';
|
||||
customTestsDiv.appendChild(customTestsTitle);
|
||||
|
||||
|
||||
const customTestsList = document.createElement('div');
|
||||
customTestsList.className = 'custom-tests-list-integrated';
|
||||
|
||||
|
||||
customTestItems.forEach(test => {
|
||||
const testItem = document.createElement('div');
|
||||
testItem.className = `custom-test-item-integrated ${test.completed ? 'completed' : ''}`;
|
||||
@@ -1295,7 +1423,7 @@
|
||||
testItem.style.background = 'var(--background)';
|
||||
testItem.style.borderRadius = '6px';
|
||||
testItem.style.border = '1px solid var(--background-0)';
|
||||
|
||||
|
||||
const testText = document.createElement('span');
|
||||
testText.className = 'test-text-integrated';
|
||||
testText.textContent = test.text;
|
||||
@@ -1305,12 +1433,12 @@
|
||||
testText.style.textDecoration = 'line-through';
|
||||
testText.style.opacity = '0.6';
|
||||
}
|
||||
|
||||
|
||||
const testActions = document.createElement('div');
|
||||
testActions.className = 'test-actions-integrated';
|
||||
testActions.style.display = 'flex';
|
||||
testActions.style.gap = '0.5rem';
|
||||
|
||||
|
||||
const completeBtn = document.createElement('button');
|
||||
completeBtn.className = 'test-complete-btn-integrated';
|
||||
completeBtn.title = test.completed ? 'Megoldva - kattints a visszavonáshoz' : 'Megoldottként jelöl';
|
||||
@@ -1322,7 +1450,7 @@
|
||||
completeBtn.style.display = 'flex';
|
||||
completeBtn.style.alignItems = 'center';
|
||||
completeBtn.style.justifyContent = 'center';
|
||||
|
||||
|
||||
const completeIcon = document.createElement('img');
|
||||
completeIcon.src = chrome.runtime.getURL('icons/pipa.svg');
|
||||
completeIcon.alt = 'Megoldva';
|
||||
@@ -1335,7 +1463,7 @@
|
||||
completeIcon.style.opacity = '0.5';
|
||||
}
|
||||
completeBtn.appendChild(completeIcon);
|
||||
|
||||
|
||||
const deleteBtn = document.createElement('button');
|
||||
deleteBtn.className = 'test-delete-btn-integrated';
|
||||
deleteBtn.title = 'Törlés';
|
||||
@@ -1347,7 +1475,7 @@
|
||||
deleteBtn.style.display = 'flex';
|
||||
deleteBtn.style.alignItems = 'center';
|
||||
deleteBtn.style.justifyContent = 'center';
|
||||
|
||||
|
||||
const deleteIcon = document.createElement('img');
|
||||
deleteIcon.src = chrome.runtime.getURL('icons/delete.svg');
|
||||
deleteIcon.alt = 'Törlés';
|
||||
@@ -1355,7 +1483,7 @@
|
||||
deleteIcon.style.height = '16px';
|
||||
deleteIcon.style.opacity = '0.5';
|
||||
deleteBtn.appendChild(deleteIcon);
|
||||
|
||||
|
||||
completeBtn.addEventListener('click', async () => {
|
||||
const newCompleted = await toggleCustomTestCompletion(lessonKey, test.id);
|
||||
if (newCompleted) {
|
||||
@@ -1372,30 +1500,30 @@
|
||||
completeBtn.title = 'Megoldottként jelöl';
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
deleteBtn.addEventListener('click', async () => {
|
||||
if (confirm('Biztosan törölni szeretnéd ezt a számonkérést?')) {
|
||||
await removeCustomTest(lessonKey, test.id);
|
||||
testItem.remove();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
testActions.appendChild(completeBtn);
|
||||
testActions.appendChild(deleteBtn);
|
||||
testItem.appendChild(testText);
|
||||
testItem.appendChild(testActions);
|
||||
customTestsList.appendChild(testItem);
|
||||
});
|
||||
|
||||
|
||||
customTestsDiv.appendChild(customTestsList);
|
||||
testContent.appendChild(customTestsDiv);
|
||||
}
|
||||
|
||||
|
||||
testSection.appendChild(testH4);
|
||||
testSection.appendChild(testContent);
|
||||
body.appendChild(testSection);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const lessonKey = getLessonKey(lesson);
|
||||
const customHomework = await getCustomHomework();
|
||||
@@ -1890,6 +2018,24 @@
|
||||
const lessonData = JSON.parse(card.dataset.lesson);
|
||||
await showLessonModal(lessonData);
|
||||
});
|
||||
|
||||
card.addEventListener("mouseenter", () => {
|
||||
const groupId = card.dataset.lessonGroup;
|
||||
if (groupId) {
|
||||
document.querySelectorAll(`[data-lesson-group="${groupId}"]`).forEach(relatedCard => {
|
||||
relatedCard.classList.add('group-hover');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
card.addEventListener("mouseleave", () => {
|
||||
const groupId = card.dataset.lessonGroup;
|
||||
if (groupId) {
|
||||
document.querySelectorAll(`[data-lesson-group="${groupId}"]`).forEach(relatedCard => {
|
||||
relatedCard.classList.remove('group-hover');
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,24 +1,3 @@
|
||||
const SENTRY_DSN = 'https://c7d88b71f550a276f973885a44b6536d@o4510511576055808.ingest.de.sentry.io/4510511935193168';
|
||||
|
||||
async function initSentry() {
|
||||
try {
|
||||
const result = await chrome.storage.sync.get('firka_errorReporting');
|
||||
const enabled = result.firka_errorReporting !== false;
|
||||
|
||||
if (enabled) {
|
||||
self.addEventListener('error', (event) => {
|
||||
console.error('[Background Error]', event.error || event);
|
||||
});
|
||||
|
||||
self.addEventListener('unhandledrejection', (event) => {
|
||||
console.error('[Background Unhandled Rejection]', event.reason);
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[Sentry] Nem sikerült inicializálni:', error);
|
||||
}
|
||||
}
|
||||
|
||||
chrome.runtime.onInstalled.addListener(async (details) => {
|
||||
if (details.reason === 'install') {
|
||||
const setupCompleted = await chrome.storage.sync.get('firka_setupCompleted');
|
||||
@@ -29,8 +8,6 @@ chrome.runtime.onInstalled.addListener(async (details) => {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await initSentry();
|
||||
});
|
||||
|
||||
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||||
@@ -57,6 +34,11 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||||
sendResponse({ success: true });
|
||||
break;
|
||||
|
||||
case 'download_attachment':
|
||||
const downloadResult = await handleDownloadAttachment(request.azonosito, request.fileName);
|
||||
sendResponse(downloadResult);
|
||||
break;
|
||||
|
||||
default:
|
||||
console.warn('[Background] Unknown action:', request.action);
|
||||
sendResponse({ success: false, error: 'Unknown action' });
|
||||
@@ -102,7 +84,7 @@ async function handleStorageClear() {
|
||||
try {
|
||||
const allData = await chrome.storage.sync.get(null);
|
||||
const firkaKeys = Object.keys(allData).filter(key => key.startsWith('firka_'));
|
||||
|
||||
|
||||
if (firkaKeys.length > 0) {
|
||||
await chrome.storage.sync.remove(firkaKeys);
|
||||
}
|
||||
@@ -112,6 +94,82 @@ async function handleStorageClear() {
|
||||
}
|
||||
}
|
||||
|
||||
async function handleDownloadAttachment(azonosito, fileName) {
|
||||
try {
|
||||
const apiUrl = `https://eugyintezes.e-kreta.hu/api/v1/dokumentumok/uzenetek/${azonosito}`;
|
||||
|
||||
const redirectResponse = await fetch(apiUrl, {
|
||||
method: 'GET',
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Accept': 'application/json, text/plain, */*',
|
||||
'x-csrf': '1',
|
||||
'x-uzenet-json-formatum': 'CamelCase',
|
||||
'x-uzenet-lokalizacio': 'hu-HU',
|
||||
'x-uzenet-verzio-szam': '1.2.3'
|
||||
},
|
||||
redirect: 'manual'
|
||||
});
|
||||
|
||||
let fileUrl;
|
||||
if (redirectResponse.type === 'opaqueredirect' || redirectResponse.status === 0) {
|
||||
const followResponse = await fetch(apiUrl, {
|
||||
method: 'GET',
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Accept': 'application/json, text/plain, */*',
|
||||
'x-csrf': '1',
|
||||
'x-uzenet-json-formatum': 'CamelCase',
|
||||
'x-uzenet-lokalizacio': 'hu-HU',
|
||||
'x-uzenet-verzio-szam': '1.2.3'
|
||||
},
|
||||
redirect: 'follow'
|
||||
});
|
||||
|
||||
if (followResponse.ok) {
|
||||
const blob = await followResponse.blob();
|
||||
const base64 = await blobToBase64(blob);
|
||||
return { success: true, data: base64, fileName: fileName };
|
||||
}
|
||||
} else if (redirectResponse.status === 302 || redirectResponse.status === 301) {
|
||||
fileUrl = redirectResponse.headers.get('location');
|
||||
}
|
||||
|
||||
if (fileUrl) {
|
||||
const fileResponse = await fetch(fileUrl, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json, text/plain, */*',
|
||||
'x-csrf': '1',
|
||||
'x-uzenet-json-formatum': 'CamelCase',
|
||||
'x-uzenet-lokalizacio': 'hu-HU',
|
||||
'x-uzenet-verzio-szam': '1.2.3'
|
||||
}
|
||||
});
|
||||
|
||||
if (fileResponse.ok) {
|
||||
const blob = await fileResponse.blob();
|
||||
const base64 = await blobToBase64(blob);
|
||||
return { success: true, data: base64, fileName: fileName };
|
||||
}
|
||||
}
|
||||
|
||||
return { success: false, error: 'Nem sikerült letölteni a mellékletet.' };
|
||||
} catch (error) {
|
||||
console.error('[Background] Attachment download error:', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
function blobToBase64(blob) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = () => resolve(reader.result);
|
||||
reader.onerror = reject;
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
}
|
||||
|
||||
chrome.storage.onChanged.addListener((changes, namespace) => {
|
||||
if (namespace === 'sync') {
|
||||
const firkaChanges = Object.keys(changes).filter(key => key.startsWith('firka_'));
|
||||
|
||||
3
tools/sentry-browser.min.js
vendored
3
tools/sentry-browser.min.js
vendored
File diff suppressed because one or more lines are too long
127
tools/sentry.js
127
tools/sentry.js
@@ -1,127 +0,0 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
const SENTRY_DSN = 'https://c7d88b71f550a276f973885a44b6536d@o4510511576055808.ingest.de.sentry.io/4510511935193168';
|
||||
let sentryInitialized = false;
|
||||
|
||||
async function isErrorReportingEnabled() {
|
||||
try {
|
||||
const result = await chrome.storage.sync.get('firka_errorReporting');
|
||||
return result.firka_errorReporting !== false;
|
||||
} catch (error) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
async function initSentry() {
|
||||
if (sentryInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
const enabled = await isErrorReportingEnabled();
|
||||
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
configureSentry();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
function configureSentry() {
|
||||
try {
|
||||
const SentrySDK = window.Sentry || (typeof Sentry !== 'undefined' ? Sentry : null);
|
||||
|
||||
if (!SentrySDK) {
|
||||
setTimeout(configureSentry, 500);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!SentrySDK.init) {
|
||||
return;
|
||||
}
|
||||
|
||||
const manifest = chrome.runtime.getManifest();
|
||||
|
||||
SentrySDK.init({
|
||||
dsn: SENTRY_DSN,
|
||||
release: `firka-extension@${manifest.version}`,
|
||||
environment: 'production',
|
||||
integrations: [],
|
||||
beforeSend(event, hint) {
|
||||
if (event.request) {
|
||||
delete event.request.cookies;
|
||||
delete event.request.headers;
|
||||
}
|
||||
return event;
|
||||
},
|
||||
});
|
||||
|
||||
sentryInitialized = true;
|
||||
} catch (error) {
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('error', function(event) {
|
||||
if (sentryInitialized) {
|
||||
const SentrySDK = window.Sentry || (typeof Sentry !== 'undefined' ? Sentry : null);
|
||||
if (SentrySDK && SentrySDK.captureException) {
|
||||
SentrySDK.captureException(event.error || new Error(event.message));
|
||||
} else {
|
||||
console.warn('[Sentry] SDK not available for capturing');
|
||||
}
|
||||
} else {
|
||||
console.warn('[Sentry] Not initialized yet, cannot capture error');
|
||||
}
|
||||
}, true);
|
||||
|
||||
window.addEventListener('unhandledrejection', function(event) {
|
||||
if (sentryInitialized) {
|
||||
const SentrySDK = window.Sentry || (typeof Sentry !== 'undefined' ? Sentry : null);
|
||||
if (SentrySDK && SentrySDK.captureException) {
|
||||
SentrySDK.captureException(event.reason);
|
||||
}
|
||||
}
|
||||
}, true);
|
||||
|
||||
if (typeof chrome !== 'undefined' && chrome.storage) {
|
||||
chrome.storage.onChanged.addListener(function(changes, namespace) {
|
||||
if (namespace === 'sync' && changes.firka_errorReporting) {
|
||||
const newValue = changes.firka_errorReporting.newValue;
|
||||
|
||||
if (newValue === false && sentryInitialized) {
|
||||
if (typeof Sentry !== 'undefined' && Sentry.close) {
|
||||
Sentry.close();
|
||||
sentryInitialized = false;
|
||||
}
|
||||
} else if (newValue !== false && !sentryInitialized) {
|
||||
initSentry();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.FirkaSentry = {
|
||||
init: initSentry,
|
||||
isEnabled: isErrorReportingEnabled,
|
||||
captureException: function(error) {
|
||||
if (sentryInitialized) {
|
||||
const SentrySDK = window.Sentry || (typeof Sentry !== 'undefined' ? Sentry : null);
|
||||
if (SentrySDK && SentrySDK.captureException) {
|
||||
SentrySDK.captureException(error);
|
||||
}
|
||||
}
|
||||
},
|
||||
captureMessage: function(message, level = 'info') {
|
||||
if (sentryInitialized) {
|
||||
const SentrySDK = window.Sentry || (typeof Sentry !== 'undefined' ? Sentry : null);
|
||||
if (SentrySDK && SentrySDK.captureMessage) {
|
||||
SentrySDK.captureMessage(message, level);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
initSentry();
|
||||
})();
|
||||
Reference in New Issue
Block a user