Loading static/js/exercises.api.mjs +28 −6 Changes for static/js/exercises.api.mjs: 28 added lines, 6 removed lines. Original line number Diff line number Diff line Loading @@ -12,8 +12,7 @@ import { arrayEquals } from "./util.mjs" * exercises.mjs. * * Instances of this class are not created directly by the user, instead, * they are created using the `exercise` function which will also immediately * add them to the global list of exercises. * they are created using the `exercise` function. */ class Exercise { #execute = null Loading Loading @@ -203,9 +202,26 @@ class ExerciseExecutionContext { } /** * List of all exercises created using the `exericse` function. * A test. It has a human-readable name and a list of exercises. */ export const exercises = [] class Test { constructor(name, exercises) { this.name = name this.exercises = exercises } } /** * Create a test. Returns the test object * * @param {String} name A human-readable name of the test * @param {Function} exerciseCreationFunction A function that calls `exercise` to create exercise. * Note: This must be a function declared with the function keyword, arrow functions (()=>{...}) do not work. */ export function test(name, exerciseCreationFunction) { const exerciseCollector = { exercises: [], /** * Add an exercise. Loading @@ -214,7 +230,13 @@ export const exercises = [] * @param {Function} execute A function that executes the exercise. * Note: This must be a function declared with the function keyword, arrow functions (()=>{...}) do not work. */ export function exercise(name, execute) { exercise(name, execute) { const exerciseObj = new Exercise(name, execute) exercises.push(exerciseObj) this.exercises.push(exerciseObj) } } exerciseCreationFunction.bind(exerciseCollector)() return new Test(name, exerciseCollector.exercises) } static/js/exercises.mjs +5 −4 Changes for static/js/exercises.mjs: 5 added lines, 4 removed lines. Original line number Diff line number Diff line /** Exercises that students must pass to pass the pool test **/ import { exercise } from "./exercises.api.mjs"; export { exercises } from "./exercises.api.mjs" import { test } from "./exercises.api.mjs"; exercise("Datei anlegen", async function () { export const pooltest = test("Pooltest Sommersemester 2022", function () { this.exercise("Datei anlegen", async function () { this.describe(`Erstelle eine Datei mit dem Namen "botschaft" und dem Inhalt "Der Junge sieht den Mann mit dem Fernglas." (jeweils ohne Anführungszeichen)`) Loading @@ -14,7 +14,7 @@ exercise("Datei anlegen", async function () { this.verify("cat botschaft").hasOutput("Der Junge sieht den Mann mit dem Fernglas.") }) exercise("Berechtigungen anpassen", async function () { this.exercise("Berechtigungen anpassen", async function () { this.describe(`Ändere die Berechtigungen der Datei "/resources/supergeheim" so, dass nur der Besitzer sie anzeigen kann (und sonst niemand).`) Loading @@ -31,3 +31,4 @@ exercise("Berechtigungen anpassen", async function () { // To add another exercise, simply copy and paste an exercise(...) block from above and adjust it. // Order is respected, so you can e.g. order the exercises by increasing difficulty. }) static/js/state.mjs +5 −5 Changes for static/js/state.mjs: 5 added lines, 5 removed lines. Original line number Diff line number Diff line /** Read and modify the current state of the application. Allows saving to local storage. */ import { exercises } from "./exercises.mjs" import { pooltest } from "./exercises.mjs" export const currentState = { Loading Loading @@ -46,8 +46,8 @@ export const currentState = { throw new Error("index must be a number") } if (index < 0 || index > exercises.length) { throw new Error(`Exercise index must be >= 0 and < exercises.length (${exercises.length})`) if (index < 0 || index > pooltest.exercises.length) { throw new Error(`Exercise index must be >= 0 and < exercises.length (${pooltest.exercises.length})`) } localStorage.setItem("exerciseIndex", index) Loading Loading @@ -77,8 +77,8 @@ export const currentState = { throw new Error(`Can't solve the same exercise (${exerciseIndex}) twice`) } if (exerciseIndex < 0 || exerciseIndex > exercises.length) { throw new Error(`Exercise index must be >= 0 and < exercises.length (${exercises.length})`) if (exerciseIndex < 0 || exerciseIndex > pooltest.exercises.length) { throw new Error(`Exercise index must be >= 0 and < exercises.length (${pooltest.exercises.length})`) } const newIndices = this.solvedExercises Loading static/js/yalikejazz.mjs +6 −6 Changes for static/js/yalikejazz.mjs: 6 added lines, 6 removed lines. Original line number Diff line number Diff line import { currentState } from "./state.mjs" import { exercises } from "./exercises.mjs" import { pooltest } from "./exercises.mjs" import { getHandInToken } from "./snakeoil.mjs" import { createExerciseCard, displayAsSolved, displayAsNonCurrent, displayAsCurrent } from "./exercises.cards.mjs" function findNextUnsolvedExerciseIndex(currentExerciseIndex) { if (currentState.solvedExercises.length === exercises.length) { if (currentState.solvedExercises.length === pooltest.exercises.length) { return null } else { let nextUnsolvedExerciseIndex = currentExerciseIndex while (currentState.solvedExercises.includes(nextUnsolvedExerciseIndex)) { nextUnsolvedExerciseIndex = (nextUnsolvedExerciseIndex + 1) % exercises.length nextUnsolvedExerciseIndex = (nextUnsolvedExerciseIndex + 1) % pooltest.exercises.length } return nextUnsolvedExerciseIndex Loading Loading @@ -42,7 +42,7 @@ function createAndInitExerciseCard(exercise, exerciseIndex) { * meaning that description and action buttons are not visible). */ function initExerciseList() { document.querySelector("#exercises").append(...exercises.map(createAndInitExerciseCard)) document.querySelector("#exercises").append(...pooltest.exercises.map(createAndInitExerciseCard)) } /** Loading @@ -51,7 +51,7 @@ function initExerciseList() { */ function startExercise(exerciseIndex) { const cardEl = document.querySelector(`.exercise[data-exercise-index='${exerciseIndex}']`) const exercise = exercises[exerciseIndex] const exercise = pooltest.exercises[exerciseIndex] currentState.exerciseIndex = exerciseIndex exercise.onDescribed(description => cardEl.querySelector(".description").textContent = description) Loading Loading @@ -108,7 +108,7 @@ function initActionLinks() { } export function main() { document.querySelector("#exerciseCnt").textContent = exercises.length document.querySelector("#exerciseCnt").textContent = pooltest.exercises.length if (currentState.firstStart) { // Show welcome message document.body.classList.add("overlay-shown") Loading Loading
static/js/exercises.api.mjs +28 −6 Changes for static/js/exercises.api.mjs: 28 added lines, 6 removed lines. Original line number Diff line number Diff line Loading @@ -12,8 +12,7 @@ import { arrayEquals } from "./util.mjs" * exercises.mjs. * * Instances of this class are not created directly by the user, instead, * they are created using the `exercise` function which will also immediately * add them to the global list of exercises. * they are created using the `exercise` function. */ class Exercise { #execute = null Loading Loading @@ -203,9 +202,26 @@ class ExerciseExecutionContext { } /** * List of all exercises created using the `exericse` function. * A test. It has a human-readable name and a list of exercises. */ export const exercises = [] class Test { constructor(name, exercises) { this.name = name this.exercises = exercises } } /** * Create a test. Returns the test object * * @param {String} name A human-readable name of the test * @param {Function} exerciseCreationFunction A function that calls `exercise` to create exercise. * Note: This must be a function declared with the function keyword, arrow functions (()=>{...}) do not work. */ export function test(name, exerciseCreationFunction) { const exerciseCollector = { exercises: [], /** * Add an exercise. Loading @@ -214,7 +230,13 @@ export const exercises = [] * @param {Function} execute A function that executes the exercise. * Note: This must be a function declared with the function keyword, arrow functions (()=>{...}) do not work. */ export function exercise(name, execute) { exercise(name, execute) { const exerciseObj = new Exercise(name, execute) exercises.push(exerciseObj) this.exercises.push(exerciseObj) } } exerciseCreationFunction.bind(exerciseCollector)() return new Test(name, exerciseCollector.exercises) }
static/js/exercises.mjs +5 −4 Changes for static/js/exercises.mjs: 5 added lines, 4 removed lines. Original line number Diff line number Diff line /** Exercises that students must pass to pass the pool test **/ import { exercise } from "./exercises.api.mjs"; export { exercises } from "./exercises.api.mjs" import { test } from "./exercises.api.mjs"; exercise("Datei anlegen", async function () { export const pooltest = test("Pooltest Sommersemester 2022", function () { this.exercise("Datei anlegen", async function () { this.describe(`Erstelle eine Datei mit dem Namen "botschaft" und dem Inhalt "Der Junge sieht den Mann mit dem Fernglas." (jeweils ohne Anführungszeichen)`) Loading @@ -14,7 +14,7 @@ exercise("Datei anlegen", async function () { this.verify("cat botschaft").hasOutput("Der Junge sieht den Mann mit dem Fernglas.") }) exercise("Berechtigungen anpassen", async function () { this.exercise("Berechtigungen anpassen", async function () { this.describe(`Ändere die Berechtigungen der Datei "/resources/supergeheim" so, dass nur der Besitzer sie anzeigen kann (und sonst niemand).`) Loading @@ -31,3 +31,4 @@ exercise("Berechtigungen anpassen", async function () { // To add another exercise, simply copy and paste an exercise(...) block from above and adjust it. // Order is respected, so you can e.g. order the exercises by increasing difficulty. })
static/js/state.mjs +5 −5 Changes for static/js/state.mjs: 5 added lines, 5 removed lines. Original line number Diff line number Diff line /** Read and modify the current state of the application. Allows saving to local storage. */ import { exercises } from "./exercises.mjs" import { pooltest } from "./exercises.mjs" export const currentState = { Loading Loading @@ -46,8 +46,8 @@ export const currentState = { throw new Error("index must be a number") } if (index < 0 || index > exercises.length) { throw new Error(`Exercise index must be >= 0 and < exercises.length (${exercises.length})`) if (index < 0 || index > pooltest.exercises.length) { throw new Error(`Exercise index must be >= 0 and < exercises.length (${pooltest.exercises.length})`) } localStorage.setItem("exerciseIndex", index) Loading Loading @@ -77,8 +77,8 @@ export const currentState = { throw new Error(`Can't solve the same exercise (${exerciseIndex}) twice`) } if (exerciseIndex < 0 || exerciseIndex > exercises.length) { throw new Error(`Exercise index must be >= 0 and < exercises.length (${exercises.length})`) if (exerciseIndex < 0 || exerciseIndex > pooltest.exercises.length) { throw new Error(`Exercise index must be >= 0 and < exercises.length (${pooltest.exercises.length})`) } const newIndices = this.solvedExercises Loading
static/js/yalikejazz.mjs +6 −6 Changes for static/js/yalikejazz.mjs: 6 added lines, 6 removed lines. Original line number Diff line number Diff line import { currentState } from "./state.mjs" import { exercises } from "./exercises.mjs" import { pooltest } from "./exercises.mjs" import { getHandInToken } from "./snakeoil.mjs" import { createExerciseCard, displayAsSolved, displayAsNonCurrent, displayAsCurrent } from "./exercises.cards.mjs" function findNextUnsolvedExerciseIndex(currentExerciseIndex) { if (currentState.solvedExercises.length === exercises.length) { if (currentState.solvedExercises.length === pooltest.exercises.length) { return null } else { let nextUnsolvedExerciseIndex = currentExerciseIndex while (currentState.solvedExercises.includes(nextUnsolvedExerciseIndex)) { nextUnsolvedExerciseIndex = (nextUnsolvedExerciseIndex + 1) % exercises.length nextUnsolvedExerciseIndex = (nextUnsolvedExerciseIndex + 1) % pooltest.exercises.length } return nextUnsolvedExerciseIndex Loading Loading @@ -42,7 +42,7 @@ function createAndInitExerciseCard(exercise, exerciseIndex) { * meaning that description and action buttons are not visible). */ function initExerciseList() { document.querySelector("#exercises").append(...exercises.map(createAndInitExerciseCard)) document.querySelector("#exercises").append(...pooltest.exercises.map(createAndInitExerciseCard)) } /** Loading @@ -51,7 +51,7 @@ function initExerciseList() { */ function startExercise(exerciseIndex) { const cardEl = document.querySelector(`.exercise[data-exercise-index='${exerciseIndex}']`) const exercise = exercises[exerciseIndex] const exercise = pooltest.exercises[exerciseIndex] currentState.exerciseIndex = exerciseIndex exercise.onDescribed(description => cardEl.querySelector(".description").textContent = description) Loading Loading @@ -108,7 +108,7 @@ function initActionLinks() { } export function main() { document.querySelector("#exerciseCnt").textContent = exercises.length document.querySelector("#exerciseCnt").textContent = pooltest.exercises.length if (currentState.firstStart) { // Show welcome message document.body.classList.add("overlay-shown") Loading