Always offer the teacher-layer selector via ?exe-teacher=1#62
Merged
Conversation
Contributor
Preview this PR in the Nextcloud PlaygroundA fresh Nextcloud boots in your browser with this branch's eXeLearning editor: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
eXeLearning core (PR exelearning/exelearning#1972, fixes #1772) now hides teacher-only content by default in exports and previews. Revealing it requires loading the package with
?exe-teacher=1, which makes an in-package "teacher layer" selector available (OFF by default; the viewer activates it, the choice is persisted inlocalStorage, and the package's own JS propagates the param across in-package navigation).Nextcloud has no teacher-mode handling today — it just renders the ELPX viewer in a sandboxed iframe. After #1972 merges, the viewer would serve the student view only and teacher-only content would become unreachable (a regression vs today, where the core showed the toggle to everyone).
Because the Nextcloud viewer is a personal file viewer — the person opening the package is effectively its author/teacher — we always make the selector available by appending
?exe-teacher=1to the package index URL.Implementation
The param is appended in one place:
buildSandboxedIframe()insrc/elpx/iframe-renderer.ts, via a smallwithTeacherMode()helper.This is the single funnel where the resolved index URL becomes
iframe.src. Both rendering paths pass through it with the index entry only:createPackageIframe()→buildSandboxedIframe(), andattachServerIframe()→buildSandboxedIframe().Subresources are never built here; they are fetched by the package's own relative links (resolved by the SW or the
AssetController). So only the top-level page carries the param, and the package's JS propagates it onward — exactly the core contract.Why it's Service-Worker-safe: the SW keys requests on
url.pathnameonly (src/sw/exelearning-sw.js→matchRuntimeUrl(url.pathname)), andparseRuntimeUrl()/path resolution inpaths.tsparse the pathname too. An extra query string on the index src is therefore harmless and does not affect request matching. The helper also guards against a double-append (includes('?') ? '&' : '?', and a no-op when the param is already present).Testing
Commands run from the repo root (Node 22):
npx vitest run tests/js/iframe-renderer.test.ts→ 5 passed (new spec)npx vitest run→ 59 passed (6 files; full suite)npx eslint --ext .js,.ts,.vue --max-warnings 0 src→ clean (exit 0)npx biome lint src/elpx/iframe-renderer.ts tests/js/iframe-renderer.test.ts→ no findingsnpx vue-tsc --noEmit→ clean (exit 0)The new spec (
tests/js/iframe-renderer.test.ts) asserts the built iframesrccontainsexe-teacher=1for both the runtime and asset-fallback index URLs, uses&when a query already exists, and never double-appends.Why this fits the future direction
Teacher-layer visibility is driven purely by the package's own URL parameter, with no host DOM/CSS/JS injection into the iframe content. The host only chooses the entry URL; everything else lives inside the sandboxed package. This advances the goal of isolating embedded resource content from the host.