Documentexport werkt niet op web: bestandskiezer kan geen pad vragen zonder bytes #1720

Closed
opened 2026-08-22 10:53:36 +00:00 by brenno · 0 comments
Owner

Probleem

Het exporteren van een document (PDF, Markdown, HTML, LaTeX) werkt niet op de web-build. Geen van de vier formaten komt de browser uit als download. De exportdialoog meldt dat het niet gelukt is en laat het document ongemoeid.

Eerder hing de knop oneindig op een spinner zonder melding. Dat is inmiddels opgelost door de ArgumentError te vangen in document_export_dialog.dart (regels 77-86), maar de onderliggende oorzaak staat er nog.

Validatie

Het document-exportpad mist de kIsWeb-tak die het deck-exportpad wél heeft.

Deck-export (lib/services/export_service.dart regels 271-283) doet het goed: de bytes worden eerst gebouwd, dan pas vertakt op kIsWeb. Op web gaat FilePicker.saveFile met bytes mee (Blob + anker = browser-download), op desktop wordt atomisch naar schijf geschreven.

Document-export (lib/widgets/document_editor_screen.dart _writeDocumentExport, regels 820-922) heeft geen kIsWeb-tak:

  1. _pickDocumentExportPath roept pickDocumentExportDestination aan, dat FilePicker.saveFile aanroept zonder bytes. Op web kan de bestandskiezer geen pad vragen zonder de bytes al te hebben, en gooit een ArgumentError.
  2. Zelfs als er een pad terugkwam, schrijft writeDocumentExport via writeStringAtomic(File(outputPath), ...) / writeBytesAtomic(File(outputPath), ...) — op web bestaat geen bestandssysteem.

De vangst in de dialoog (regels 77-86) bevestigt dit zelf: de commentaar zegt letterlijk dat de bestandskiezer op web geen pad kan kiezen zonder de bytes al te hebben en een ArgumentError gooit.

Root cause

De document-export is gebouwd als een desktop-pad: eerst pad kiezen, dan naar dat pad schrijven. Op web werkt dat niet — de browser wil de bytes up front als download, niet een pad om naartoe te schrijven.

Voorgestelde oplossing

Spiegel het deck-exportpatroon: bytes eerst bouwen, dan pas vertakken op kIsWeb.

  1. Splits writeDocumentExport in bouwen en schrijven. De PDF-tak heeft al buildDocumentExportPdf die bytes teruggeeft zonder te schrijven. De md/html/latex-takken bouwen nu een string en schrijven die direct weg — haal de string-bouw los van het wegschrijven, zodat er een functie ontstaat die Uint8List teruggeeft.
  2. Vertak in _writeDocumentExport op kIsWeb:
    • Op desktop: pad kiezen, dan writeDocumentExport naar pad (bestaande flow).
    • Op web: bytes bouwen, dan FilePicker.saveFile(fileName: fileName, bytes: bytes) (browser-download). Bestandsnaam via suggestedDocumentExportFileName (bestaat al).
  3. Bestandsnaam op web: suggestedDocumentExportFileName levert al de juiste naam met extensie en profiel-tag. Die kan direct als fileName mee.

Waarom de vertakking in writeDocumentExport zelf

writeDocumentExport is geregistreerd als SurfaceKind.audience-oppervlak in tool/check_audience_boundary.dart juist omdat het de enige plek is die writeStringAtomic/writeBytesAtomic raakt. Een kIsWeb-tak daarbinnen die FilePicker.saveFile doet in plaats van schrijven, houdt dat oppervlak intact — één plek waar documentinhoud de machine verlaat. Dat is de netste plek voor de vertakking.

Scope

  • Alleen document-export. Deck-export werkt al op web.
  • Geen bestandsformaat-wijziging, geen opslag-wijziging, geen nieuwe afhankelijkheid (file_picker is al aanwezig).
  • Het redactiemanifest (dat op web bij deck-export meegaat via _redactionManifestFiles) hoort hier ook mee te reizen — zelfde patroon.

Repro

  1. Open de web-build van OciDeck.
  2. Open een document.
  3. Kies Exporteren, kies een formaat (PDF/MD/HTML/LaTeX), Exporteren.
  4. Verwacht: browser-download van het bestand.
  5. Krijgt: dialoog meldt dat het niet gelukt is.

Labels

bug

