// The student's screens, switched by the address after "#": "/" the subjects, "/subject/" a subject's home, "/subject//path" // its path, "/skill/" a skill's sheet over its subject's path, "/collection". The subject of a skill, a quiz or a test opened by a // link is asked from the server, so a reload lands on the right subject's path. import { api } from "./api.js"; import { esc } from "./math.js"; import { setSubject } from "./ui.js"; import * as exercise from "./exercise.js"; import * as home from "./home.js"; import * as phone from "./phone.js"; import * as path from "./path.js"; import * as quiz from "./quiz.js"; import * as lessonRound from "./round.js"; import { route as onRoute } from "./router.js"; export async function show(me, view) { if (!me.classes.length && me.roles.every(r => r === "student")) { view(`

עוד לא בכיתה

עוד לא הוסיפו אותך לכיתה. בקשו מהמורה או ממנהל הכיתות להוסיף את כתובת המייל שבה נכנסתם:

${esc(me.email)}

`); return; } let lastSkill = ""; async function route() { phone.stopComputer(); // a page that was waiting for the phone's photo is left const raw = location.hash.replace(/^#/, ""); const where = raw.startsWith("/") ? raw : "/"; // no address, or the sign-in service's "#access_token=…": the first screen if (!where.startsWith("/round/") && !where.startsWith("/retry/")) lessonRound.close(); try { if (where.startsWith("/round/")) { // a lesson's round over the home (a link or a reload: the home first) exercise.close(); quiz.close(); const data = await lessonRound.start(decodeURIComponent(where.slice(7))); setSubject(data.subject_id); if (!document.getElementById("lesson-map")) await home.show(view); await lessonRound.show(data); } else if (where.startsWith("/retry/")) { // the mistakes of a handed-in attempt, over its test's card (a quiz: the path) exercise.close(); quiz.close(); const data = await lessonRound.startRetry(decodeURIComponent(where.slice(7))); setSubject(data.subject_id); if (data.source.test_id) { if (!document.getElementById("test-card")) await (await import("./testcard.js")).show(view, data.source.test_id); } else if (!document.getElementById("path")) await path.show(view); await lessonRound.show(data); } else if (where.startsWith("/skill/")) { quiz.close(); lastSkill = decodeURIComponent(where.slice(7)); if (!document.getElementById("path")) { // a link or a reload: the skill's subject's path first, then the sheet setSubject((await api(`/api/skills/${encodeURIComponent(lastSkill)}`)).subject_id); await path.show(view); } await exercise.open(lastSkill); } else if (where.startsWith("/quiz/")) { exercise.close(); const [lesson, attempt] = where.slice(6).split("/").map(decodeURIComponent); if (!document.getElementById("path")) { // a link or a reload: the lesson's subject's path first setSubject((await api(`/api/lessons/${encodeURIComponent(lesson)}/quiz`)).subject_id); await path.show(view); } if (attempt) await quiz.open(attempt); else await quiz.start(lesson); // the node starts or resumes; the address then names the attempt } else if (where === "/submissions") { exercise.close(); quiz.close(); await (await import("./submissions.js")).show(view); } else if (where.startsWith("/assignment/")) { exercise.close(); quiz.close(); await (await import("./assignment.js")).show(view, decodeURIComponent(where.slice(12))); } else if (where.startsWith("/exam/") || where.startsWith("/sim/")) { exercise.close(); const [kind, ...rest] = where.slice(1).split("/").map(decodeURIComponent); const [test, second, third] = rest; const allSkills = kind === "exam" ? third === "all" : second === "all"; // "/exam///all", "/sim//all": not an attempt id const attempt = allSkills ? undefined : kind === "exam" ? third : second; if (!document.getElementById("path") && !document.getElementById("test-card")) await (await import("./testcard.js")).show(view, test); // a link or a reload: the test's card first if (attempt) await quiz.open(attempt); else if (kind === "exam" && second === "4") location.replace(`#/test/${encodeURIComponent(test)}/practice`); // picked skills: choose them first else if (kind === "exam") await quiz.startExam(test, second, allSkills); else await quiz.startSimulation(test, allSkills); } else if (where.startsWith("/test/")) { exercise.close(); quiz.close(); const [testId, part] = where.slice(6).split("/").map(decodeURIComponent); // "/test//practice": straight to the practice test's choice await (await import("./testcard.js")).show(view, testId, part === "practice" ? "practice" : ""); } else if (where === "/review") { exercise.close(); quiz.close(); await (await import("./review.js")).show(view); } else if (where === "/grades") { exercise.close(); quiz.close(); await (await import("./grades.js")).show(view); } else if (where === "/") { exercise.close(); quiz.close(); await path.showSubjects(view); } else if (/^\/subject\/[^/]+$/.test(where)) { exercise.close(); quiz.close(); setSubject(decodeURIComponent(where.slice(9))); await home.show(view); } else if (where === "/collection") { exercise.close(); quiz.close(); await (await import("./collection.js")).show(view); } else { // "/subject//path", and any unknown address const named = where.match(/^\/subject\/([^/]+)\/path$/); if (named) setSubject(decodeURIComponent(named[1])); const wasOpen = exercise.isOpen() || quiz.isOpen(); exercise.close(); quiz.close(); await path.show(view, { scroll: !wasOpen }); // closing a sheet refreshes the stars and keeps the place if (wasOpen && lastSkill) document.querySelector(`.star[data-skill="${CSS.escape(lastSkill)}"]`)?.focus({ preventScroll: true }); } } catch (error) { if (error.status === 401) throw error; const sim = where.match(/^\/sim\/([^/]+)$/); // the simulation with nothing started yet: a bypass on all the material const bypass = sim && error.status === 409 && /עוד לא התחלתם/.test(error.message || "") ? `

להתחיל בכל זאת, על כל החומר

מבחן סימולציה עושים פעם אחת, והציון נשמר.

` : ""; view(`
${bypass}
`); } if (!where.startsWith("/skill/") && !exercise.isOpen()) { /* the path scrolls itself */ } } onRoute(route); phone.startWatching(); // a photo request from the student's computer shows here when this is the phone await route(); }