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
This commit is contained in:
Leon Bösche
2026-01-12 01:40:10 +01:00
parent d52307c792
commit 7bd1ab16da

View File

@@ -404,8 +404,9 @@ class _DocumentViewerModalState extends State<DocumentViewerModal> {
final wopiSession = snapshot.data!; final wopiSession = snapshot.data!;
// Build Collabora Online viewer URL with WOPISrc // Build Collabora Online viewer URL with WOPISrc
// Note: Don't double-encode the WOPISrc - Collabora expects the URL as-is
final collaboraUrl = 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 // Use WebView to display Collabora Online
return _buildWebView(collaboraUrl); return _buildWebView(collaboraUrl);
@@ -453,31 +454,69 @@ class _DocumentViewerModalState extends State<DocumentViewerModal> {
} }
Widget _buildCollaboraIframe(String collaboraUrl) { Widget _buildCollaboraIframe(String collaboraUrl) {
// Register the iframe element // For Collabora Online, we need to use a form-based approach instead of iframe
const String viewType = 'collabora-iframe'; // because loleaflet.html expects a POST request with WOPISrc in the body
// Create the iframe with proper attributes for Collabora Online const String viewType = 'collabora-form-container';
ui.platformViewRegistry.registerViewFactory(viewType, (int viewId) {
final iframe = html.IFrameElement() ui.platformViewRegistry.registerViewFactory(
..src = collaboraUrl viewType,
..style.border = 'none' (int viewId) {
..style.width = '100%' // Create a container div for the form and iframe
..style.height = '100%' final container = html.DivElement()
..style.margin = '0' ..style.width = '100%'
..style.padding = '0' ..style.height = '100%'
..setAttribute( ..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', 'allow',
'microphone; camera; usb; autoplay; clipboard-read; clipboard-write', 'microphone; camera; usb; autoplay; clipboard-read; clipboard-write',
); );
// Prevent sandbox restrictions that might block Collabora container.append(iframe);
iframe.setAttribute(
'sandbox',
'allow-same-origin allow-scripts allow-popups allow-forms allow-top-navigation allow-pointer-lock allow-presentation allow-modals',
);
return iframe; // Submit the form to load the document
}); form.submit();
return container;
},
);
return HtmlElementView(viewType: viewType); return HtmlElementView(viewType: viewType);
} }