mirror of
https://github.com/QwIT-Development/firka-extension.git
synced 2026-06-12 03:41:39 +02:00
1015 lines
37 KiB
JavaScript
1015 lines
37 KiB
JavaScript
(() => {
|
|
async function loadWeekDataFromAPI(startDate, endDate) {
|
|
try {
|
|
const timestamp = Date.now();
|
|
const apiUrl = `https://${window.location.hostname}/api/CalendarApi/GetTanuloOrarend?tanarId=-1&osztalyCsoportId=-1&tanuloId=-1&teremId=-1&kellCsengetesiRendMegjelenites=false&csakOrarendiOra=false&kellTanoranKivuliFoglalkozasok=false&kellTevekenysegek=false&kellTanevRendje=true&szuresTanevRendjeAlapjan=false&kellOraTemaTooltip=True&start=${startDate}&end=${endDate}&_=${timestamp}`;
|
|
|
|
const response = await fetch(apiUrl, {
|
|
credentials: 'include',
|
|
headers: {
|
|
'Accept': 'application/json',
|
|
'X-Requested-With': 'XMLHttpRequest'
|
|
}
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`${LanguageManager.t('common.api_error')}: ${response.status}`);
|
|
}
|
|
|
|
return await response.json();
|
|
} catch (error) {
|
|
console.error(LanguageManager.t('common.api_load_error'), error);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
function generateWeekDates(startDate) {
|
|
const start = new Date(startDate);
|
|
const dates = [];
|
|
const dayNames = [LanguageManager.t('common.monday'), LanguageManager.t('common.tuesday'), LanguageManager.t('common.wednesday'), LanguageManager.t('common.thursday'), LanguageManager.t('common.friday')];
|
|
|
|
for (let i = 0; i < 5; i++) {
|
|
const date = new Date(start);
|
|
date.setDate(start.getDate() + i);
|
|
|
|
const month = date.toLocaleDateString('hu-HU', { month: 'short' });
|
|
const day = date.getDate();
|
|
|
|
dates.push({
|
|
date: `${dayNames[i]} ${month} ${day}.`,
|
|
formattedDate: `${month} ${day}.`,
|
|
fullDate: date.toISOString().split('T')[0]
|
|
});
|
|
}
|
|
|
|
return dates;
|
|
}
|
|
|
|
function convertAPIDataToLessons(apiData, weekDates) {
|
|
const lessons = [];
|
|
apiData.forEach((event, index) => {
|
|
try {
|
|
const eventDate = new Date(event.start);
|
|
const dayIndex = weekDates.findIndex(date =>
|
|
new Date(date.fullDate).toDateString() === eventDate.toDateString()
|
|
);
|
|
|
|
if (dayIndex === -1) {
|
|
return;
|
|
}
|
|
|
|
if (event.oraType === 5) {
|
|
const lesson = {
|
|
startTime: LanguageManager.t('timetable.all_day'),
|
|
endTime: '',
|
|
subject: event.title || 'Különleges nap',
|
|
teacher: '',
|
|
originalTeacher: '',
|
|
room: '',
|
|
day: dayIndex,
|
|
isSubstituted: false,
|
|
isCancelled: false,
|
|
hasHomework: false,
|
|
testInfo: event.Tema || '',
|
|
homeworkDetails: '',
|
|
isSpecialDay: true,
|
|
color: event.color
|
|
};
|
|
lessons.push(lesson);
|
|
} else if (event.oraType === 2 || event.oraType === 1 || event.oraType === 3 || event.oraType === 4) {
|
|
const startTime = new Date(event.start);
|
|
const endTime = new Date(event.end);
|
|
const startTimeStr = startTime.toLocaleTimeString('hu-HU', { hour: '2-digit', minute: '2-digit' });
|
|
const endTimeStr = endTime.toLocaleTimeString('hu-HU', { hour: '2-digit', minute: '2-digit' });
|
|
const titleParts = event.title ? event.title.split('\n') : [];
|
|
const teacher = titleParts[1] || '';
|
|
const room = titleParts[2] ? titleParts[2].replace(/[()]/g, '') : '';
|
|
const subject = event.Tantargy || event.TantargyKategoria || titleParts[0] || 'Ismeretlen tantárgy';
|
|
|
|
if (startTimeStr && subject) {
|
|
const lesson = {
|
|
startTime: startTimeStr,
|
|
endTime: endTimeStr,
|
|
subject: subject,
|
|
teacher: teacher,
|
|
originalTeacher: event.helyettesitoId ? teacher : '',
|
|
room: room,
|
|
day: dayIndex,
|
|
isSubstituted: !!event.helyettesitoId,
|
|
isCancelled: event.isElmaradt || false,
|
|
hasHomework: event.hasHaziFeladat || false,
|
|
testInfo: event.hasBejelentettSzamonkeres ? (event.Tema || LanguageManager.t('timetable.test_indicator')) : '',
|
|
homeworkDetails: '',
|
|
isSpecialDay: false,
|
|
color: event.color
|
|
};
|
|
lessons.push(lesson);
|
|
} else {
|
|
}
|
|
} else {
|
|
}
|
|
} catch (error) {
|
|
console.error(`Hiba az API feldolgozása során (${index}):`, error, event);
|
|
}
|
|
});
|
|
return lessons;
|
|
}
|
|
|
|
function generateTimeGrid(lessons, weekDates) {
|
|
const specialDayLessons = lessons.filter(l => l.isSpecialDay);
|
|
const regularLessons = lessons.filter(l => !l.isSpecialDay);
|
|
|
|
const times = [...new Set(regularLessons.map(l => l.startTime))].sort((a, b) => {
|
|
const timeA = helper.convertTimeToMinutes(a);
|
|
const timeB = helper.convertTimeToMinutes(b);
|
|
return timeA - timeB;
|
|
});
|
|
const days = [
|
|
LanguageManager.t('timetable.monday'),
|
|
LanguageManager.t('timetable.tuesday'),
|
|
LanguageManager.t('timetable.wednesday'),
|
|
LanguageManager.t('timetable.thursday'),
|
|
LanguageManager.t('timetable.friday')
|
|
];
|
|
|
|
return `
|
|
<div class="grid-header"></div>
|
|
${days.map((day, index) => {
|
|
return `
|
|
<div class="grid-header">
|
|
<span class="day-name">${day}</span>
|
|
<span class="day-date">${weekDates[index]?.formattedDate || ''}</span>
|
|
</div>
|
|
`;
|
|
}).join('')}
|
|
${times.map((time, timeIndex) => `
|
|
<div class="time-slot">${time}</div>
|
|
${Array(5).fill().map((_, dayIndex) => {
|
|
const dayLessons = regularLessons.filter(l => l.startTime === time && l.day === dayIndex);
|
|
const specialDay = specialDayLessons.find(l => l.day === dayIndex);
|
|
|
|
return `
|
|
<div class="lesson-slot ${specialDay ? 'special-day-slot' : ''}">
|
|
${specialDay && timeIndex === 0 ? `
|
|
<div class="special-day-card" style="background-color: ${specialDay.color || '#F99F50'}" data-lesson='${JSON.stringify(specialDay)}'>
|
|
<div class="special-day-title">${specialDay.subject}</div>
|
|
${specialDay.testInfo ? `<div class="special-day-subtitle">${specialDay.testInfo}</div>` : ''}
|
|
</div>
|
|
` : dayLessons.map(lesson => `
|
|
<div class="lesson-card ${lesson.isSubstituted ? 'substituted' : ''}
|
|
${lesson.isCancelled ? 'cancelled' : ''}
|
|
${lesson.hasHomework ? 'has-homework' : ''}"
|
|
data-lesson='${JSON.stringify(lesson)}'>
|
|
<div class="lesson-subject">${lesson.subject}</div>
|
|
<div class="lesson-teacher">${lesson.teacher}</div>
|
|
<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>
|
|
${lesson.hasHomework || lesson.testInfo ? `
|
|
<div class="lesson-indicators">
|
|
${lesson.hasHomework ? `
|
|
<span class="lesson-indicator homework-indicator" title="${LanguageManager.t('timetable.homework_indicator')}">
|
|
<span class="material-icons-round">assignment</span>
|
|
</span>
|
|
` : ''}
|
|
${lesson.testInfo ? `
|
|
<span class="lesson-indicator test-indicator" title="${LanguageManager.t('timetable.test_indicator')}">
|
|
<span class="material-icons-round">quiz</span>
|
|
</span>
|
|
` : ''}
|
|
</div>
|
|
` : ''}
|
|
</div>
|
|
`).join('')}
|
|
</div>
|
|
`;
|
|
}).join('')}
|
|
`).join('')}
|
|
`;
|
|
}
|
|
function showLessonModal(lesson) {
|
|
const modal = document.createElement('div');
|
|
modal.className = 'lesson-modal';
|
|
modal.innerHTML = `
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h3 class="modal-title">${lesson.subject}</h3>
|
|
<button class="modal-close">
|
|
<span class="material-icons-round">close</span>
|
|
</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="lesson-details">
|
|
<div class="detail-item">
|
|
<span class="detail-label">${LanguageManager.t('timetable.teacher_label')}</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">${LanguageManager.t('timetable.substitute_teacher_label')}</span>
|
|
<span class="detail-value">${lesson.teacher.replace('Helyettesítő:', '')}</span>
|
|
</div>
|
|
<div class="detail-item">
|
|
<span class="detail-label">${LanguageManager.t('timetable.classroom_label')}</span>
|
|
<span class="detail-value">${lesson.room}</span>
|
|
</div>
|
|
<div class="detail-item">
|
|
<span class="detail-label">${LanguageManager.t('timetable.time_label')}</span>
|
|
<span class="detail-value">${lesson.startTime} - ${lesson.endTime}</span>
|
|
</div>
|
|
${lesson.isSubstituted ? `
|
|
<div class="detail-item">
|
|
<span class="detail-label">${LanguageManager.t('timetable.status_label')}</span>
|
|
<span class="detail-value"><span class="material-icons-round">sync_alt</span> ${LanguageManager.t('timetable.substitution')}</span>
|
|
</div>
|
|
` : ''}
|
|
${lesson.isCancelled ? `
|
|
<div class="detail-item">
|
|
<span class="detail-label">${LanguageManager.t('timetable.status_label')}</span>
|
|
<span class="detail-value"><span class="material-icons-round">cancel</span> ${LanguageManager.t('timetable.cancelled')}</span>
|
|
</div>
|
|
` : ''}
|
|
</div>
|
|
|
|
${lesson.hasHomework ? `
|
|
<div class="modal-section homework-section">
|
|
<h4>
|
|
<span class="material-icons-round">assignment</span>
|
|
${LanguageManager.t('timetable.homework_indicator')}
|
|
</h4>
|
|
<div class="homework-content">
|
|
${lesson.homeworkDetails ? `<p>${lesson.homeworkDetails}</p>` : `<p>${LanguageManager.t('timetable.has_homework')}</p>`}
|
|
<a href='https://${window.location.hostname}/Tanulo/TanuloHaziFeladat' class="more-link">
|
|
${LanguageManager.t('timetable.open_homework')}
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="17" viewBox="0 0 16 17" fill="none">
|
|
<path d="M11.2997 5.19947L5.64282 5.19947M11.2997 5.19947L11.2997 10.8563M11.2997 5.19947L4.70001 11.7991" stroke="var(--accent-accent)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
|
|
</svg>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
` : ''}
|
|
${lesson.testInfo ? `
|
|
<div class="modal-section test-section">
|
|
<h4>
|
|
<span class="material-icons-round">quiz</span>
|
|
${LanguageManager.t('timetable.test_indicator')}
|
|
</h4>
|
|
<div class="test-content">
|
|
<p>${lesson.testInfo}</p>
|
|
</div>
|
|
</div>
|
|
` : ''}
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
document.body.appendChild(modal);
|
|
|
|
const closeModal = () => {
|
|
modal.classList.remove('show');
|
|
setTimeout(() => modal.remove(), 300);
|
|
};
|
|
|
|
modal.querySelector('.modal-close').addEventListener('click', closeModal);
|
|
modal.addEventListener('click', (e) => {
|
|
if (e.target === modal) closeModal();
|
|
});
|
|
|
|
const handleEscape = (e) => {
|
|
if (e.key === 'Escape') {
|
|
closeModal();
|
|
document.removeEventListener('keydown', handleEscape);
|
|
}
|
|
};
|
|
document.addEventListener('keydown', handleEscape);
|
|
|
|
requestAnimationFrame(() => {
|
|
modal.classList.add('show');
|
|
});
|
|
}
|
|
|
|
async function loadAndDisplayWeek(weekOption) {
|
|
try {
|
|
loadingScreen.show();
|
|
let startDate, endDate;
|
|
if (weekOption.startDate && weekOption.endDate) {
|
|
startDate = weekOption.startDate;
|
|
endDate = weekOption.endDate;
|
|
} else {
|
|
const weekText = weekOption.text;
|
|
const dateMatch = weekText.match(/(\d{4})\.(\d{2})\.(\d{2})/);
|
|
|
|
if (!dateMatch) {
|
|
console.error(LanguageManager.t('timetable.date_extract_error'), weekText);
|
|
return;
|
|
}
|
|
const [, year, month, day] = dateMatch;
|
|
startDate = `${year}-${month}-${day}`;
|
|
const start = new Date(startDate);
|
|
const end = new Date(start);
|
|
end.setDate(start.getDate() + 6);
|
|
endDate = end.toISOString().split('T')[0];
|
|
}
|
|
const apiData = await loadWeekDataFromAPI(startDate, endDate);
|
|
const weekDates = generateWeekDates(startDate);
|
|
const kendoCombo = document.querySelector('#Calendar_tanevHetek')?.__kendoWidget;
|
|
if (kendoCombo) {
|
|
kendoCombo.value(weekOption.value);
|
|
kendoCombo.trigger('change');
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
}
|
|
|
|
const apiLessons = convertAPIDataToLessons(apiData, weekDates);
|
|
const allLessons = apiLessons;
|
|
const timetableGrid = document.querySelector('.timetable-grid');
|
|
if (timetableGrid) {
|
|
timetableGrid.innerHTML = generateTimeGrid(allLessons, weekDates);
|
|
setupLessonCardListeners();
|
|
}
|
|
|
|
const weekSelect = document.querySelector('.week-select');
|
|
if (weekSelect) {
|
|
weekSelect.value = weekOption.value;
|
|
}
|
|
|
|
setupDayNavigation(weekDates);
|
|
|
|
} catch (error) {
|
|
console.error(LanguageManager.t('timetable.week_load_error'), error);
|
|
} finally {
|
|
loadingScreen.hide();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function setupLessonCardListeners() {
|
|
document.querySelectorAll('.lesson-card').forEach(card => {
|
|
card.addEventListener('click', () => {
|
|
const lessonData = JSON.parse(card.dataset.lesson);
|
|
showLessonModal(lessonData);
|
|
});
|
|
});
|
|
}
|
|
|
|
function setupEventListeners(data) {
|
|
setupLessonCardListeners();
|
|
setupDayNavigation(data.weekDates);
|
|
|
|
const weekGrid = document.getElementById('week-grid');
|
|
const weekTooltip = document.getElementById('week-tooltip');
|
|
|
|
if (weekGrid && weekTooltip) {
|
|
weekGrid.addEventListener('click', async (e) => {
|
|
if (e.target.classList.contains('week-cell')) {
|
|
const weekValue = e.target.dataset.week;
|
|
const weekOption = data.weekInfo.options.find(opt => opt.value === weekValue);
|
|
|
|
if (weekOption) {
|
|
document.querySelectorAll('.week-cell.selected').forEach(cell => {
|
|
cell.classList.remove('selected');
|
|
});
|
|
|
|
e.target.classList.add('selected');
|
|
|
|
await loadAndDisplayWeek(weekOption);
|
|
}
|
|
}
|
|
});
|
|
|
|
weekGrid.addEventListener('mouseover', (e) => {
|
|
if (e.target.classList.contains('week-cell')) {
|
|
const startDate = e.target.dataset.start;
|
|
const endDate = e.target.dataset.end;
|
|
const weekNum = e.target.dataset.week;
|
|
|
|
if (startDate && endDate) {
|
|
const startFormatted = formatDateHU(new Date(startDate));
|
|
const endFormatted = formatDateHU(new Date(endDate));
|
|
weekTooltip.textContent = `${weekNum}. hét: ${startFormatted} - ${endFormatted}`;
|
|
const rect = e.target.getBoundingClientRect();
|
|
const containerRect = weekGrid.getBoundingClientRect();
|
|
|
|
weekTooltip.style.left = `${rect.left - containerRect.left + rect.width / 2}px`;
|
|
weekTooltip.style.top = `${rect.top - containerRect.top - 40}px`;
|
|
weekTooltip.style.transform = 'translateX(-50%)';
|
|
weekTooltip.classList.add('show');
|
|
}
|
|
}
|
|
});
|
|
|
|
weekGrid.addEventListener('mouseout', (e) => {
|
|
if (e.target.classList.contains('week-cell')) {
|
|
weekTooltip.classList.remove('show');
|
|
}
|
|
});
|
|
}
|
|
|
|
const expandBtn = document.getElementById('expandWeekView');
|
|
const modal = document.getElementById('weekModal');
|
|
const closeBtn = document.getElementById('closeWeekModal');
|
|
const modalGrid = document.getElementById('weekModalGrid');
|
|
|
|
if (expandBtn && modal && closeBtn && modalGrid) {
|
|
expandBtn.addEventListener('click', () => {
|
|
generateFullYearWeeks(modalGrid, data);
|
|
modal.style.display = 'flex';
|
|
document.body.style.overflow = 'hidden';
|
|
});
|
|
|
|
closeBtn.addEventListener('click', () => {
|
|
modal.style.display = 'none';
|
|
document.body.style.overflow = 'auto';
|
|
});
|
|
|
|
modal.addEventListener('click', (e) => {
|
|
if (e.target === modal) {
|
|
modal.style.display = 'none';
|
|
document.body.style.overflow = 'auto';
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
let dayNavigationState = {
|
|
currentDayIndex: 0,
|
|
isInitialized: false
|
|
};
|
|
|
|
function setupDayNavigation(weekDates) {
|
|
const days = [
|
|
LanguageManager.t('timetable.monday'),
|
|
LanguageManager.t('timetable.tuesday'),
|
|
LanguageManager.t('timetable.wednesday'),
|
|
LanguageManager.t('timetable.thursday'),
|
|
LanguageManager.t('timetable.friday')
|
|
];
|
|
|
|
const prevBtn = document.getElementById('prevDay');
|
|
const nextBtn = document.getElementById('nextDay');
|
|
const currentDayName = document.getElementById('currentDayName');
|
|
const currentDayDate = document.getElementById('currentDayDate');
|
|
|
|
if (!dayNavigationState.isInitialized) {
|
|
const today = new Date();
|
|
const dayOfWeek = today.getDay();
|
|
let currentDayIndex = 0;
|
|
if (dayOfWeek >= 1 && dayOfWeek <= 5) {
|
|
currentDayIndex = dayOfWeek - 1;
|
|
} else {
|
|
currentDayIndex = 0;
|
|
}
|
|
|
|
dayNavigationState.currentDayIndex = currentDayIndex;
|
|
} else {
|
|
const preservedDayIndex = dayNavigationState.currentDayIndex;
|
|
dayNavigationState.currentDayIndex = preservedDayIndex;
|
|
updateDayDisplay();
|
|
return;
|
|
}
|
|
|
|
function updateDayDisplay() {
|
|
if (currentDayName && currentDayDate) {
|
|
currentDayName.textContent = days[dayNavigationState.currentDayIndex];
|
|
currentDayDate.textContent = weekDates[dayNavigationState.currentDayIndex]?.formattedDate || '';
|
|
}
|
|
|
|
const gridHeaders = document.querySelectorAll('.grid-header:not(:first-child)');
|
|
const lessonSlots = document.querySelectorAll('.lesson-slot');
|
|
|
|
gridHeaders.forEach((header, index) => {
|
|
header.classList.toggle('active', index === dayNavigationState.currentDayIndex);
|
|
});
|
|
|
|
const timeSlots = document.querySelectorAll('.time-slot');
|
|
timeSlots.forEach((timeSlot, timeIndex) => {
|
|
const startIndex = timeIndex * 5;
|
|
lessonSlots.forEach((slot, slotIndex) => {
|
|
const dayIndex = (slotIndex - startIndex) % 5;
|
|
if (slotIndex >= startIndex && slotIndex < startIndex + 5) {
|
|
slot.classList.toggle('active', dayIndex === dayNavigationState.currentDayIndex);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
if (prevBtn && nextBtn && !dayNavigationState.isInitialized) {
|
|
prevBtn.addEventListener('click', () => {
|
|
if (dayNavigationState.currentDayIndex > 0) {
|
|
dayNavigationState.currentDayIndex--;
|
|
updateDayDisplay();
|
|
}
|
|
});
|
|
|
|
nextBtn.addEventListener('click', () => {
|
|
if (dayNavigationState.currentDayIndex < days.length - 1) {
|
|
dayNavigationState.currentDayIndex++;
|
|
updateDayDisplay();
|
|
}
|
|
});
|
|
|
|
dayNavigationState.isInitialized = true;
|
|
}
|
|
|
|
updateDayDisplay();
|
|
}
|
|
|
|
function getWeekNumber(date) {
|
|
const currentDate = new Date(date);
|
|
const currentYear = currentDate.getFullYear();
|
|
const currentMonth = currentDate.getMonth();
|
|
let schoolYearStart;
|
|
if (currentMonth >= 8) {
|
|
schoolYearStart = new Date(currentYear, 8, 1);
|
|
} else {
|
|
schoolYearStart = new Date(currentYear - 1, 8, 1);
|
|
}
|
|
const timeDiff = currentDate.getTime() - schoolYearStart.getTime();
|
|
const daysDiff = Math.floor(timeDiff / (1000 * 60 * 60 * 24));
|
|
const weekNumber = Math.floor(daysDiff / 7) + 1;
|
|
return Math.max(1, Math.min(52, weekNumber));
|
|
}
|
|
|
|
function getDateOfWeek(year, week, dayOfWeek) {
|
|
const jan4 = new Date(year, 0, 4);
|
|
const jan4DayOfWeek = jan4.getDay() || 7;
|
|
const daysToAdd = (week - 1) * 7 + (dayOfWeek - jan4DayOfWeek);
|
|
const result = new Date(jan4);
|
|
result.setDate(jan4.getDate() + daysToAdd);
|
|
return result;
|
|
}
|
|
|
|
function formatDateHU(date) {
|
|
const year = date.getFullYear();
|
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
const day = String(date.getDate()).padStart(2, '0');
|
|
return `${year}.${month}.${day}.`;
|
|
}
|
|
|
|
function generateWeekOptions() {
|
|
const options = [];
|
|
const today = new Date();
|
|
|
|
for (let offset = -2; offset <= 2; offset++) {
|
|
const targetDate = new Date(today);
|
|
targetDate.setDate(today.getDate() + (offset * 7));
|
|
const dayOfWeek = targetDate.getDay();
|
|
const daysToMonday = dayOfWeek === 0 ? -6 : 1 - dayOfWeek;
|
|
const weekStart = new Date(targetDate);
|
|
weekStart.setDate(targetDate.getDate() + daysToMonday);
|
|
|
|
const weekEnd = new Date(weekStart);
|
|
weekEnd.setDate(weekStart.getDate() + 6);
|
|
|
|
const weekNumber = getWeekNumber(weekStart);
|
|
|
|
const startDateFormatted = formatDateHU(weekStart);
|
|
const endDateFormatted = formatDateHU(weekEnd);
|
|
|
|
const startDate = weekStart.toISOString().split('T')[0];
|
|
const endDate = weekEnd.toISOString().split('T')[0];
|
|
|
|
options.push({
|
|
text: `${weekNumber}. hét (${startDateFormatted} - ${endDateFormatted})`,
|
|
value: weekNumber.toString(),
|
|
selected: offset === 0,
|
|
startDate: startDate,
|
|
endDate: endDate
|
|
});
|
|
}
|
|
|
|
return options;
|
|
}
|
|
|
|
function generateFullYearWeeks(modalGrid, data) {
|
|
const today = new Date();
|
|
const currentYear = today.getFullYear();
|
|
const currentMonth = today.getMonth();
|
|
|
|
let schoolYearStart;
|
|
if (currentMonth >= 8) {
|
|
schoolYearStart = new Date(currentYear, 8, 1);
|
|
} else {
|
|
schoolYearStart = new Date(currentYear - 1, 8, 1);
|
|
}
|
|
|
|
const currentWeekNumber = getWeekNumber(today);
|
|
const allWeeks = [];
|
|
|
|
for (let weekNum = 1; weekNum <= 52; weekNum++) {
|
|
const weekStart = new Date(schoolYearStart);
|
|
const sept1DayOfWeek = schoolYearStart.getDay();
|
|
const daysToMonday = sept1DayOfWeek === 0 ? 1 : (8 - sept1DayOfWeek) % 7;
|
|
if (weekNum === 1) {
|
|
weekStart.setDate(schoolYearStart.getDate() - daysToMonday);
|
|
} else {
|
|
weekStart.setDate(schoolYearStart.getDate() - daysToMonday + (weekNum - 1) * 7);
|
|
}
|
|
|
|
const weekEnd = new Date(weekStart);
|
|
weekEnd.setDate(weekStart.getDate() + 6);
|
|
|
|
const startDateFormatted = formatDateHU(weekStart);
|
|
const endDateFormatted = formatDateHU(weekEnd);
|
|
|
|
const startDate = weekStart.toISOString().split('T')[0];
|
|
const endDate = weekEnd.toISOString().split('T')[0];
|
|
|
|
allWeeks.push({
|
|
text: `${weekNum}. hét (${startDateFormatted} - ${endDateFormatted})`,
|
|
value: weekNum.toString(),
|
|
selected: weekNum === currentWeekNumber,
|
|
startDate: startDate,
|
|
endDate: endDate
|
|
});
|
|
}
|
|
|
|
modalGrid.innerHTML = allWeeks.map(week => `
|
|
<div class="week-cell ${week.selected ? 'selected' : ''}"
|
|
data-week="${week.value}"
|
|
data-start="${week.startDate}"
|
|
data-end="${week.endDate}"
|
|
title="${week.text}">
|
|
${week.value}
|
|
</div>
|
|
`).join('');
|
|
modalGrid.addEventListener('click', async (e) => {
|
|
if (e.target.classList.contains('week-cell')) {
|
|
const weekValue = e.target.dataset.week;
|
|
const weekOption = allWeeks.find(opt => opt.value === weekValue);
|
|
|
|
if (weekOption) {
|
|
document.getElementById('weekModal').style.display = 'none';
|
|
document.body.style.overflow = 'auto';
|
|
|
|
document.querySelectorAll('#week-grid .week-cell.selected').forEach(cell => {
|
|
cell.classList.remove('selected');
|
|
});
|
|
|
|
await loadAndDisplayWeek(weekOption);
|
|
|
|
const newWeekOptions = generateWeekOptionsAroundWeek(parseInt(weekValue));
|
|
updateMainWeekGrid(newWeekOptions);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
function generateWeekOptionsAroundWeek(targetWeekNumber) {
|
|
const options = [];
|
|
const today = new Date();
|
|
const currentYear = today.getFullYear();
|
|
const currentMonth = today.getMonth();
|
|
|
|
let schoolYearStart;
|
|
if (currentMonth >= 8) {
|
|
schoolYearStart = new Date(currentYear, 8, 1);
|
|
} else {
|
|
schoolYearStart = new Date(currentYear - 1, 8, 1);
|
|
}
|
|
for (let offset = -2; offset <= 2; offset++) {
|
|
const weekNum = Math.max(1, Math.min(52, targetWeekNumber + offset));
|
|
const weekStart = new Date(schoolYearStart);
|
|
const sept1DayOfWeek = schoolYearStart.getDay();
|
|
const daysToMonday = sept1DayOfWeek === 0 ? 1 : (8 - sept1DayOfWeek) % 7;
|
|
if (weekNum === 1) {
|
|
weekStart.setDate(schoolYearStart.getDate() - daysToMonday);
|
|
} else {
|
|
weekStart.setDate(schoolYearStart.getDate() - daysToMonday + (weekNum - 1) * 7);
|
|
}
|
|
|
|
const weekEnd = new Date(weekStart);
|
|
weekEnd.setDate(weekStart.getDate() + 6);
|
|
|
|
const startDateFormatted = formatDateHU(weekStart);
|
|
const endDateFormatted = formatDateHU(weekEnd);
|
|
|
|
const startDate = weekStart.toISOString().split('T')[0];
|
|
const endDate = weekEnd.toISOString().split('T')[0];
|
|
|
|
options.push({
|
|
text: `${weekNum}. hét (${startDateFormatted} - ${endDateFormatted})`,
|
|
value: weekNum.toString(),
|
|
selected: weekNum === targetWeekNumber,
|
|
startDate: startDate,
|
|
endDate: endDate
|
|
});
|
|
}
|
|
|
|
return options;
|
|
}
|
|
|
|
function updateMainWeekGrid(newWeekOptions) {
|
|
const weekGrid = document.getElementById('week-grid');
|
|
if (weekGrid) {
|
|
weekGrid.innerHTML = newWeekOptions.map(opt => `
|
|
<div class="week-cell ${opt.selected ? 'selected' : ''}"
|
|
data-week="${opt.value}"
|
|
data-start="${opt.startDate}"
|
|
data-end="${opt.endDate}"
|
|
title="${opt.text}">
|
|
${opt.value}
|
|
</div>
|
|
`).join('');
|
|
}
|
|
}
|
|
|
|
async function transformTimetablePage() {
|
|
try {
|
|
const weekOptions = generateWeekOptions();
|
|
const currentWeekOption = weekOptions.find(opt => opt.selected);
|
|
const today = new Date();
|
|
const startOfWeek = new Date(today);
|
|
startOfWeek.setDate(today.getDate() - today.getDay() + 1);
|
|
const endOfWeek = new Date(startOfWeek);
|
|
endOfWeek.setDate(startOfWeek.getDate() + 6);
|
|
const startDate = startOfWeek.toISOString().split('T')[0];
|
|
const endDate = endOfWeek.toISOString().split('T')[0];
|
|
const apiData = await loadWeekDataFromAPI(startDate, endDate);
|
|
const weekDates = generateWeekDates(startDate);
|
|
const lessons = convertAPIDataToLessons(apiData, weekDates);
|
|
const data = {
|
|
schoolInfo: {
|
|
name: cookieManager.get('schoolName') || 'Iskola',
|
|
id: cookieManager.get('schoolCode') || ''
|
|
},
|
|
userData: {
|
|
name: cookieManager.get('userName') || 'Felhasználó',
|
|
time: '45:00'
|
|
},
|
|
weekInfo: {
|
|
title: LanguageManager.t('timetable.week'),
|
|
options: weekOptions
|
|
},
|
|
weekDates: weekDates,
|
|
lessons: lessons
|
|
};
|
|
|
|
document.body.innerHTML = `
|
|
<div class="kreta-container">
|
|
${createTemplate.header()}
|
|
|
|
<main class="kreta-main">
|
|
<div class="week-controls">
|
|
<div class="week-selector-container">
|
|
<div class="week-selector" id="week-selector">
|
|
<button class="week-nav-btn" id="prevWeekBtn" title="Előző hét">
|
|
<span class="material-icons-round">chevron_left</span>
|
|
</button>
|
|
<div class="week-display" id="week-display">
|
|
<!-- Will be populated with 5 weeks -->
|
|
</div>
|
|
<button class="week-nav-btn" id="nextWeekBtn" title="Következő hét">
|
|
<span class="material-icons-round">chevron_right</span>
|
|
</button>
|
|
<button class="expand-week-view-btn" id="expandWeekView" title="Teljes nézet">
|
|
<span class="material-icons-round">open_in_full</span>
|
|
</button>
|
|
</div>
|
|
<div class="week-tooltip" id="week-tooltip"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Modal for expanded week view -->
|
|
<div class="week-modal" id="weekModal" style="display: none;">
|
|
<div class="week-modal-content">
|
|
<div class="week-modal-header">
|
|
<h3>Hét választó - Teljes nézet</h3>
|
|
<button class="week-modal-close" id="closeWeekModal">
|
|
<span class="material-icons-round">close</span>
|
|
</button>
|
|
</div>
|
|
<div class="week-modal-grid" id="weekModalGrid">
|
|
<!-- Will be populated with all 52 weeks -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="day-navigation">
|
|
<button class="day-nav-btn" id="prevDay">
|
|
<span class="material-icons-round">chevron_left</span>
|
|
Előző
|
|
</button>
|
|
<button class="day-nav-btn" id="nextDay">
|
|
Következő
|
|
<span class="material-icons-round">chevron_right</span>
|
|
</button>
|
|
</div>
|
|
|
|
<div class="timetable-container">
|
|
<div class="timetable-grid">
|
|
${generateTimeGrid(data.lessons, data.weekDates)}
|
|
</div>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
`;
|
|
|
|
createTemplate.importFonts();
|
|
setupUserDropdown();
|
|
setupMobileNavigation();
|
|
setupEventListeners(data);
|
|
initializeWeekSelector(data.weekInfo.options);
|
|
|
|
loadingScreen.hide();
|
|
|
|
} catch (error) {
|
|
console.error(LanguageManager.t('timetable.page_transform_error'), error);
|
|
loadingScreen.hide();
|
|
}
|
|
}
|
|
|
|
let currentWeekIndex = 0;
|
|
let allWeekOptions = [];
|
|
|
|
function initializeWeekSelector(weekOptions) {
|
|
allWeekOptions = weekOptions;
|
|
const today = new Date();
|
|
const currentWeekNumber = getWeekNumber(today);
|
|
currentWeekIndex = allWeekOptions.findIndex(opt => parseInt(opt.value) === currentWeekNumber);
|
|
if (currentWeekIndex === -1) {
|
|
currentWeekIndex = Math.floor(allWeekOptions.length / 2);
|
|
}
|
|
|
|
updateWeekDisplay();
|
|
setupWeekNavigation();
|
|
}
|
|
|
|
function updateWeekDisplay() {
|
|
const weekDisplay = document.getElementById('week-display');
|
|
if (!weekDisplay) return;
|
|
let startIndex = currentWeekIndex - 2;
|
|
if (startIndex < 0) {
|
|
startIndex = 0;
|
|
}
|
|
else if (startIndex + 5 > allWeekOptions.length) {
|
|
startIndex = Math.max(0, allWeekOptions.length - 5);
|
|
}
|
|
|
|
const endIndex = Math.min(allWeekOptions.length, startIndex + 5);
|
|
const visibleWeeks = allWeekOptions.slice(startIndex, startIndex + 5);
|
|
|
|
const today = new Date();
|
|
const currentWeekNumber = getWeekNumber(today);
|
|
|
|
weekDisplay.innerHTML = visibleWeeks.map((opt, index) => {
|
|
const weekNumber = parseInt(opt.value);
|
|
const isSelected = startIndex + index === currentWeekIndex;
|
|
const isCurrent = weekNumber === currentWeekNumber;
|
|
|
|
return `
|
|
<div class="week-cell ${isSelected ? 'selected' : ''} ${isCurrent ? 'current-week' : ''}"
|
|
data-week="${opt.value}"
|
|
data-start="${opt.startDate}"
|
|
data-end="${opt.endDate}"
|
|
data-index="${startIndex + index}"
|
|
title="${opt.text}${isCurrent ? ' (Jelenlegi hét)' : ''}">
|
|
<span class="week-number">${opt.value}</span>
|
|
${isCurrent ? '<span class="current-indicator">●</span>' : ''}
|
|
</div>
|
|
`;
|
|
}).join('');
|
|
}
|
|
|
|
function setupWeekNavigation() {
|
|
const prevBtn = document.getElementById('prevWeekBtn');
|
|
const nextBtn = document.getElementById('nextWeekBtn');
|
|
const expandBtn = document.getElementById('expandWeekView');
|
|
|
|
if (prevBtn) {
|
|
prevBtn.addEventListener('click', () => {
|
|
if (currentWeekIndex > 0) {
|
|
currentWeekIndex--;
|
|
updateWeekDisplay();
|
|
loadAndDisplayWeek(allWeekOptions[currentWeekIndex]);
|
|
}
|
|
});
|
|
}
|
|
|
|
if (nextBtn) {
|
|
nextBtn.addEventListener('click', () => {
|
|
if (currentWeekIndex < allWeekOptions.length - 1) {
|
|
currentWeekIndex++;
|
|
updateWeekDisplay();
|
|
loadAndDisplayWeek(allWeekOptions[currentWeekIndex]);
|
|
}
|
|
});
|
|
}
|
|
|
|
if (expandBtn) {
|
|
expandBtn.addEventListener('click', () => {
|
|
openWeekModal();
|
|
});
|
|
}
|
|
document.addEventListener('click', (e) => {
|
|
if (e.target.closest('.week-cell')) {
|
|
const weekCell = e.target.closest('.week-cell');
|
|
const weekIndex = parseInt(weekCell.dataset.index);
|
|
if (!isNaN(weekIndex)) {
|
|
currentWeekIndex = weekIndex;
|
|
updateWeekDisplay();
|
|
loadAndDisplayWeek(allWeekOptions[currentWeekIndex]);
|
|
}
|
|
}
|
|
});
|
|
|
|
setupWeekModal();
|
|
}
|
|
|
|
function openWeekModal() {
|
|
const modal = document.getElementById('weekModal');
|
|
const modalGrid = document.getElementById('weekModalGrid');
|
|
|
|
if (!modal || !modalGrid) return;
|
|
const today = new Date();
|
|
const currentYear = today.getFullYear();
|
|
const currentWeekNumber = getWeekNumber(today);
|
|
const allWeeks = [];
|
|
for (let week = 1; week <= 52; week++) {
|
|
const existingWeek = allWeekOptions.find(opt => parseInt(opt.value) === week);
|
|
if (existingWeek) {
|
|
allWeeks.push({ ...existingWeek, weekIndex: allWeekOptions.indexOf(existingWeek) });
|
|
} else {
|
|
const startOfWeek = getDateOfWeek(currentYear, week, 1);
|
|
const endOfWeek = getDateOfWeek(currentYear, week, 5);
|
|
allWeeks.push({
|
|
value: week.toString(),
|
|
text: `${week}. hét`,
|
|
startDate: startOfWeek.toISOString().split('T')[0],
|
|
endDate: endOfWeek.toISOString().split('T')[0],
|
|
weekIndex: week - 1
|
|
});
|
|
}
|
|
}
|
|
|
|
modalGrid.innerHTML = allWeeks.map((week) => {
|
|
const weekNumber = parseInt(week.value);
|
|
const isSelected = week.weekIndex === currentWeekIndex;
|
|
const isCurrent = weekNumber === currentWeekNumber;
|
|
|
|
return `
|
|
<div class="week-cell modal-week-cell ${isSelected ? 'selected' : ''} ${isCurrent ? 'current-week' : ''}"
|
|
data-week="${week.value}"
|
|
data-start="${week.startDate || ''}"
|
|
data-end="${week.endDate || ''}"
|
|
data-index="${allWeeks.indexOf(week)}"
|
|
title="${week.text}${isCurrent ? ' (Jelenlegi hét)' : ''}">
|
|
<span class="week-number">${week.value}</span>
|
|
${isCurrent ? '<span class="current-indicator">●</span>' : ''}
|
|
</div>
|
|
`;
|
|
}).join('');
|
|
|
|
modal.style.display = 'flex';
|
|
document.body.style.overflow = 'hidden';
|
|
}
|
|
|
|
function closeWeekModal() {
|
|
const modal = document.getElementById('weekModal');
|
|
if (modal) {
|
|
modal.style.display = 'none';
|
|
document.body.style.overflow = '';
|
|
}
|
|
}
|
|
|
|
function setupWeekModal() {
|
|
const modal = document.getElementById('weekModal');
|
|
const closeBtn = document.querySelector('.close-modal');
|
|
|
|
if (closeBtn) {
|
|
closeBtn.addEventListener('click', closeWeekModal);
|
|
}
|
|
|
|
if (modal) {
|
|
modal.addEventListener('click', (e) => {
|
|
if (e.target === modal) {
|
|
closeWeekModal();
|
|
}
|
|
});
|
|
}
|
|
|
|
document.addEventListener('click', (e) => {
|
|
if (e.target.closest('.modal-week-cell')) {
|
|
const weekCell = e.target.closest('.modal-week-cell');
|
|
const weekIndex = parseInt(weekCell.dataset.index);
|
|
if (!isNaN(weekIndex) && weekIndex >= 0) {
|
|
currentWeekIndex = weekIndex;
|
|
updateWeekDisplay();
|
|
loadAndDisplayWeek(allWeekOptions[currentWeekIndex]);
|
|
closeWeekModal();
|
|
}
|
|
}
|
|
});
|
|
|
|
document.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Escape' && modal && modal.style.display === 'flex') {
|
|
closeWeekModal();
|
|
}
|
|
});
|
|
}
|
|
|
|
if (window.location.href.includes('/Orarend/')) {
|
|
transformTimetablePage();
|
|
}
|
|
})(); |