feat: niet-lineaire navigatie — de sprong-uit (fase 1+2 van #1162) #1189

Merged
brenno merged 5 commits from feat/1162-nietlineaire-navigatie into main 2026-08-04 06:53:13 +00:00
Owner

Fase 1+2 van #1162 (niet-lineaire navigatie): de sprong-uit, op een herbruikbaar navigatiefundament. Het keuze-menu-diatype (feature 1) volgt als aparte PR hierop.

Wat dit doet

Een dia kan aangeven "hierna → dia X" in plaats van de eerstvolgende in bronvolgorde. Zo laat je een zijpad aan het eind terugkeren naar waar het aftakte.

  • Formaat — twee optionele Slide-velden die verliesvrij round-trippen als HTML-comments: anchor (<!-- ocideck_slide_anchor: … -->, stabiel doel-anker) en nextAnchor (<!-- ocideck_next: … -->, de sprong-uit). Beide leeg = een gewone dia, geen extra regel in het bestand.
  • Presentator_next honoreert de sprong (ook voorbij de laatste dia); "terug" volgt de werkelijk gelopen route via een navigatiestack (jouw keuze), niet de vorige brondia. Auto-play volgt dezelfde sprong maar vult de stack bewust niet (kiosk-lus zou hem laten groeien). Onvindbaar anker → fail-safe lineair, geen crash.
  • Editor — in de slide-instellingen ("Tijdens presenteren") kies je met Hierna een doeldia op kop; die krijgt zo nodig een uniek, bevroren anker (de gebruiker kiest een dia, nooit een anker). Een "Sprong"-badge toont de staat in de ingeklapte kop; een verwijderde doeldia geeft een waarschuwing.

Ontwerpkeuze (vastgelegd)

Stabiel mens-leesbaar anker i.p.v. index of uuid. Een index schuift bij invoegen/verwijderen; een kale uuid is onleesbaar in de ruwe .md. Het anker wordt geseed uit de kop-slug en daarna bevroren opgeslagen — hernoemen breekt een link niet. Het volledige formaatontwerp staat in issue #1162.

Bewaker-blik (formaat + publieke belofte geraakt)

  • Uitwisselbaar: de sprong-uit is negeerbare <!-- ocideck_* -->-comments; elke Marp-lezer toont het deck lineair. Geen base64, mens-leesbaar anker.
  • Als het project stopt: het deck blijft geldige Marp-.md en presenteert lineair in elk gereedschap — de uitgang is zo makkelijk als de ingang.
  • Geen nieuwe partij, geen netwerk, geen afhankelijkheid, geen sleutel.
  • Spanning (uitwisselbaarheid vs. rijke functie): opgelost door de branching in gewone Markdown-vorm te houden; geen waarde overruled.

Kwaliteit

  • make check volledig groen (analyze, format, conventies, methodelengte, dode code, hardcoded-tekst, l10n 23/23, volledige testsuite, dekkingsvloeren incl. per-file).
  • make check-secrets (gitleaks + trufflehog) en make sast (semgrep) schoon: 0 findings.
  • Nieuwe tests: round-trip (verliesvrij + schoon-bij-leeg), presentator (sprong/retrace/fail-safe), anker-helper + setSlideJump.
  • Docs bijgewerkt: FILE_FORMAT §8, USER_GUIDE, SOURCE_MAP, CHANGELOG. l10n voor 5 nieuwe strings in alle 31 talen.
  • Class/method/bestand-baselines opgerekt met de exacte, gemotiveerde delta; de pure berekeningen zijn bewust uit de klassen getild (slide_anchors.dart, top-level _indexOfAnchor/_firstDirective).

Nog niet in deze PR

  • Het keuze-menu-diatype (feature 1 van #1162) — volgt op dit fundament.
  • Beeldkeuring — uitgesteld naar het menu-diatype, want dat is het visuele "valt of staat"-oppervlak uit het issue; deze PR voegt alleen een dropdown toe in de bestaande settings-rij-stijl.
Fase 1+2 van #1162 (niet-lineaire navigatie): **de sprong-uit**, op een herbruikbaar navigatiefundament. Het keuze-menu-diatype (feature 1) volgt als aparte PR hierop. ## Wat dit doet Een dia kan aangeven "hierna → dia X" in plaats van de eerstvolgende in bronvolgorde. Zo laat je een zijpad aan het eind terugkeren naar waar het aftakte. - **Formaat** — twee optionele `Slide`-velden die verliesvrij round-trippen als HTML-comments: `anchor` (`<!-- ocideck_slide_anchor: … -->`, stabiel doel-anker) en `nextAnchor` (`<!-- ocideck_next: … -->`, de sprong-uit). Beide leeg = een gewone dia, geen extra regel in het bestand. - **Presentator** — `_next` honoreert de sprong (ook voorbij de laatste dia); "terug" volgt de **werkelijk gelopen route** via een navigatiestack (jouw keuze), niet de vorige brondia. Auto-play volgt dezelfde sprong maar vult de stack bewust niet (kiosk-lus zou hem laten groeien). Onvindbaar anker → fail-safe lineair, geen crash. - **Editor** — in de slide-instellingen ("Tijdens presenteren") kies je met **Hierna** een doeldia op kop; die krijgt zo nodig een uniek, bevroren anker (de gebruiker kiest een dia, nooit een anker). Een "Sprong"-badge toont de staat in de ingeklapte kop; een verwijderde doeldia geeft een waarschuwing. ## Ontwerpkeuze (vastgelegd) **Stabiel mens-leesbaar anker i.p.v. index of uuid.** Een index schuift bij invoegen/verwijderen; een kale uuid is onleesbaar in de ruwe `.md`. Het anker wordt geseed uit de kop-slug en daarna **bevroren opgeslagen** — hernoemen breekt een link niet. Het volledige formaatontwerp staat in issue #1162. ## Bewaker-blik (formaat + publieke belofte geraakt) - **Uitwisselbaar:** de sprong-uit is negeerbare `<!-- ocideck_* -->`-comments; elke Marp-lezer toont het deck lineair. Geen base64, mens-leesbaar anker. - **Als het project stopt:** het deck blijft geldige Marp-`.md` en presenteert lineair in elk gereedschap — de uitgang is zo makkelijk als de ingang. - **Geen nieuwe partij, geen netwerk, geen afhankelijkheid, geen sleutel.** - **Spanning** (uitwisselbaarheid vs. rijke functie): opgelost door de branching in gewone Markdown-vorm te houden; geen waarde overruled. ## Kwaliteit - `make check` volledig groen (analyze, format, conventies, methodelengte, dode code, hardcoded-tekst, l10n 23/23, volledige testsuite, dekkingsvloeren incl. per-file). - `make check-secrets` (gitleaks + trufflehog) en `make sast` (semgrep) schoon: 0 findings. - Nieuwe tests: round-trip (verliesvrij + schoon-bij-leeg), presentator (sprong/retrace/fail-safe), anker-helper + `setSlideJump`. - Docs bijgewerkt: FILE_FORMAT §8, USER_GUIDE, SOURCE_MAP, CHANGELOG. l10n voor 5 nieuwe strings in alle 31 talen. - Class/method/bestand-baselines opgerekt met de exacte, gemotiveerde delta; de pure berekeningen zijn bewust uit de klassen getild (`slide_anchors.dart`, top-level `_indexOfAnchor`/`_firstDirective`). ## Nog niet in deze PR - **Het keuze-menu-diatype** (feature 1 van #1162) — volgt op dit fundament. - **Beeldkeuring** — uitgesteld naar het menu-diatype, want dat is het visuele "valt of staat"-oppervlak uit het issue; deze PR voegt alleen een dropdown toe in de bestaande settings-rij-stijl.
Fase 1 van de niet-lineaire navigatie: het formaatfundament dat de sprong-uit
en het menu-slidetype straks delen. Twee nieuwe, optionele Slide-velden die
verliesvrij round-trippen als HTML-comments:

- `anchor` (`<!-- ocideck_slide_anchor: … -->`): een stabiel in-deck anker waar
  een dia het doel van kan zijn. Bedoeld om uit de kop-slug geseed en daarna
  bevroren te worden, zodat hernoemen een link niet breekt — anders dan de
  vluchtige parse-tijd-uuid `id` overleeft dit een opslag/herlaad-ronde.
- `nextAnchor` (`<!-- ocideck_next: … -->`): per-dia sprong-uit. Leeg = de
  bestaande lineaire volgorde; een sprong naar een verdwenen anker valt
  fail-safe terug op lineair.

Beide leeg = een gewone dia zonder een enkele extra regel in het bestand.
Nog geen gedrag of UI — dat komt in de sprong-uit- en menu-fases hierop.

- velden + doc + constructor/copyWith-doorvoer in Slide
- schrijven in de top-level `_writeSlideDirectives`, lezen in
  `_parseBlockDirectives`, geregistreerd in het validator-vocabulaire
- FILE_FORMAT §8 gedocumenteerd
- round-trip- en "schoon bij leeg"-tests
- bestand- en class-baseline opgerekt met de exacte, gemotiveerde delta

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fase 2-kern: de presentator honoreert nu de per-dia sprong-uit (`nextAnchor`).

- `_next` springt naar het doelanker als dat er is en vindbaar is — ook voorbij
  de laatste dia, zodat een tak terug naar het menu kan keren. Onvindbaar anker
  valt fail-safe terug op de lineaire volgorde.
- "Terug" (`_prev`) volgt de werkelijk gelopen route via een retrace-stack
  (`_jumpHistory`): na een menusprong keer je terug náár het menu, niet naar de
  vorige brondia. Een lineair deck heeft `[0,1,2,…]` op de stack en gedraagt zich
  precies als voorheen; een expliciete teleport (raster/nummer/Home/End) wist de
  stack.
- Auto-play volgt dezelfde sprong-uit, maar vult de stack bewust niet (een
  kiosk-lus zou hem eindeloos laten groeien).
- Anker-resolutie als top-level `_indexOfAnchor`, naast `_exitSlideId`, zodat de
  presenter-state niet onnodig groeit.

Nog geen editor-UI om de sprong te zetten — dat komt hierop; nu round-trippt en
werkt hij vanuit de Markdown. Tests dekken sprong, retrace en fail-safe.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Maakt de sprong-uit bruikbaar zonder Markdown te typen. In de slide-instellingen
("Tijdens presenteren") staat nu "Hierna": een keuzelijst die de dia's op kop
toont. Kies je een doeldia, dan krijgt die zo nodig een uniek, bevroren anker en
wijst deze dia daarheen — de gebruiker kiest een dia, nooit een anker.

- `slide_anchors.dart`: pure helpers `slugifyAnchor` (ASCII-veilige slug uit de
  kop, terugval `dia`), `uniqueAnchor` (botsing → `-2`, `-3`, …) en
  `slidesWithJump` (de lijstberekening achter de deck-operatie, los testbaar).
- `DeckNotifier.setSlideJump`: dunne delegator die beide dia's in één stap
  muteert; `null`-doel wist de sprong, sprong-naar-zichzelf wordt genegeerd.
- Editor: de "Hierna"-rij + een "Sprong"-badge in de ingeklapte kop (zichtbare
  staat), en een waarschuwing als de doeldia verwijderd is (verweesde
  verwijzing, geen crash).
- l10n: vijf nieuwe strings in alle 31 talen + Engelse fallback.
- Tests voor de helpers en de deck-operatie (anker toekennen, bevriezen, wissen,
  self-sprong negeren).

Baselines (class/method) opgerekt met de exacte, gemotiveerde delta; de pure
berekening is bewust uit de klasse en de parse-methode getild.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
docs(1162): documenteer de sprong-uit + dart format
All checks were successful
scans / scans (pull_request) Successful in 1m33s
static-gate / static-gate (pull_request) Successful in 4m52s
06a94f2f41
- USER_GUIDE: nieuwe subsectie "Non-linear order: jump to another slide" onder
  Presenting, en de per-slide-optieregel verwijst ernaar.
- CHANGELOG (Unreleased/Added): de "Hierna"-sprong, met de kanttekening dat dit
  de eerste helft van #1162 is (het menu-diatype volgt).
- SOURCE_MAP: slide_anchors.dart beschreven.
- dart format op vier bestanden uit de vorige commits die nog niet
  format-conform waren.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Merge remote-tracking branch 'origin/main' into feat/1162-nietlineaire-navigatie
All checks were successful
scans / scans (pull_request) Successful in 1m31s
static-gate / static-gate (pull_request) Successful in 3m55s
532f8f4616
brenno merged commit bb7b7d03ef into main 2026-08-04 06:53:13 +00:00
Sign in to join this conversation.
No description provided.