aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/admin-tools.js4
-rw-r--r--src/cockpit.js182
-rw-r--r--src/database-mock.ts9
-rw-r--r--src/database-prod.ts27
-rw-r--r--src/graduation-common.ts199
-rw-r--r--src/graduation-mock.ts4
-rw-r--r--src/graduation-prod.ts7
-rw-r--r--src/mass-graduation.js89
-rw-r--r--src/mock.ts49
-rw-r--r--src/selection.js32
-rw-r--r--src/student-mock.ts13
-rw-r--r--src/student-prod.ts35
-rw-r--r--src/utils-common.ts18
-rw-r--r--src/utils-mock.js20
-rw-r--r--src/utils-prod.js12
15 files changed, 373 insertions, 327 deletions
diff --git a/src/admin-tools.js b/src/admin-tools.js
index b0cf80d..d8e1bf7 100644
--- a/src/admin-tools.js
+++ b/src/admin-tools.js
@@ -1,5 +1,5 @@
-import { DB } from "./database.js";
-import { fetchStudents } from "./student-ENV.js";
+import { DB } from "./database-ENV.ts";
+import { fetchStudents } from "./student-ENV.ts";
let outputNode;
function output(msg) {
diff --git a/src/cockpit.js b/src/cockpit.js
index 67619d8..97d6fed 100644
--- a/src/cockpit.js
+++ b/src/cockpit.js
@@ -1,6 +1,6 @@
// import {
- // fetchSubjectsMock as fetchSubjects,
- // fetchProgressMock as fetchProgress,
+// fetchSubjectsMock as fetchSubjects,
+// fetchProgressMock as fetchProgress,
// } from "../../js/mock.ts";
import {
@@ -8,15 +8,11 @@ import {
LEVEL_NAMES,
GraduationChange,
fetchGraduation,
- submitGraduationChange
+ submitGraduationChange,
} from "./graduation-ENV.ts";
import { fetchStudent, fetchStudents } from "./student-ENV.ts";
-import {
- getName,
- DATE_FMT,
- DATETIME_FMT,
-} from "./utils-ENV.js";
+import { getName, DATE_FMT, DATETIME_FMT } from "./utils-ENV.js";
import { initSelection } from "./selection.js";
let name;
@@ -35,7 +31,7 @@ function initStudentSelection() {
"student-selection",
fetchStudents,
(student) => `${student.name} ${student.getGroup()}`,
- loadStudent
+ loadStudent,
);
}
@@ -46,46 +42,46 @@ function pointClickHandler(color) {
// 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;
+ 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();
const coach = name;
- const submit = function() {
+ const submit = function () {
let change;
switch (color) {
- case "green":
- change = GraduationChange.newGreenPointChange(textarea.value, coach);
- break;
- case "orange":
- change = GraduationChange.newOrangePointChange(textarea.value, coach);
- break;
- case "red":
- change = GraduationChange.newRedPointChange(textarea.value, coach);
- break;
- default:
- throw new Error("Invalid color");
+ case "green":
+ change = GraduationChange.newGreenPointChange(textarea.value, coach);
+ break;
+ case "orange":
+ change = GraduationChange.newOrangePointChange(textarea.value, coach);
+ break;
+ case "red":
+ change = GraduationChange.newRedPointChange(textarea.value, coach);
+ break;
+ default:
+ throw new Error("Invalid color");
}
submitGraduationChange(student, change);
textareaDiv.style.display = "none";
updateStudentInfo();
- student.fetchGraduation().then(() => updateStudentGraduation() );
+ student.fetchGraduation().then(() => updateStudentGraduation());
};
// Use onEVENT to override any previous handler
- textarea.onkeydown = function(e) {
+ textarea.onkeydown = function (e) {
if (e.shiftKey && e.key === "Enter") {
submit();
}
@@ -108,12 +104,12 @@ function updateStudentInfo() {
document.getElementById("student-info-icon").src = DEFAULT_STUDENT_ICON;
// Try to replace the generic icon with the user's icon
- var img = document.createElement('img');
- img.onload = function() {
+ var img = document.createElement("img");
+ img.onload = function () {
document.getElementById("student-info-icon").src = img.src;
img = img.onload = null;
};
- student.getIconUrl().then( (url) => img.src = url );
+ student.getIconUrl().then((url) => (img.src = url));
document.getElementById("student-info-name").innerHTML = `${student.name}`;
@@ -126,12 +122,15 @@ function updateStudentInfo() {
document.getElementById("student-info-points-orange").innerHTML = student.graduation.orange;
document.getElementById("student-info-points-red").innerHTML = student.graduation.red;
- document.getElementById("student-info-green").addEventListener('click',
- () => pointClickHandler("green"));
- document.getElementById("student-info-orange").addEventListener('click',
- () => pointClickHandler("orange"));
- document.getElementById("student-info-red").addEventListener('click',
- () => pointClickHandler("red"));
+ document
+ .getElementById("student-info-green")
+ .addEventListener("click", () => pointClickHandler("green"));
+ document
+ .getElementById("student-info-orange")
+ .addEventListener("click", () => pointClickHandler("orange"));
+ document
+ .getElementById("student-info-red")
+ .addEventListener("click", () => pointClickHandler("red"));
renderGraduationLevel(student.graduation);
@@ -152,11 +151,11 @@ function renderGraduationLevel(graduation) {
}
// function renderGraduationStickers(graduation, node) {
- // node.innerHTML = "";
+// node.innerHTML = "";
// }
// function renderGraduationBonus(graduation, node) {
- // node.innerHTML = "";
+// node.innerHTML = "";
// }
function renderObservationStatus(graduation, node) {
@@ -167,9 +166,10 @@ function renderObservationStatus(graduation, node) {
status = document.createElement("span");
status.classList.add("student-observation-status");
if (graduation.isObserved()) {
- status.innerHTML = '<span style="font-size: larger;">&#128065</span> Ich befinde mich in der Beobachtungsphase zum Levelaufstieg.';
+ status.innerHTML =
+ '<span style="font-size: larger;">&#128065</span> Ich befinde mich in der Beobachtungsphase zum Levelaufstieg.';
} else if (graduation.observationRequested) {
- status.innerHTML = 'Beobachtungsphase noch nicht begonnen.';
+ status.innerHTML = "Beobachtungsphase noch nicht begonnen.";
} else {
status.innerHTML = "Nicht in Beobachtung.";
}
@@ -178,7 +178,7 @@ function renderObservationStatus(graduation, node) {
status.classList.add("student-request-observation-button");
// Level is 1-based
status.innerHTML = `Ich will ${LEVEL_NAMES[graduation.level]} werden`;
- status.addEventListener("click", async function() {
+ status.addEventListener("click", async function () {
await graduation.requestObservation();
// Rerender the observation status
renderObservationStatus(graduation, node);
@@ -188,37 +188,37 @@ function renderObservationStatus(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 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);
- // }
+// 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");
+// let cal = document.getElementById("calendar");
// }
async function updateStudentGraduation() {
@@ -227,26 +227,26 @@ async function updateStudentGraduation() {
const changesTbl = document.getElementById("graduation-changes");
changesTbl.innerHTML = "";
- for (const change of graduation.changes.filter(
- (ch) => ["Grün", "Rot", "Orange"].includes(ch.change) ))
- {
+ for (const change of graduation.changes.filter((ch) =>
+ ["Grün", "Rot", "Orange"].includes(ch.change),
+ )) {
const changeTr = document.createElement("tr");
for (const key in change) {
if (key == "json" || key == "id" || key == "name") continue;
if (key == "change") {
- switch(change.change) {
- case "Grün":
- changeTr.style.background = "green";
- break;
- case "Rot":
- changeTr.style.background = "red";
- break;
- case "Orange":
- changeTr.style.background = "orange";
- break;
- default:
- console.error(`unexpected change: ${change.change}`);
+ switch (change.change) {
+ case "Grün":
+ changeTr.style.background = "green";
+ break;
+ case "Rot":
+ changeTr.style.background = "red";
+ break;
+ case "Orange":
+ changeTr.style.background = "orange";
+ break;
+ default:
+ console.error(`unexpected change: ${change.change}`);
}
continue;
}
@@ -291,7 +291,9 @@ async function updateStudentGraduation() {
endDiv.style.display = "block";
- const reason = document.getElementById("graduation-current-observation-period-end-reason").value;
+ const reason = document.getElementById(
+ "graduation-current-observation-period-end-reason",
+ ).value;
const successBtn = document.getElementById("graduation-current-observation-period-end-success");
successBtn.addEventListener("click", () => {
submitGraduationChange(graduation.student, GraduationChange.newObservationEnd(reason, true));
@@ -336,7 +338,7 @@ async function initCockpit() {
}
}
-window.onload = function() {
+window.onload = function () {
DEFAULT_STUDENT_ICON = document.getElementById("student-info-icon").src;
name = getName();
initCockpit();
diff --git a/src/database-mock.ts b/src/database-mock.ts
index 24cb08f..4d7bf55 100644
--- a/src/database-mock.ts
+++ b/src/database-mock.ts
@@ -14,17 +14,12 @@ class DB {
async saveEntry(json: string) {
console.log(`Mock DB save entry ${json}`);
- return;
+ return;
}
-
}
async function getGraduationDb() {
return new DB();
}
-export {
- DB,
- DatabaseEntry, DatabaseParams,
- getGraduationDb,
-};
+export { DB, DatabaseEntry, DatabaseParams, getGraduationDb };
diff --git a/src/database-prod.ts b/src/database-prod.ts
index 6a55f25..57b9974 100644
--- a/src/database-prod.ts
+++ b/src/database-prod.ts
@@ -23,7 +23,7 @@ const DB_TEMPLATE_LIST_FOOTER = `
let graduationDb = findGraduationDb();
-const ID_QUERY_PARAM_REGEX = /[?&]id=(\d+)/
+const ID_QUERY_PARAM_REGEX = /[?&]id=(\d+)/;
async function findGraduationDb() {
let graduationDbId = localStorage.getItem("gruaduationDbId");
@@ -33,16 +33,16 @@ async function findGraduationDb() {
const courseUrl = `https://lernplattform.bycs.de/course/view.php?id=${getCourseId()}`;
const courseRes = await fetch(courseUrl);
- const courseDoc = new DOMParser().parseFromString(await courseRes.text(), 'text/html');
+ const courseDoc = new DOMParser().parseFromString(await courseRes.text(), "text/html");
for (const a of courseDoc.querySelectorAll("div.activityname a.aalink")) {
if (a.textContent.trim() === "Graduation Datenbank") {
- const anchor = (a as HTMLAnchorElement);
+ const anchor = a as HTMLAnchorElement;
const match = anchor.href.match(ID_QUERY_PARAM_REGEX);
if (match === null) continue;
const dbId = match[1];
localStorage.setItem("graduationDbId", dbId);
- return new DB(Number(dbId))
+ return new DB(Number(dbId));
}
}
console.assert(false, "Graduation DB not found");
@@ -64,13 +64,12 @@ class DB {
}
async fetchEntries(params?: DatabaseParams) {
- return loadFromDatabaseActivity(this.id, params)
+ return loadFromDatabaseActivity(this.id, params);
}
async saveEntry(json: string) {
return addEntryToDatabaseActivity(this.id, json);
}
-
}
async function loadFromDatabaseActivity(id: string | number, params?: DatabaseParams) {
@@ -79,16 +78,16 @@ async function loadFromDatabaseActivity(id: string | number, params?: DatabasePa
if (typeof params !== "undefined") {
dbUrl += "&filter=1&advanced=1";
for (const param in params) {
- dbUrl += `&${param}=${encodeURIComponent(params[param])}`
+ dbUrl += `&${param}=${encodeURIComponent(params[param])}`;
}
}
const dbRes = await fetch(encodeURI(dbUrl));
- const dbDoc = new DOMParser().parseFromString(await dbRes.text(), 'text/html');
+ const dbDoc = new DOMParser().parseFromString(await dbRes.text(), "text/html");
let data: any[] = [];
- dbDoc.querySelectorAll('.db-row').forEach(row => {
+ dbDoc.querySelectorAll(".db-row").forEach((row) => {
let entry: DatabaseEntry = {};
- row.querySelectorAll<HTMLElement>('.db-cell').forEach(field => {
+ row.querySelectorAll<HTMLElement>(".db-cell").forEach((field) => {
const key = field.dataset.key!;
let value;
// Moodle includes the full date in the title attribute of the included span
@@ -112,7 +111,7 @@ async function addEntryToDatabaseActivity(id: number, json: string) {
// TODO(muhq): do not fetch the form
const url = `/mod/data/edit.php?id=${id}`;
const editRes = await fetch(url);
- const editDoc = new DOMParser().parseFromString(await editRes.text(), 'text/html');
+ const editDoc = new DOMParser().parseFromString(await editRes.text(), "text/html");
const form = editDoc.querySelector<HTMLFormElement>('div[role="main"] > form');
const formData = new FormData(form!);
@@ -133,8 +132,4 @@ async function addEntryToDatabaseActivity(id: number, json: string) {
});
}
-export {
- DB,
- DatabaseEntry, DatabaseParams,
- getGraduationDb,
-};
+export { DB, DatabaseEntry, DatabaseParams, getGraduationDb };
diff --git a/src/graduation-common.ts b/src/graduation-common.ts
index 61600d3..2c0fb69 100644
--- a/src/graduation-common.ts
+++ b/src/graduation-common.ts
@@ -1,5 +1,5 @@
-import { getGraduationDb, DatabaseEntry } from "./database-ENV.ts"
-import type { Student } from "./student-common.ts"
+import { getGraduationDb, DatabaseEntry } from "./database-ENV.ts";
+import type { Student } from "./student-common.ts";
import NeulingPng from "../assets/Neuling.png";
import EntdeckerPng from "../assets/Entdecker.png";
@@ -23,7 +23,14 @@ class GraduationChange {
coach: string;
context: any;
- constructor(date: Date, studentId: number, change: string, reason: string, coach: string, context: any) {
+ constructor(
+ date: Date,
+ studentId: number,
+ change: string,
+ reason: string,
+ coach: string,
+ context: any,
+ ) {
this.date = date;
this.studentId = studentId;
this.change = change;
@@ -32,19 +39,26 @@ class GraduationChange {
this.context = context;
}
- dbFields () {
+ dbFields() {
return {
- "studentId": this.studentId,
- "change": this.change,
- "reason": this.reason,
- "context": this.context,
+ studentId: this.studentId,
+ change: this.change,
+ reason: this.reason,
+ context: this.context,
};
}
static fromDBEntry(e: DatabaseEntry) {
- const {date, coach, json} = e;
+ const { date, coach, json } = e;
const change = JSON.parse(json);
- return new GraduationChange(new Date(date), change.change, change.student, change.reason, coach, change.context);
+ return new GraduationChange(
+ new Date(date),
+ change.change,
+ change.student,
+ change.reason,
+ coach,
+ change.context,
+ );
}
static newObservationRequest() {
@@ -56,11 +70,25 @@ class GraduationChange {
}
static newObservationEnd(reason: string, success: boolean) {
- return new GraduationChange(new Date(), -1, "ObservationEnd", reason, "", JSON.stringify(success));
+ return new GraduationChange(
+ new Date(),
+ -1,
+ "ObservationEnd",
+ reason,
+ "",
+ JSON.stringify(success),
+ );
}
static newObservationChange(observation: Observation) {
- return new GraduationChange(observation.date, -1, "Observation", "", "", JSON.stringify(observation.status));
+ return new GraduationChange(
+ observation.date,
+ -1,
+ "Observation",
+ "",
+ "",
+ JSON.stringify(observation.status),
+ );
}
static newGreenPointChange(reason: string, coach: string) {
@@ -87,7 +115,17 @@ class Graduation {
pastObservations: Array<ObservationPeriod>;
changes: Array<GraduationChange>;
- constructor(student: Student, green: number, orange: number, red: number, level: number, observationRequested: Date | null, observation: ObservationPeriod | null, pastObservations: Array<ObservationPeriod>, changes: Array<GraduationChange>) {
+ constructor(
+ student: Student,
+ green: number,
+ orange: number,
+ red: number,
+ level: number,
+ observationRequested: Date | null,
+ observation: ObservationPeriod | null,
+ pastObservations: Array<ObservationPeriod>,
+ changes: Array<GraduationChange>,
+ ) {
this.student = student;
this.green = green;
this.orange = orange;
@@ -115,63 +153,70 @@ class Graduation {
for (const change of changes) {
switch (change.change) {
- case "Grün":
- green++;
- break;
-
- case "Orange":
- orange++;
- break;
-
- case "Rot":
- red++;
- break;
-
- case "ObservationRequest":
- openObservationRequest = change.date;
- break;
-
- case "ObservationStart":
- console.assert(openObservationRequest === null,
- "No request for observation start");
-
- observationPeriod = new ObservationPeriod(change.date);
- openObservationRequest = null;
- break;
-
- case "ObservationEnd":
- if (observationPeriod === null) {
- console.error("No active observation period");
- continue;
- }
- observationPeriod.finishPeriod(change.context.success);
- if (change.context.success) {
- level++;
- }
- pastObservations.push(observationPeriod);
- observationPeriod = null;
- break;
-
- case "Observation":
- if (observationPeriod === null) {
- console.error("No active observation period");
- continue;
- }
- const observation = Observation.fromChange(change);
- observationPeriod.addObservation(observation);
- break;
-
- case "LevelChange":
- level = change.context.level;
- break;
-
- default:
- throw new Error(`Unexpected change: ${change}`);
+ case "Grün":
+ green++;
+ break;
+
+ case "Orange":
+ orange++;
+ break;
+
+ case "Rot":
+ red++;
+ break;
+
+ case "ObservationRequest":
+ openObservationRequest = change.date;
+ break;
+
+ case "ObservationStart":
+ console.assert(openObservationRequest === null, "No request for observation start");
+
+ observationPeriod = new ObservationPeriod(change.date);
+ openObservationRequest = null;
+ break;
+
+ case "ObservationEnd":
+ if (observationPeriod === null) {
+ console.error("No active observation period");
+ continue;
+ }
+ observationPeriod.finishPeriod(change.context.success);
+ if (change.context.success) {
+ level++;
+ }
+ pastObservations.push(observationPeriod);
+ observationPeriod = null;
+ break;
+
+ case "Observation":
+ if (observationPeriod === null) {
+ console.error("No active observation period");
+ continue;
+ }
+ const observation = Observation.fromChange(change);
+ observationPeriod.addObservation(observation);
+ break;
+
+ case "LevelChange":
+ level = change.context.level;
+ break;
+
+ default:
+ throw new Error(`Unexpected change: ${change}`);
}
}
- return new Graduation(student, green, orange, red, level,
- openObservationRequest, observationPeriod, pastObservations,
- changes);
+ return new Graduation(
+ student,
+ green,
+ orange,
+ red,
+ level,
+ openObservationRequest,
+ observationPeriod,
+ pastObservations,
+ changes,
+ );
}
addChange(change: GraduationChange) {
@@ -264,8 +309,7 @@ class ObservationPeriod {
}
ready() {
- if (this.observations.length < 10)
- return false;
+ if (this.observations.length < 10) return false;
// at least 10 observation on different days
let days = new Map();
@@ -277,14 +321,14 @@ class ObservationPeriod {
}
getObservationsSums() {
- let sums = Array(OBSERVATION_TYPES.length).fill(null).map(() => ({"yes":0, "no":0}));
+ let sums = Array(OBSERVATION_TYPES.length)
+ .fill(null)
+ .map(() => ({ yes: 0, no: 0 }));
for (const observation of this.observations) {
for (let i = 0; i < sums.length; i++) {
if (observation.status[i]) {
- if (observation.status[i] === "yes")
- sums[i].yes++;
- else
- sums[i].no++;
+ if (observation.status[i] === "yes") sums[i].yes++;
+ else sums[i].no++;
}
}
}
@@ -317,7 +361,7 @@ class Observation {
}
static fromChange(change: GraduationChange) {
- return new Observation(change.date, JSON.parse(change.context))
+ return new Observation(change.date, JSON.parse(change.context));
}
}
@@ -328,7 +372,7 @@ async function submitGraduationChange(graduation: Graduation, change: Graduation
}
async function submitObservation(graduation: Graduation, observation: Observation) {
- if(graduation.observation === null) throw new Error("no active observation");
+ if (graduation.observation === null) throw new Error("no active observation");
graduation.observation.addObservation(observation);
await submitGraduationChange(graduation, GraduationChange.newObservationChange(observation));
}
@@ -340,7 +384,6 @@ export {
Graduation,
submitGraduationChange,
submitObservation,
-
OBSERVATION_TYPES,
Observation,
ObservationPeriod,
diff --git a/src/graduation-mock.ts b/src/graduation-mock.ts
index 84a7143..5c48a81 100644
--- a/src/graduation-mock.ts
+++ b/src/graduation-mock.ts
@@ -2,7 +2,6 @@ import {
LEVEL_NAMES,
GraduationChange,
Graduation,
-
OBSERVATION_TYPES,
Observation,
ObservationPeriod,
@@ -11,7 +10,7 @@ import {
import {
fetchGraduationMock as fetchGraduation,
submitGraduationChangeMock as submitGraduationChange,
- submitObservationMock as submitObservation
+ submitObservationMock as submitObservation,
} from "./mock.ts";
export {
@@ -21,7 +20,6 @@ export {
fetchGraduation,
submitGraduationChange,
submitObservation,
-
OBSERVATION_TYPES,
Observation,
ObservationPeriod,
diff --git a/src/graduation-prod.ts b/src/graduation-prod.ts
index 975fd0f..663493a 100644
--- a/src/graduation-prod.ts
+++ b/src/graduation-prod.ts
@@ -1,8 +1,8 @@
-import { getGraduationDb } from "./database-ENV.ts"
+import { getGraduationDb } from "./database-ENV.ts";
import { Graduation, GraduationChange } from "./graduation-common.ts";
import type { Student } from "./student-common.ts";
-const _graduationChangesPromise = async function() {
+const _graduationChangesPromise = (async function () {
const db = await getGraduationDb();
let changes = new Map();
let entries = await db.fetchEntries();
@@ -16,7 +16,7 @@ const _graduationChangesPromise = async function() {
}
}
return changes;
-}();
+})();
const graduations: Map<number, Graduation> = new Map();
@@ -36,7 +36,6 @@ export {
Graduation,
submitGraduationChange,
submitObservation,
-
OBSERVATION_TYPES,
Observation,
ObservationPeriod,
diff --git a/src/mass-graduation.js b/src/mass-graduation.js
index b9240f0..48d23ad 100644
--- a/src/mass-graduation.js
+++ b/src/mass-graduation.js
@@ -3,7 +3,7 @@ import {
GraduationChange,
submitGraduationChange,
Observation,
- submitObservation
+ submitObservation,
} from "./graduation-ENV.ts";
import { fetchGroups } from "./group-fetch.ts";
@@ -19,8 +19,7 @@ function toggle(btn, others) {
} else {
btn.innerHTML = "X";
if (others) {
- for (const other of others)
- other.innerHTML = "o";
+ for (const other of others) other.innerHTML = "o";
}
}
@@ -31,7 +30,7 @@ function toggle(btn, others) {
function observationClickHandler(li) {
let observationDiv = li.observationDiv;
// Build the observation container
- if(!observationDiv) {
+ if (!observationDiv) {
li.style.background = "lightgray";
observationDiv = document.createElement("div");
@@ -97,12 +96,11 @@ function observationClickHandler(li) {
obsTbdy.appendChild(obsTr);
}
- // Toggle the observation container visibility
+ // Toggle the observation container visibility
} else {
if (observationDiv.style.display === "none") {
observationDiv.style.display = "block";
li.style.background = "lightgray";
-
} else {
observationDiv.style.display = "none";
li.style.background = "unset";
@@ -148,7 +146,7 @@ async function loadGroup(selected) {
return;
}
ob.innerHTML = "&#128065";
- ob.addEventListener("click", () => observationClickHandler(li) );
+ ob.addEventListener("click", () => observationClickHandler(li));
});
graduationPromises.push(graduationPromise);
@@ -158,7 +156,7 @@ async function loadGroup(selected) {
const b = document.createElement("button");
b.classList.add(`group-member-${col}`);
b.innerHTML = "o";
- b.addEventListener("click", () => toggle(b) );
+ b.addEventListener("click", () => toggle(b));
li.appendChild(b);
}
@@ -169,7 +167,7 @@ async function loadGroup(selected) {
const p = document.createElement("button");
p.classList.add("group-member-print");
p.innerHTML = "🖶";
- p.addEventListener("click", () => printNote(li) );
+ p.addEventListener("click", () => printNote(li));
li.appendChild(p);
ul.appendChild(li);
@@ -177,7 +175,7 @@ async function loadGroup(selected) {
const graduations = await Promise.all(graduationPromises);
const observations = graduations.filter(
- (g) => g.observationRequested || (g.observation && !g.observation.end)
+ (g) => g.observationRequested || (g.observation && !g.observation.end),
);
const observationReuqestsContainer = document.getElementById("observation-requests-container");
@@ -234,7 +232,10 @@ async function loadGroup(selected) {
startBtn.classList.add("start-observation");
} else {
startBtn.addEventListener("click", () => {
- window.open(`/mod/page/view.php?id=93017047&userToLoad=${graduation.student.id}`, '_blank');
+ window.open(
+ `/mod/page/view.php?id=93017047&userToLoad=${graduation.student.id}`,
+ "_blank",
+ );
});
startBtn.innerHTML = `Graduierung abschließen`;
startBtn.classList.add("end-observation");
@@ -256,50 +257,55 @@ function submitMassGraduation() {
// TODO(muhq): await graduation promises
const promises = [];
- for(const li of document.querySelectorAll("li.group-member")) {
+ for (const li of document.querySelectorAll("li.group-member")) {
const reason = li.querySelector(".group-member-point-reason").value;
const student = li.student;
if (li.querySelector(".group-member-green").innerHTML === "X") {
- promises.push(submitGraduationChange(student, GraduationChange.newGreenPointChange(reason, name)));
+ promises.push(
+ submitGraduationChange(student, GraduationChange.newGreenPointChange(reason, name)),
+ );
}
if (li.querySelector(".group-member-orange").innerHTML === "X") {
- promises.push(submitGraduationChange(student, GraduationChange.newOrangePointChange(reason, name)));
+ promises.push(
+ submitGraduationChange(student, GraduationChange.newOrangePointChange(reason, name)),
+ );
}
if (li.querySelector(".group-member-red").innerHTML === "X") {
- promises.push(submitGraduationChange(student, GraduationChange.newRedPointChange(reason, name)));
+ promises.push(
+ submitGraduationChange(student, GraduationChange.newRedPointChange(reason, name)),
+ );
}
if (li.observationDiv) {
const status = [];
for (const row of li.observationDiv.querySelectorAll("tbody > tr")) {
- if (row.querySelector('td[data-yes="true"]').innerHTML === "X")
- status.push("yes");
- else if (row.querySelector('td[data-no="true"]').innerHTML === "X")
- status.push("no");
- else
- status.push("");
+ if (row.querySelector('td[data-yes="true"]').innerHTML === "X") status.push("yes");
+ else if (row.querySelector('td[data-no="true"]').innerHTML === "X") status.push("no");
+ else status.push("");
}
promises.push(submitObservation(student, new Observation(new Date(), status)));
}
}
- Promise.all(promises).then(() => {
- state.style.display = "inline";
- state.innerHTML = "✓";
- state.style.color = "green";
- for (const li of document.querySelectorAll("li.group-member")) {
- if (!li.observationDiv)
- continue;
- li.observationDiv.remove();
- li.observationDiv = null;
- }
- }).catch((error) => {
- state.style.display = "inline";
- state.innerHTML = "X";
- state.style.color = "red";
- console.log(error);
- }).finally(() => {
- state.classList.remove("submit-mass-graduation-inprogress");
- });
+ Promise.all(promises)
+ .then(() => {
+ state.style.display = "inline";
+ state.innerHTML = "✓";
+ state.style.color = "green";
+ for (const li of document.querySelectorAll("li.group-member")) {
+ if (!li.observationDiv) continue;
+ li.observationDiv.remove();
+ li.observationDiv = null;
+ }
+ })
+ .catch((error) => {
+ state.style.display = "inline";
+ state.innerHTML = "X";
+ state.style.color = "red";
+ console.log(error);
+ })
+ .finally(() => {
+ state.classList.remove("submit-mass-graduation-inprogress");
+ });
}
let prePrintBody = null;
@@ -342,7 +348,9 @@ async function init() {
initSelection(
"group-selection",
- async function() { return (await fetchGroups()).values(); },
+ async function () {
+ return (await fetchGroups()).values();
+ },
(group) => `${group.name}`,
loadGroup,
);
@@ -353,4 +361,3 @@ if (document.readyState === "loading") {
} else {
init();
}
-
diff --git a/src/mock.ts b/src/mock.ts
index 220b1e3..5afe1db 100644
--- a/src/mock.ts
+++ b/src/mock.ts
@@ -3,9 +3,9 @@ import { Student } from "./student-common.ts";
import { buildGroups } from "./group.ts";
const students = [
- new Student(1, 'foo bar', 'test'),
- new Student(2, 'maxi mustermensch', 'test'),
- new Student(3, 'b b b', '5a')
+ new Student(1, "foo bar", "test"),
+ new Student(2, "maxi mustermensch", "test"),
+ new Student(3, "b b b", "5a"),
];
// Build the groups from our mock students
@@ -16,7 +16,7 @@ async function fetchStudentsMock(_id?: number, _name?: string, _group?: string)
}
async function fetchSubjectsMock() {
- return ['Mathe', 'Deutsch', 'Englisch'];
+ return ["Mathe", "Deutsch", "Englisch"];
}
function fetchProgressMock(subject: string) {
@@ -36,23 +36,30 @@ function fetchProgressMock(subject: string) {
const graduations = new Map();
for (const s of students) {
switch (s.name) {
- case "foo bar":
- graduations.set(s, Graduation.from(s, [
- GraduationChange.newGreenPointChange("Gute Arbeit", "Florian Fischer"),
- GraduationChange.newOrangePointChange("", "Florian Fischer"),
- ]));
- break;
- case "maxi mustermensch":
- graduations.set(s, Graduation.from(s, [
- GraduationChange.newGreenPointChange("", "Florian Fischer"),
- GraduationChange.newGreenPointChange("", "Florian Fischer"),
- new GraduationChange(new Date(), s.id, "ObservationStart", "", "Florian Fischer", ""),
- ]));
- break;
- case "b b b":
- graduations.set(s, Graduation.from(s, [
- GraduationChange.newRedPointChange("", "Florian Fischer"),
- ]));
+ case "foo bar":
+ graduations.set(
+ s,
+ Graduation.from(s, [
+ GraduationChange.newGreenPointChange("Gute Arbeit", "Florian Fischer"),
+ GraduationChange.newOrangePointChange("", "Florian Fischer"),
+ ]),
+ );
+ break;
+ case "maxi mustermensch":
+ graduations.set(
+ s,
+ Graduation.from(s, [
+ GraduationChange.newGreenPointChange("", "Florian Fischer"),
+ GraduationChange.newGreenPointChange("", "Florian Fischer"),
+ new GraduationChange(new Date(), s.id, "ObservationStart", "", "Florian Fischer", ""),
+ ]),
+ );
+ break;
+ case "b b b":
+ graduations.set(
+ s,
+ Graduation.from(s, [GraduationChange.newRedPointChange("", "Florian Fischer")]),
+ );
}
}
diff --git a/src/selection.js b/src/selection.js
index bfaebc0..b7968af 100644
--- a/src/selection.js
+++ b/src/selection.js
@@ -27,7 +27,7 @@ async function initSelection(idPrefix, fetchCandidates, fmtCandidate, onSelectio
let currentFocus = -1;
let visibleItems = [];
function setActive() {
- visibleItems.forEach(item => item.classList.remove("active"));
+ visibleItems.forEach((item) => item.classList.remove("active"));
if (currentFocus >= 0 && visibleItems[currentFocus]) {
visibleItems[currentFocus].classList.add("active");
}
@@ -37,11 +37,11 @@ async function initSelection(idPrefix, fetchCandidates, fmtCandidate, onSelectio
const item = document.createElement("li");
item.candidate = candidate;
item.innerHTML = fmtCandidate(candidate);
- item.style.display = 'none';
+ item.style.display = "none";
- item.addEventListener('click', function() {
+ item.addEventListener("click", function () {
sel.value = "";
- sel.dispatchEvent(new Event('keyup'));
+ sel.dispatchEvent(new Event("keyup"));
onSelection(candidate);
});
@@ -49,9 +49,8 @@ async function initSelection(idPrefix, fetchCandidates, fmtCandidate, onSelectio
items.push(item);
}
- sel.addEventListener('keyup', function(e) {
- if ((["ArrowDown", "ArrowUp", "Enter"]).includes(e.key))
- return;
+ sel.addEventListener("keyup", function (e) {
+ if (["ArrowDown", "ArrowUp", "Enter"].includes(e.key)) return;
const filter = sel.value.toLowerCase();
visibleItems = [];
@@ -63,10 +62,10 @@ async function initSelection(idPrefix, fetchCandidates, fmtCandidate, onSelectio
visibleItems.push(item);
// Highlight matched text
- const regex = new RegExp(`(${filter})`, 'gi');
+ const regex = new RegExp(`(${filter})`, "gi");
item.innerHTML = item.textContent.replace(
regex,
- "<u class='student-selection-list-highlight'>$1</u>"
+ "<u class='student-selection-list-highlight'>$1</u>",
);
} else {
item.style.display = "none";
@@ -82,26 +81,23 @@ async function initSelection(idPrefix, fetchCandidates, fmtCandidate, onSelectio
noResults.style.display = visibleItems.length || filter === "" ? "none" : "block";
});
- clearBtn.addEventListener('click', function() {
+ clearBtn.addEventListener("click", function () {
sel.value = "";
- sel.dispatchEvent(new Event('keyup')); // reset list
+ sel.dispatchEvent(new Event("keyup")); // reset list
sel.focus();
});
- sel.addEventListener('keydown', function(e) {
+ 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;
+ 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'));
+ sel.dispatchEvent(new Event("keyup"));
onSelection(visibleItem.candidate);
}
e.preventDefault();
diff --git a/src/student-mock.ts b/src/student-mock.ts
index 93b45b0..bf817d2 100644
--- a/src/student-mock.ts
+++ b/src/student-mock.ts
@@ -3,20 +3,19 @@ import { Student } from "./student-common.ts";
import { fetchStudentsMock as fetchStudents, fetchGraduationMock } from "./mock.ts";
declare module "./student-common.ts" {
- interface Student {
- getGraduation(): Promise<Graduation>;
- getIconUrl(): Promise<string>;
- }
+ interface Student {
+ getGraduation(): Promise<Graduation>;
+ getIconUrl(): Promise<string>;
+ }
}
Student.prototype.getGraduation = function () {
- return fetchGraduationMock(this);
+ return fetchGraduationMock(this);
};
Student.prototype.getIconUrl = async function () {
- return "";
+ return "";
};
-
async function fetchStudent(_idFilter?: number, _nameFilter?: string, _groupFilter?: string) {
const students = await fetchStudents();
return students[0];
diff --git a/src/student-prod.ts b/src/student-prod.ts
index 24ac869..67379d9 100644
--- a/src/student-prod.ts
+++ b/src/student-prod.ts
@@ -1,20 +1,20 @@
import type { Graduation } from "./graduation-common.ts";
import { Student } from "./student-common.ts";
-import { getUserIconUrl, getCourseParticipantsUrl } from "./utils-prod.js"
+import { getUserIconUrl, getCourseParticipantsUrl } from "./utils-prod.js";
import { fetchGraduation } from "./graduation-prod.ts";
declare module "./student-common.ts" {
- interface Student {
- getGraduation(): Promise<Graduation>;
- getIconUrl(): Promise<string>;
- }
+ interface Student {
+ getGraduation(): Promise<Graduation>;
+ getIconUrl(): Promise<string>;
+ }
}
Student.prototype.getGraduation = function () {
- return fetchGraduation(this);
+ return fetchGraduation(this);
};
Student.prototype.getIconUrl = function () {
- return getUserIconUrl(this.id);
+ return getUserIconUrl(this.id);
};
// Cache the fetched students.
@@ -26,9 +26,8 @@ async function _fetchStudents() {
const doc = new DOMParser().parseFromString(await res.text(), "text/html");
const table = doc.querySelector("tbody")!;
const fetchedStudents: Array<Student> = [];
- table.querySelectorAll("tr").forEach(row => {
- if (row.classList.contains("emptyrow"))
- return;
+ table.querySelectorAll("tr").forEach((row) => {
+ if (row.classList.contains("emptyrow")) return;
const roleCell = row.querySelector(".c4")!;
// TODO(muhq): Is this locale dependent?
@@ -39,10 +38,8 @@ async function _fetchStudents() {
const nameCell = row.querySelector<HTMLElement>(".c1")!;
let name;
const c = nameCell.firstChild!.firstChild! as HTMLElement;
- if (c.tagName == "SPAN")
- name = c.title;
- else
- name = nameCell.innerText;
+ if (c.tagName == "SPAN") name = c.title;
+ else name = nameCell.innerText;
const profileUrl = nameCell.querySelector<HTMLAnchorElement>("a.aabtn")!.href;
const match = idRegex.exec(profileUrl);
@@ -76,10 +73,12 @@ async function fetchStudents(idFilter?: number, nameFilter?: string, groupFilter
}
}
- return students.filter((s) =>
- (typeof idFilter === "undefined" || s.id === idFilter) &&
- (typeof nameFilter === "undefined" || s.name.includes(nameFilter)) &&
- (typeof groupFilter === "undefined" || s.group.includes(groupFilter)));
+ return students.filter(
+ (s) =>
+ (typeof idFilter === "undefined" || s.id === idFilter) &&
+ (typeof nameFilter === "undefined" || s.name.includes(nameFilter)) &&
+ (typeof groupFilter === "undefined" || s.group.includes(groupFilter)),
+ );
}
async function fetchStudent(idFilter: number, nameFilter: string, groupFilter: string) {
diff --git a/src/utils-common.ts b/src/utils-common.ts
index f3ad944..8053043 100644
--- a/src/utils-common.ts
+++ b/src/utils-common.ts
@@ -1,8 +1,18 @@
"use strict";
-export const DATE_FMT = new Intl.DateTimeFormat("de-DE", { month: "numeric", day: "numeric", year: "numeric"});
+export const DATE_FMT = new Intl.DateTimeFormat("de-DE", {
+ month: "numeric",
+ day: "numeric",
+ year: "numeric",
+});
-export const DATETIME_FMT = new Intl.DateTimeFormat("de-DE", { month: "numeric", day: "numeric", year: "numeric", hour: "numeric", minute: "numeric" });
+export const DATETIME_FMT = new Intl.DateTimeFormat("de-DE", {
+ month: "numeric",
+ day: "numeric",
+ year: "numeric",
+ hour: "numeric",
+ minute: "numeric",
+});
export function dateStringNow() {
return DATE_FMT.format(new Date());
@@ -14,8 +24,8 @@ export function datetimeStringNow() {
// TODO(muhq): Cache the retrieved URL
export async function getUserIconUrl(userId: number): Promise<string> {
- const userRes = await fetch(`https://lernplattform.bycs.de/user/profile.php?id=${userId}`)
- const userDoc = new DOMParser().parseFromString(await userRes.text(), 'text/html')
+ const userRes = await fetch(`https://lernplattform.bycs.de/user/profile.php?id=${userId}`);
+ const userDoc = new DOMParser().parseFromString(await userRes.text(), "text/html");
const userpicture = userDoc.querySelector(".userpicture");
if (userpicture === null) {
return "";
diff --git a/src/utils-mock.js b/src/utils-mock.js
index ab87ddc..9694500 100644
--- a/src/utils-mock.js
+++ b/src/utils-mock.js
@@ -4,11 +4,11 @@ export {
DATETIME_FMT,
dateStringNow,
datetimeStringNow,
- getUserIconUrl
+ getUserIconUrl,
} from "./utils-common.ts";
export function isTeacher() {
- return !(new URLSearchParams(document.location.search)).has("student");
+ return !new URLSearchParams(document.location.search).has("student");
}
export function getFirstAndLastname() {
@@ -16,10 +16,8 @@ export function getFirstAndLastname() {
let lastname = "";
const params = new URLSearchParams(document.location.search);
- if (params.has("firstname"))
- firstname = params.get("firstname");
- if (params.has("lastname"))
- lastname = params.get("lastname");
+ if (params.has("firstname")) firstname = params.get("firstname");
+ if (params.has("lastname")) lastname = params.get("lastname");
return [firstname, lastname];
}
@@ -28,10 +26,8 @@ export function getName() {
let name = "";
const params = new URLSearchParams(document.location.search);
- if (params.has("firstname"))
- name = params.get("firstname");
- if (params.has("lastname"))
- name += params.get("lastname");
+ if (params.has("firstname")) name = params.get("firstname");
+ if (params.has("lastname")) name += params.get("lastname");
return name;
}
@@ -39,7 +35,7 @@ export function getName() {
export function getUserId() {
const name = getName();
- return fetchStudentsMock.filter((s) => s.name === name )[0].id;
+ return fetchStudentsMock.filter((s) => s.name === name)[0].id;
}
export function getCourseId() {
@@ -50,5 +46,3 @@ export function getCourseParticipantsUrl() {
console.error("Try to get mocked participations URL");
return "";
}
-
-
diff --git a/src/utils-prod.js b/src/utils-prod.js
index f7c89e4..94d724a 100644
--- a/src/utils-prod.js
+++ b/src/utils-prod.js
@@ -3,12 +3,14 @@ export {
DATETIME_FMT,
dateStringNow,
datetimeStringNow,
- getUserIconUrl
+ getUserIconUrl,
} from "./utils-common.ts";
export function isTeacher() {
- return Boolean(document.querySelector('.editmode-switch-form'))
- || document.body.classList.contains('editing');
+ return (
+ Boolean(document.querySelector(".editmode-switch-form")) ||
+ document.body.classList.contains("editing")
+ );
}
export function getFirstAndLastname() {
@@ -24,7 +26,8 @@ export function getFirstAndLastname() {
}
export function getName() {
- return document.querySelector("bycs-topbar").shadowRoot.querySelector("div.user-name").textContent;
+ return document.querySelector("bycs-topbar").shadowRoot.querySelector("div.user-name")
+ .textContent;
}
export function getUserId() {
@@ -40,4 +43,3 @@ export function getCourseId() {
export function getCourseParticipantsUrl() {
return `https://lernplattform.bycs.de/user/index.php?id=${getCourseId()}&perpage=5000`;
}
-