Fix Download: Saubere Trennung JSON (1-3) vs ZIP (4+) Response

- 1-3 Bilder: normales AJAX ohne blob, JSON-Response direkt parsen
- 4+ Bilder: nativer XMLHttpRequest mit blob fuer ZIP-Download
- Fehler-Handler zeigt jetzt den echten Server-Fehler an
  (vorher war xhr.responseJSON immer undefined wegen blob)
- ZIP-Fehler: Blob wird als Text gelesen und JSON geparst
- Download-Dateiname aus URL extrahiert statt leer

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Kroonk
2026-04-16 23:52:47 +02:00
parent b65ade8381
commit 95f2847155
2 changed files with 56 additions and 34 deletions

View File

@@ -394,34 +394,43 @@
// Download-Button (direkt gebunden, nicht delegiert) // Download-Button (direkt gebunden, nicht delegiert)
$toolbar.on('click', '#sel-download', function() { $toolbar.on('click', '#sel-download', function() {
if (selectedImages.length === 0) return; if (selectedImages.length === 0) return;
$.ajax({ var payload = JSON.stringify({ images: selectedImages });
url: '/api/download/selected',
type: 'POST', if (selectedImages.length <= 3) {
contentType: 'application/json', // 1-3 Bilder: normales AJAX, Server gibt JSON mit URLs
data: JSON.stringify({ images: selectedImages }), $.ajax({
xhrFields: { responseType: 'blob' }, url: '/api/download/selected',
success: function(data, status, xhr) { type: 'POST',
var ct = xhr.getResponseHeader('Content-Type'); contentType: 'application/json',
if (ct && ct.indexOf('application/json') !== -1) { data: payload,
var reader = new FileReader(); success: function(resp) {
reader.onload = function() { if (resp.mode === 'individual') {
var resp = JSON.parse(this.result); resp.urls.forEach(function(url, i) {
if (resp.mode === 'individual') { setTimeout(function() {
resp.urls.forEach(function(url, i) { var a = document.createElement('a');
setTimeout(function() { a.href = url;
var a = document.createElement('a'); a.download = url.split('/').pop();
a.href = url; document.body.appendChild(a);
a.download = ''; a.click();
document.body.appendChild(a); document.body.removeChild(a);
a.click(); }, i * 500);
document.body.removeChild(a); });
}, i * 300); }
}); },
} error: function(xhr) {
}; var msg = (xhr.responseJSON && xhr.responseJSON.error) || 'Download fehlgeschlagen';
reader.readAsText(data); alert(msg);
} else { }
var url = window.URL.createObjectURL(data); });
} else {
// 4+ Bilder: Blob-Download fuer ZIP
var xhr = new XMLHttpRequest();
xhr.open('POST', '/api/download/selected', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.responseType = 'blob';
xhr.onload = function() {
if (xhr.status === 200) {
var url = window.URL.createObjectURL(xhr.response);
var a = document.createElement('a'); var a = document.createElement('a');
a.href = url; a.href = url;
a.download = 'mischkomposition-auswahl.zip'; a.download = 'mischkomposition-auswahl.zip';
@@ -429,12 +438,25 @@
a.click(); a.click();
window.URL.revokeObjectURL(url); window.URL.revokeObjectURL(url);
document.body.removeChild(a); document.body.removeChild(a);
} else {
// Fehler-Blob als Text lesen
var reader = new FileReader();
reader.onload = function() {
try {
var resp = JSON.parse(this.result);
alert(resp.error || 'Download fehlgeschlagen');
} catch(e) {
alert('Download fehlgeschlagen (Status ' + xhr.status + ')');
}
};
reader.readAsText(xhr.response);
} }
}, };
error: function(xhr) { xhr.onerror = function() {
alert(xhr.responseJSON ? xhr.responseJSON.error : 'Download fehlgeschlagen'); alert('Netzwerkfehler beim Download');
} };
}); xhr.send(payload);
}
}); });
// Abbrechen-Button (direkt gebunden) // Abbrechen-Button (direkt gebunden)

File diff suppressed because one or more lines are too long