/** * lesson-html.ts — wire a lesson document up to the classroom runtime at serve time. * * Lessons on disk are plain, self-contained HTML: open one in a browser directly and * it still reads fine. Everything interactive (highlight-to-ask, quiz submission, * theming) is injected here, so a lesson authored months ago picks up runtime fixes * without being rewritten. */ import { toScriptJson } from "./markdown.js"; export interface LessonRuntimeConfig { classroom: string; lesson: string; classroomTitle: string; lessonTitle: string; baseUrl: string; } /** The `
` additions: shared stylesheet plus the no-flash theme bootstrap. */ function headInjection(): string { return ` `; } function bodyInjection(config: LessonRuntimeConfig): string { return ` `; } /** Insert `snippet` before the first ``, or fall back to prepending it. */ function insertInHead(html: string, snippet: string): string { const idx = html.search(/<\/head\s*>/i); if (idx !== -1) return html.slice(0, idx) + snippet + "\n" + html.slice(idx); // No — try after , else prepend. Lessons are model-authored and a // stray fragment must still render rather than 500. const bodyIdx = html.search(/]*>/i); if (bodyIdx !== -1) { const end = html.indexOf(">", bodyIdx) + 1; return html.slice(0, end) + "\n" + snippet + html.slice(end); } return snippet + "\n" + html; } /** Insert `snippet` before the last ``, or append it. */ function insertBeforeBodyEnd(html: string, snippet: string): string { const idx = html.toLowerCase().lastIndexOf(""); if (idx !== -1) return html.slice(0, idx) + snippet + "\n" + html.slice(idx); return html + "\n" + snippet; } /** * Add the classroom runtime to a lesson document. * * Idempotent: a lesson that already links the runtime (because the model copied a * served page back to disk) is returned unchanged rather than double-wired. */ export function injectLessonRuntime(html: string, config: LessonRuntimeConfig): string { if (html.includes('id="cl-config"')) return html; return insertBeforeBodyEnd(insertInHead(html, headInjection()), bodyInjection(config)); }