diff options
| author | Florian Fischer <florian.fischer@muhq.space> | 2026-05-28 15:20:46 +0200 |
|---|---|---|
| committer | Florian Fischer <florian.fischer@muhq.space> | 2026-05-28 15:20:46 +0200 |
| commit | f9a9fa15d6d61eb9730183193ce8af29bdfc17e7 (patch) | |
| tree | c3b96a36623e52f22d281b518d7136795cf82b8a /cockpit/js/cockpit.js | |
| download | bycs-sol-f9a9fa15d6d61eb9730183193ce8af29bdfc17e7.tar.gz bycs-sol-f9a9fa15d6d61eb9730183193ce8af29bdfc17e7.zip | |
cockpit: initial commit
Diffstat (limited to 'cockpit/js/cockpit.js')
| -rw-r--r-- | cockpit/js/cockpit.js | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/cockpit/js/cockpit.js b/cockpit/js/cockpit.js new file mode 100644 index 0000000..3b54f67 --- /dev/null +++ b/cockpit/js/cockpit.js @@ -0,0 +1,289 @@ +import { + fetchSubjectsMock as fetchSubjects, + fetchProgressMock as fetchProgress, +} from "./mock.js"; + +import { + Graduation, + GraduationChange, + fetchGraduation, + submitGraduationChange +} from "./graduation-ENV.js"; + +import { Student, fetchStudents } from "./student-ENV.js"; + +let isTeacher; +let firstname; +let lastname; +let student; + +function getIsTeacher() { + return Boolean(document.querySelector('a[href*="templates.php"]')) || document.body.classList.contains('editing'); +} + +function initCurrentName() { + const autoNameDiv = document.getElementById("auto-name"); + firstname = autoNameDiv.children[0].innerHTML; + lastname = autoNameDiv.children[1].innerHTML; + autoNameDiv.remove(); +} + +async function loadNewStudent(name, group) { + student = new Student(0, name, group); + await loadStudent(student); +} + +async function loadStudent(studentToLoad) { + student = studentToLoad; + fetchAndUpdateStudentInfo(); + updateStudentCalendar(); + updateStudentProgress(); + updateStudentGraduation(); +} + +async function initStudentSelection() { + const sel = document.getElementById("student-selection"); + const list = document.getElementById('student-selection-list'); + const noResults = document.getElementById('student-selection-noresults'); + + const students = await fetchStudents(); + + let items = []; + + let currentFocus = -1; + let visibleItems = []; + function setActive() { + visibleItems.forEach(item => item.classList.remove("active")); + if (currentFocus >= 0 && visibleItems[currentFocus]) { + visibleItems[currentFocus].classList.add("active"); + } + } + + for (const student of students) { + let item = document.createElement("li"); + item.student = student; + item.innerHTML = `${student.name} ${student.group}`; + item.style.display = 'none'; + + item.addEventListener('click', function() { + sel.value = ""; + sel.dispatchEvent(new Event('keyup')); + loadStudent(student); + }); + + list.appendChild(item); + items.push(item); + } + + sel.addEventListener('keyup', function(e) { + if ((["ArrowDown", "ArrowUp", "Enter"]).includes(e.key)) + return; + + const filter = sel.value.toLowerCase(); + visibleItems = []; + for (const item of items) { + const itemText = item.textContent.trim().toLowerCase(); + + if (itemText.indexOf(filter) > -1 && filter !== "") { + item.style.display = ""; + visibleItems.push(item); + + // Highlight matched text + const regex = new RegExp(`(${filter})`, 'gi'); + item.innerHTML = item.textContent.replace( + regex, + "<span class='highlight'>$1</span>" + ); + } else { + item.style.display = "none"; + } + } + + // Select the first or none if there are no items visible + currentFocus = visibleItems.length ? 0 : -1; + setActive(visibleItems); + noResults.style.display = visibleItems.length || filter === "" ? "none" : "block"; + }); + + const clearBtn = document.getElementById('student-selection-clear'); + + sel.addEventListener('input', function() { + clearBtn.style.display = sel.value ? "block" : "none"; + }); + + clearBtn.addEventListener('click', function() { + sel.value = ""; + clearBtn.style.display = "none"; + sel.dispatchEvent(new Event('keyup')); // reset list + sel.focus(); + }); + + sel.addEventListener('keydown', function(e) { + if (e.key === "ArrowDown" || e.key === "ArrowUp") { + if(e.key === "ArrowDown") + currentFocus = (currentFocus + 1) % visibleItems.length; + else + currentFocus = (currentFocus - 1 + visibleItems.length) % visibleItems.length; + setActive(); + e.preventDefault(); + } else if (e.key === "Enter") { + if (currentFocus > -1 && visibleItems[currentFocus]) { + + const visibleItem = visibleItems[currentFocus]; + sel.value = ""; + sel.dispatchEvent(new Event('keyup')); + loadStudent(visibleItem.student); + } + e.preventDefault(); + } + }); +} + +function pointClickHandler(color) { + const textareaDiv = document.getElementById("student-info-point-reason-container"); + const textarea = document.getElementById("student-info-point-reason"); + const submitBtn = document.getElementById("student-info-point-reason-submit"); + + // TODO(muhq): Prefill the textarea with common reasons + switch (color) { + case "green": + textarea.style.background = "rgb(from green r g b / 20%)" + textarea.value = ""; + break; + case "orange": + textarea.style.background = "rgb(from orange r g b / 20%)" + textarea.value = ""; + break; + case "red": + textarea.style.background = "rgb(from red r g b / 20%)" + textarea.value = ""; + break; + } + textareaDiv.style.display = "block"; + textarea.focus(); + + let submit = function() { + let change; + switch (color) { + case "green": + change = GraduationChange.newGreenPointChange(student, textarea.value, `${firstname} ${lastname}`); + break; + case "orange": + change = GraduationChange.newOrangePointChange(student, textarea.value, `${firstname} ${lastname}`); + break; + case "red": + change = GraduationChange.newRedPointChange(student, textarea.value, `${firstname} ${lastname}`); + break; + default: + alert("Invalid color"); + break; + } + submitGraduationChange(student, change); + textareaDiv.style.display = "none"; + updateStudentInfo(); + } + // Use onEVENT to override any previous handler + textarea.onkeydown = function(e) { + if (e.shiftKey && e.key === "Enter") { + submit(); + } + if (e.key === "Escape") { + textareaDiv.style.display = "none"; + } + }; + submitBtn.onclick = submit; +} + +async function fetchAndUpdateStudentInfo() { + student.graduation = await fetchGraduation(student); + updateStudentInfo(); +} + +function updateStudentInfo() { + document.getElementById("student-info-icon").src = student.getIconUrl(); + document.getElementById("student-info-name").innerHTML = `${student.name}`; + + if (student.graduation) { + const tag = document.getElementById("student-info-tag"); + tag.innerHTML = student.graduation.level; + tag.style.display = "block"; + + document.getElementById("student-info-green").addEventListener('click', () => pointClickHandler("green")); + document.getElementById("student-info-points-green").innerHTML = student.graduation.green; + + document.getElementById("student-info-orange").addEventListener('click', () => pointClickHandler("orange")); + document.getElementById("student-info-points-orange").innerHTML = student.graduation.orange; + + document.getElementById("student-info-red").addEventListener('click', () => pointClickHandler("red")); + document.getElementById("student-info-points-red").innerHTML = student.graduation.red; + + renderGraduationLevel(student.graduation, document.getElementById("student-info-level")); + + renderGraduationStickers(student.graduation, document.getElementById("student-info-stickers")); + renderGraduationBonus(student.graduation, document.getElementById("student-info-stickers")); + } +} + +function renderGraduationLevel(graduation, node) { + node.innerHTML = graduation.level; +} + +function renderGraduationStickers(graduation, node) { +} + +function renderGraduationBonus(graduation, node) { +} + +function newProgressBar(subject) { + let bar = document.createElement("div"); + fetchProgress(subject).then((progress) => { + bar.progress = progress; + }); + + let s1 = document.createElement("div"); + s1.onhover + + bar.appendChild(s1); + let s2 = document.createElement("div"); + bar.appendChild(s2); + let s3 = document.createElement("div"); + bar.appendChild(s3); + return bar; +} + +let selectedSubjects; +async function updateStudentProgress() { + selectedSubjects = await fetchSubjects(student); + + let prog = document.getElementById("progress"); + for(const subj of selectedSubjects) { + let subjDiv = document.createElement("div"); + subjDiv.innerHTML = subj; + subjDiv.appendChild(newProgressBar(subj)) + prog.appendChild(subjDiv); + } +} + +async function updateStudentCalendar() { + let cal = document.getElementById("calendar"); +} + +async function updateStudentGraduation() { + let graduation = document.getElementById("graduation"); +} + +async function initCockpit() { + if (isTeacher) { + await initStudentSelection(); + } else { + loadNewStudent(`${firstname} ${lastname}`); + } + return; +} + +window.onload = function() { + // isTeacher = getIsTeacher(); + isTeacher = true; + initCurrentName(); + initCockpit(isTeacher); +} |
