From 7bd1ab16da568e86142c96636cda641480f654b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leon=20B=C3=B6sche?= Date: Mon, 12 Jan 2026 01:40:10 +0100 Subject: [PATCH] Fix Collabora Online loading using form-based POST instead of URL params - Collabora's loleaflet.html expects WOPISrc as POST parameter, not URL query param - Changed from iframe with src= to form submission approach - Extract WOPISrc from URL and pass as hidden form input - This avoids 400 Bad Request from Collabora when using GET with URL params --- b0esche_cloud/lib/pages/document_viewer.dart | 85 ++++++++++++++------ 1 file changed, 62 insertions(+), 23 deletions(-) diff --git a/b0esche_cloud/lib/pages/document_viewer.dart b/b0esche_cloud/lib/pages/document_viewer.dart index dc0461d..2f8e451 100644 --- a/b0esche_cloud/lib/pages/document_viewer.dart +++ b/b0esche_cloud/lib/pages/document_viewer.dart @@ -404,8 +404,9 @@ class _DocumentViewerModalState extends State { final wopiSession = snapshot.data!; // Build Collabora Online viewer URL with WOPISrc + // Note: Don't double-encode the WOPISrc - Collabora expects the URL as-is final collaboraUrl = - 'https://of.b0esche.cloud/loleaflet/dist/loleaflet.html?WOPISrc=${Uri.encodeComponent(wopiSession.wopisrc)}'; + 'https://of.b0esche.cloud/loleaflet/dist/loleaflet.html?WOPISrc=${wopiSession.wopisrc}'; // Use WebView to display Collabora Online return _buildWebView(collaboraUrl); @@ -453,31 +454,69 @@ class _DocumentViewerModalState extends State { } Widget _buildCollaboraIframe(String collaboraUrl) { - // Register the iframe element - const String viewType = 'collabora-iframe'; - - // Create the iframe with proper attributes for Collabora Online - ui.platformViewRegistry.registerViewFactory(viewType, (int viewId) { - final iframe = html.IFrameElement() - ..src = collaboraUrl - ..style.border = 'none' - ..style.width = '100%' - ..style.height = '100%' - ..style.margin = '0' - ..style.padding = '0' - ..setAttribute( + // For Collabora Online, we need to use a form-based approach instead of iframe + // because loleaflet.html expects a POST request with WOPISrc in the body + + const String viewType = 'collabora-form-container'; + + ui.platformViewRegistry.registerViewFactory( + viewType, + (int viewId) { + // Create a container div for the form and iframe + final container = html.DivElement() + ..style.width = '100%' + ..style.height = '100%' + ..style.margin = '0' + ..style.padding = '0'; + + // Create a hidden form to POST to Collabora + final form = html.FormElement() + ..method = 'POST' + ..action = 'https://of.b0esche.cloud/loleaflet/dist/loleaflet.html' + ..target = 'collabora-frame' + ..style.display = 'none'; + + // Extract the WOPISrc value from the URL + final wopisrcValue = collaboraUrl.split('WOPISrc=').length > 1 + ? collaboraUrl.split('WOPISrc=')[1] + : ''; + + final wopisrcInput = html.InputElement() + ..type = 'hidden' + ..name = 'WOPISrc' + ..value = wopisrcValue; + + form.append(wopisrcInput); + container.append(form); + + // Create the iframe + final iframe = html.IFrameElement() + ..name = 'collabora-frame' + ..style.border = 'none' + ..style.width = '100%' + ..style.height = '100%' + ..style.margin = '0' + ..style.padding = '0'; + + // Set sandbox attributes + iframe.setAttribute( + 'sandbox', + 'allow-same-origin allow-scripts allow-popups allow-forms allow-top-navigation allow-pointer-lock allow-presentation allow-modals allow-downloads', + ); + + iframe.setAttribute( 'allow', 'microphone; camera; usb; autoplay; clipboard-read; clipboard-write', ); - - // Prevent sandbox restrictions that might block Collabora - iframe.setAttribute( - 'sandbox', - 'allow-same-origin allow-scripts allow-popups allow-forms allow-top-navigation allow-pointer-lock allow-presentation allow-modals', - ); - - return iframe; - }); + + container.append(iframe); + + // Submit the form to load the document + form.submit(); + + return container; + }, + ); return HtmlElementView(viewType: viewType); }