File size: 7,672 Bytes
b6f5bc4 66fd359 b6f5bc4 a7ffb22 0815e01 a7ffb22 72ba2ce a7ffb22 66fd359 a7ffb22 66fd359 a7ffb22 66fd359 a7ffb22 0815e01 a7ffb22 6958fef a7ffb22 72ba2ce 6958fef 72ba2ce a7ffb22 b6f5bc4 a7ffb22 b6f5bc4 a7ffb22 0815e01 a7ffb22 400263a a7ffb22 82cae90 7638d7c 400263a a7ffb22 82cae90 5384c20 a7ffb22 b6f5bc4 a7ffb22 b6f5bc4 a7ffb22 b6f5bc4 a7ffb22 400263a a7ffb22 0815e01 a7ffb22 66fd359 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | // The student's screens, switched by the address after "#": "/" the subjects, "/subject/<id>" a subject's home, "/subject/<id>/path"
// its path, "/skill/<id>" 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(`<section class="card" id="no-class"><h2>עוד לא בכיתה</h2>
<p>עוד לא הוסיפו אותך לכיתה. בקשו מהמורה או ממנהל הכיתות להוסיף את כתובת המייל שבה נכנסתם:</p>
<p dir="ltr"><b>${esc(me.email)}</b></p></section>`);
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/<test>/<n>/all", "/sim/<test>/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/<id>/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/<id>/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 || "")
? `<p><a class="button primary" id="sim-bypass" href="#/sim/${sim[1]}/all">להתחיל בכל זאת, על כל החומר</a></p>
<p class="muted">מבחן סימולציה עושים פעם אחת, והציון נשמר.</p>` : "";
view(`<section class="card"><p class="error" role="alert">${esc(error.message || "משהו השתבש")}</p>${bypass}</section>`);
}
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();
}
|