## Probleem Het exporteren van een document (PDF, Markdown, HTML, LaTeX) werkt niet op de web-build. Geen van de vier formaten komt de browser uit als download. De exportdialoog meldt dat het niet gelukt is en laat het document ongemoeid. Eerder hing de knop oneindig op een spinner zonder melding. Dat is inmiddels opgelost door de `ArgumentError` te vangen in `document_export_dialog.dart` (regels 77-86), maar de onderliggende oorzaak staat er nog. ## Validatie Het document-exportpad mist de `kIsWeb`-tak die het deck-exportpad wél heeft. **Deck-export** (`lib/services/export_service.dart` regels 271-283) doet het goed: de bytes worden eerst gebouwd, dan pas vertakt op `kIsWeb`. Op web gaat `FilePicker.saveFile` met bytes mee (Blob + anker = browser-download), op desktop wordt atomisch naar schijf geschreven. **Document-export** (`lib/widgets/document_editor_screen.dart` `_writeDocumentExport`, regels 820-922) heeft geen `kIsWeb`-tak: 1. `_pickDocumentExportPath` roept `pickDocumentExportDestination` aan, dat `FilePicker.saveFile` aanroept **zonder bytes**. Op web kan de bestandskiezer geen pad vragen zonder de bytes al te hebben, en gooit een `ArgumentError`. 2. Zelfs als er een pad terugkwam, schrijft `writeDocumentExport` via `writeStringAtomic(File(outputPath), ...)` / `writeBytesAtomic(File(outputPath), ...)` — op web bestaat geen bestandssysteem. De vangst in de dialoog (regels 77-86) bevestigt dit zelf: de commentaar zegt letterlijk dat de bestandskiezer op web geen pad kan kiezen zonder de bytes al te hebben en een `ArgumentError` gooit. ## Root cause De document-export is gebouwd als een desktop-pad: eerst pad kiezen, dan naar dat pad schrijven. Op web werkt dat niet — de browser wil de bytes up front als download, niet een pad om naartoe te schrijven. ## Voorgestelde oplossing Spiegel het deck-exportpatroon: **bytes eerst bouwen, dan pas vertakken op `kIsWeb`**. 1. **Splits `writeDocumentExport` in bouwen en schrijven.** De PDF-tak heeft al `buildDocumentExportPdf` die bytes teruggeeft zonder te schrijven. De md/html/latex-takken bouwen nu een string en schrijven die direct weg — haal de string-bouw los van het wegschrijven, zodat er een functie ontstaat die `Uint8List` teruggeeft. 2. **Vertak in `_writeDocumentExport` op `kIsWeb`:** - Op desktop: pad kiezen, dan `writeDocumentExport` naar pad (bestaande flow). - Op web: bytes bouwen, dan `FilePicker.saveFile(fileName: fileName, bytes: bytes)` (browser-download). Bestandsnaam via `suggestedDocumentExportFileName` (bestaat al). 3. **Bestandsnaam op web:** `suggestedDocumentExportFileName` levert al de juiste naam met extensie en profiel-tag. Die kan direct als `fileName` mee. ### Waarom de vertakking in `writeDocumentExport` zelf `writeDocumentExport` is geregistreerd als `SurfaceKind.audience`-oppervlak in `tool/check_audience_boundary.dart` juist omdat het de enige plek is die `writeStringAtomic`/`writeBytesAtomic` raakt. Een `kIsWeb`-tak daarbinnen die `FilePicker.saveFile` doet in plaats van schrijven, houdt dat oppervlak intact — één plek waar documentinhoud de machine verlaat. Dat is de netste plek voor de vertakking. ### Scope - Alleen document-export. Deck-export werkt al op web. - Geen bestandsformaat-wijziging, geen opslag-wijziging, geen nieuwe afhankelijkheid (`file_picker` is al aanwezig). - Het redactiemanifest (dat op web bij deck-export meegaat via `_redactionManifestFiles`) hoort hier ook mee te reizen — zelfde patroon. ## Repro 1. Open de web-build van OciDeck. 2. Open een document. 3. Kies Exporteren, kies een formaat (PDF/MD/HTML/LaTeX), Exporteren. 4. Verwacht: browser-download van het bestand. 5. Krijgt: dialoog meldt dat het niet gelukt is. ## Labels bug
brenno 2026-08-22 18:34:20 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
LibreKAT/Ocideck#1720
No description provided.