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;
var payload = JSON.stringify({ images: selectedImages });
if (selectedImages.length <= 3) {
// 1-3 Bilder: normales AJAX, Server gibt JSON mit URLs
$.ajax({ $.ajax({
url: '/api/download/selected', url: '/api/download/selected',
type: 'POST', type: 'POST',
contentType: 'application/json', contentType: 'application/json',
data: JSON.stringify({ images: selectedImages }), data: payload,
xhrFields: { responseType: 'blob' }, success: function(resp) {
success: function(data, status, xhr) {
var ct = xhr.getResponseHeader('Content-Type');
if (ct && ct.indexOf('application/json') !== -1) {
var reader = new FileReader();
reader.onload = function() {
var resp = JSON.parse(this.result);
if (resp.mode === 'individual') { if (resp.mode === 'individual') {
resp.urls.forEach(function(url, i) { resp.urls.forEach(function(url, i) {
setTimeout(function() { setTimeout(function() {
var a = document.createElement('a'); var a = document.createElement('a');
a.href = url; a.href = url;
a.download = ''; a.download = url.split('/').pop();
document.body.appendChild(a); document.body.appendChild(a);
a.click(); a.click();
document.body.removeChild(a); document.body.removeChild(a);
}, i * 300); }, i * 500);
}); });
} }
}; },
reader.readAsText(data); error: function(xhr) {
var msg = (xhr.responseJSON && xhr.responseJSON.error) || 'Download fehlgeschlagen';
alert(msg);
}
});
} else { } else {
var url = window.URL.createObjectURL(data); // 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 + ')');
} }
}, };
error: function(xhr) { reader.readAsText(xhr.response);
alert(xhr.responseJSON ? xhr.responseJSON.error : 'Download fehlgeschlagen'); }
};
xhr.onerror = function() {
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