Fix: admin.html wird beim Update automatisch mitgespeichert (v1.2.3)

Blob-URL-Ansatz rückgängig gemacht (localStorage-Problem), stattdessen
beide Dateien gemeinsam per showSaveFilePicker aktualisieren.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Christian Heubaum
2026-04-21 21:10:12 +02:00
parent 6dcfcfa4a6
commit 875ef0d42f
2 changed files with 36 additions and 33 deletions

View File

@@ -1713,7 +1713,7 @@
// ============================================================
// CONSTANTS & CHAPTER CONFIG
// ============================================================
const APP_VERSION = '1.2.2';
const APP_VERSION = '1.2.3';
const GITEA_RAW = 'http://72.60.134.73:3000/api/v1/repos/cheubaum/BNI-Vorstellungsrunde/raw';
const GITEA_API = 'http://72.60.134.73:3000/api/v1/repos/cheubaum/BNI-Vorstellungsrunde';
function giteaUrl(path) { return `${GITEA_RAW}/${path}?ref=main`; }
@@ -1893,7 +1893,7 @@ function renderStammvertreterSection() {
if (!container) return;
const list = loadStammvertreter();
if (list.length === 0) {
container.innerHTML = `<div style="color:var(--muted);font-size:0.82rem;padding:2px 0 8px;">Noch keine gespeichert. → <a href="#" onclick="openAdminPanel();return false;" style="color:var(--red);">Admin öffnen</a> zum Importieren aus anderen Chaptern.</div>`;
container.innerHTML = `<div style="color:var(--muted);font-size:0.82rem;padding:2px 0 8px;">Noch keine gespeichert. → <a href="admin.html" target="_blank" style="color:var(--red);">Admin öffnen</a> zum Importieren aus anderen Chaptern.</div>`;
return;
}
container.innerHTML = '';
@@ -4346,23 +4346,38 @@ async function downloadUpdate(version) {
}
} catch(e) { alert('Keine Serververbindung möglich.'); return; }
let html;
let html, adminHtml;
try {
const res = await fetch(giteaUrl('index.html'), { cache: 'no-store' });
html = await res.text();
const [r1, r2] = await Promise.all([
fetch(giteaUrl('index.html'), { cache: 'no-store' }),
fetch(giteaUrl('admin.html'), { cache: 'no-store' }),
]);
html = await r1.text();
adminHtml = await r2.text();
} catch(e) { alert('Download fehlgeschlagen: ' + e.message); return; }
if ('showSaveFilePicker' in window) {
try {
const fileHandle = await window.showSaveFilePicker({
const fh1 = await window.showSaveFilePicker({
suggestedName: 'index.html',
types: [{ description: 'HTML-Datei', accept: { 'text/html': ['.html'] } }],
id: 'bni-update',
startIn: 'documents',
});
const writable = await fileHandle.createWritable();
await writable.write(html);
await writable.close();
const w1 = await fh1.createWritable();
await w1.write(html);
await w1.close();
const fh2 = await window.showSaveFilePicker({
suggestedName: 'admin.html',
types: [{ description: 'HTML-Datei', accept: { 'text/html': ['.html'] } }],
id: 'bni-update',
startIn: 'documents',
});
const w2 = await fh2.createWritable();
await w2.write(adminHtml);
await w2.close();
if (confirm('Update erfolgreich eingespielt!\n\nSeite jetzt neu laden?')) location.reload();
return;
} catch(e) {
@@ -4372,13 +4387,15 @@ async function downloadUpdate(version) {
}
// Fallback für Browser ohne File System Access API
const blob = new Blob([html], { type: 'text/html' });
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = 'index.html';
a.click();
URL.revokeObjectURL(a.href);
alert('Datei wurde heruntergeladen.\nBitte die alte index.html damit ersetzen und die Seite neu laden.');
for (const [name, content] of [['index.html', html], ['admin.html', adminHtml]]) {
const blob = new Blob([content], { type: 'text/html' });
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = name;
a.click();
URL.revokeObjectURL(a.href);
}
alert('Dateien wurden heruntergeladen.\nBitte index.html und admin.html ersetzen und die Seite neu laden.');
}
async function fetchChapterMembersFromGitea() {
@@ -4492,7 +4509,7 @@ function renderAdminPanel() {
</div>
<button class="btn btn-secondary btn-sm" style="width:100%;margin-bottom:6px;" onclick="fetchChapterMembersFromGitea()">🔄 Mitglieder vom Server laden</button>
<div style="font-size:0.78rem;color:var(--muted);margin-bottom:16px;">Letzter Download: ${lastSync}</div>
<button onclick="openAdminPanel()" class="btn btn-primary btn-sm" style="width:100%;display:block;margin-bottom:16px;">⚙ Admin-Panel öffnen</button>
<a href="admin.html" target="_blank" class="btn btn-primary btn-sm" style="width:100%;display:block;text-align:center;text-decoration:none;margin-bottom:16px;">⚙ Admin-Panel öffnen</a>
` : `<div style="color:var(--muted);font-size:0.88rem;margin-bottom:20px;">Kein Chapter aktiviert.</div>`}
<div style="border-top:1px solid var(--border);padding-top:14px;margin-bottom:14px;">
<div style="font-size:0.78rem;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:1px;margin-bottom:10px;">Einstellungen</div>
@@ -4509,20 +4526,6 @@ function renderAdminPanel() {
</div>`;
}
async function openAdminPanel() {
try {
const res = await fetch(giteaUrl('admin.html'), { cache: 'no-store' });
if (!res.ok) throw new Error('Nicht erreichbar');
const html = await res.text();
const blob = new Blob([html], { type: 'text/html' });
const url = URL.createObjectURL(blob);
window.open(url, '_blank', 'noopener');
setTimeout(() => URL.revokeObjectURL(url), 10000);
} catch(e) {
alert('Admin-Panel konnte nicht geladen werden.\nBitte Internetverbindung prüfen.');
}
}
function confirmSwitchChapter() {
if (!confirm('Chapter wechseln?\n\nAlle lokalen Daten dieses Chapters werden gelöscht. Fortfahren?')) return;
clearChapterData();