diff --git a/BungeeCord-Chrome/popup.js b/BungeeCord-Chrome/popup.js
index f423981..448d8e8 100644
--- a/BungeeCord-Chrome/popup.js
+++ b/BungeeCord-Chrome/popup.js
@@ -1,353 +1,384 @@
-const $ = id => document.getElementById(id);
-const uid = () => 'srv_' + Math.random().toString(36).slice(2,9);
-
-const inputName = $('inputName');
-const inputUrl = $('inputUrl');
-const inputWpSite = $('inputWpSite');
-const inputWpServerId = $('inputWpServerId');
-const btnAdd = $('btnAddServer');
-const serversContainer = $('serversContainer');
-const serverListPanel = document.querySelector('.server-list');
-const btnRefresh = $('btnRefresh');
-const btnToggleSettings = $('btnToggleSettings');
-const settingsForm = $('settingsForm');
-
-const noSelection = $('noSelection');
-const detailContent = $('detailContent');
-const detailName = $('detailName');
-const detailUrlText = $('detailUrlText');
-const detailStatus = $('detailStatus');
-const detailPulse = $('detailPulse');
-const detailVersion = $('detailVersion');
-const detailPlayers = $('detailPlayers');
-const detailPing = $('detailPing');
-const detailPlayerList = $('detailPlayerList');
-const btnEdit = $('btnEdit');
-const btnDelete = $('btnDelete');
-
-let servers = [];
-let selectedId = null;
-let statuses = {};
-let previousStatuses = {};
-let settingsVisible = false;
-
-document.addEventListener('DOMContentLoaded', init);
-btnAdd.addEventListener('click', handleAdd);
-btnRefresh.addEventListener('click', manualRefresh);
-btnToggleSettings.addEventListener('click', toggleSettings);
-btnEdit.addEventListener('click', handleEdit);
-btnDelete.addEventListener('click', handleDelete);
-
-async function init() {
- await loadServersFromStorage();
- await loadStatusesFromStorage();
- await loadSettingsVisibility();
- renderServerList();
-
- if (servers.length === 1) selectedId = servers[0].id;
- renderDetail(selectedId);
-
- adjustDetailLayout();
-}
-
-// --- Settings Visibility ---
-async function loadSettingsVisibility() {
- const obj = await chrome.storage.local.get(['settingsVisible']);
- settingsVisible = obj.settingsVisible !== undefined ? obj.settingsVisible : false;
- if (!settingsVisible) settingsForm.classList.add('hidden');
- else settingsForm.classList.remove('hidden');
-}
-
-async function saveSettingsVisibility() {
- await chrome.storage.local.set({ settingsVisible });
-}
-
-async function toggleSettings() {
- settingsVisible = !settingsVisible;
- settingsForm.classList.toggle('hidden');
- await saveSettingsVisibility();
- adjustDetailLayout();
-}
-
-// --- Storage ---
-async function loadServersFromStorage() {
- const obj = await chrome.storage.local.get(['servers']);
- servers = obj.servers || [];
- for (const s of servers) if (!s.id) s.id = uid();
- await chrome.storage.local.set({ servers });
-}
-
-async function saveServersToStorage() {
- await chrome.storage.local.set({ servers });
-}
-
-async function loadStatusesFromStorage() {
- const obj = await chrome.storage.local.get(['serverStatuses']);
- statuses = obj.serverStatuses || {};
-}
-
-// --- Layout ---
-function adjustDetailLayout() {
- const settingsHidden = settingsForm.classList.contains('hidden');
- detailContent.classList.toggle('full-width', settingsHidden);
- serverListPanel.classList.toggle('hidden', settingsHidden);
- btnEdit.style.display = settingsHidden ? 'none' : 'inline-block';
- btnDelete.style.display = settingsHidden ? 'none' : 'inline-block';
-}
-
-// --- Render Server List ---
-function renderServerList() {
- serversContainer.innerHTML = '';
- if (servers.length === 0) {
- serversContainer.innerHTML = '
Noch keine Server hinzugefügt.
';
- return;
- }
-
- for (const s of servers) {
- const item = document.createElement('li');
- item.className = 'server-item';
- item.dataset.id = s.id;
-
- const meta = document.createElement('div');
- meta.className = 'meta';
- const name = document.createElement('div'); name.className = 'name';
- name.textContent = s.name || '(Kein Name)';
-
- let listUrl = s.url || (s.wpSite ? s.wpSite + ' (WP)' : '');
- listUrl = listUrl.replace(':9191', '');
-
- const url = document.createElement('div'); url.className = 'url';
- url.textContent = listUrl;
- meta.append(name, url);
-
- const statusBubble = document.createElement('div');
- statusBubble.className = 'status-bubble';
- statusBubble.textContent = '—';
- statusBubble.style.backgroundColor = 'transparent';
- item.statusBubble = statusBubble;
-
- item.append(meta, statusBubble);
- item.addEventListener('click', () => {
- selectedId = s.id;
- renderDetail(selectedId);
- });
-
- serversContainer.appendChild(item);
- }
- updateServerListStatuses(false);
-}
-
-// --- Render Detail ---
-function renderDetail(id) {
- if (!id) {
- noSelection.classList.remove('hidden');
- detailContent.classList.add('hidden');
- return;
- }
- const srv = servers.find(x => x.id === id);
- if (!srv) {
- noSelection.classList.remove('hidden');
- detailContent.classList.add('hidden');
- return;
- }
- noSelection.classList.add('hidden');
- detailContent.classList.remove('hidden');
-
- detailName.textContent = srv.name || 'Unbenannter Server';
-
- let urlToShow = srv.url || (srv.wpSite ? srv.wpSite : 'Lokal');
- urlToShow = urlToShow.replace(':9191', '');
-
- detailUrlText.textContent = urlToShow;
-
- updateDetailForServer(srv, true);
-}
-
-// --- Update Detail ---
-function updateDetailForServer(srv, force = false) {
- const st = statuses[srv.id];
- const prevSt = previousStatuses[srv.id];
-
- const statusChanged = force ||
- !prevSt ||
- (prevSt.ok !== st?.ok) ||
- (prevSt.data?.online !== st?.data?.online);
-
- if (!st || !st.ok || !st.data) {
- if (statusChanged) {
- detailStatus.textContent = 'Offline';
- detailPulse.classList.remove('online');
- detailVersion.textContent = '-';
- detailPlayers.textContent = '-';
- detailPing.textContent = '-';
- updatePlayerList([]);
- }
- } else {
- const d = st.data;
-
- if (statusChanged) {
- detailStatus.textContent = d.online ? 'Online' : 'Offline';
- if (d.online) {
- detailPulse.classList.add('online');
- } else {
- detailPulse.classList.remove('online');
- }
- }
-
- const newVersion = d.version || 'unknown';
- if (force || detailVersion.textContent !== newVersion) {
- detailVersion.textContent = newVersion;
- }
-
- const playersCount = Array.isArray(d.players) ? d.players.length : (typeof d.players === 'number' ? d.players : 0);
- const maxPlayers = d.max_players;
- let newPlayersText = String(playersCount);
- if (maxPlayers) newPlayersText += ` / ${maxPlayers}`;
-
- if (force || detailPlayers.textContent !== newPlayersText) {
- detailPlayers.textContent = newPlayersText;
- }
-
- let pingVal = d.ping || d.latency || '-';
- if (pingVal !== '-' && typeof pingVal === 'number') {
- pingVal = pingVal + ' ms';
- }
-
- if (force || (pingVal !== '-' && detailPing.textContent !== pingVal)) {
- detailPing.textContent = pingVal;
- }
-
- const currentPlayers = Array.isArray(d.players) ? d.players : [];
- const prevPlayers = (prevSt && Array.isArray(prevSt.data.players)) ? prevSt.data.players : [];
-
- let playersChanged = false;
- if (force) {
- playersChanged = true;
- } else {
- playersChanged = JSON.stringify(currentPlayers) !== JSON.stringify(prevPlayers);
- }
-
- if (playersChanged) {
- updatePlayerList(currentPlayers);
- }
- }
-
- previousStatuses[srv.id] = st ? JSON.parse(JSON.stringify(st)) : null;
-}
-
-// --- Spielerliste ---
-function updatePlayerList(players) {
- detailPlayerList.innerHTML = '';
- if (!players || players.length === 0) {
- detailPlayerList.innerHTML = 'Keine Spieler online.';
- return;
- }
- for (const p of players) {
- const li = document.createElement('li');
- const name = typeof p === 'object' ? p.name || p.username || p.player || '' : String(p);
- if (p.avatar) {
- const img = document.createElement('img');
- img.src = p.avatar;
- img.className = 'player-avatar';
- img.title = name;
- li.appendChild(img);
- }
- detailPlayerList.appendChild(li);
- }
-}
-
-// --- Update List (Fix: Syntaxfehler behoben) ---
-function updateServerListStatuses() {
- const items = serversContainer.querySelectorAll('.server-item');
- items.forEach(item => {
- const s = servers.find(x => x.id === item.dataset.id);
- if (!s) return;
-
- const st = statuses[s.id];
- const prevSt = previousStatuses[s.id];
-
- const statusChanged = !prevSt ||
- (prevSt.ok !== st?.ok) ||
- (prevSt.data?.online !== st?.data?.online);
-
- if (!statusChanged) return;
-
- if (!st || !st.ok || !st.data) {
- item.statusBubble.textContent = 'Offline';
- item.statusBubble.style.backgroundColor = 'var(--offline)';
- } else if (st.data.online) {
- item.statusBubble.textContent = 'Online';
- item.statusBubble.style.backgroundColor = 'var(--online)';
- } else {
- item.statusBubble.textContent = 'Offline';
- // Klammerfehler korrigiert: ')' zu '}'
- item.statusBubble.style.backgroundColor = 'var(--offline)';
- }
-
- previousStatuses[s.id] = st ? JSON.parse(JSON.stringify(st)) : null;
- });
-}
-
-// --- Add / Edit / Delete ---
-async function handleAdd() {
- const name = inputName.value.trim();
- const url = inputUrl.value.trim();
- const wpSite = inputWpSite.value.trim();
- const wpServerId = inputWpServerId.value.trim();
- if (!url && !wpSite) {
- alert('Bitte URL oder WP Site angeben');
- return;
- }
- const s = {
- id: uid(),
- name: name || url || wpSite,
- url: url || null,
- wpSite: wpSite || null,
- wpServerId: wpServerId || null
- };
- servers.push(s);
- await saveServersToStorage();
- inputName.value=''; inputUrl.value=''; inputWpSite.value=''; inputWpServerId.value='';
- renderServerList();
-}
-
-async function handleEdit() {
- if(!selectedId) return;
- const srv=servers.find(s=>s.id===selectedId);
- if(!srv) return;
- const newName=prompt('Name:',srv.name)||srv.name;
- const newUrl=prompt('URL:',srv.url||'')||srv.url;
- const newWpSite=prompt('WP Site:',srv.wpSite||'')||srv.wpSite;
- const newWpServerId=prompt('WP Server ID:',srv.wpServerId||'')||srv.wpServerId;
- srv.name=newName.trim(); srv.url=newUrl.trim();
- srv.wpSite=newWpSite.trim(); srv.wpServerId=newWpServerId.trim();
- await saveServersToStorage();
- renderServerList();
- renderDetail(selectedId);
-}
-
-async function handleDelete() {
- if(!selectedId) return;
- if(!confirm('Server wirklich löschen?')) return;
- servers = servers.filter(s=>s.id!==selectedId);
- selectedId=null;
- await saveServersToStorage();
- renderServerList();
- renderDetail(null);
-}
-
-async function manualRefresh() {
- try { chrome.runtime.sendMessage({ cmd: 'refreshNow' }); } catch(e) {}
-}
-
-// --- Listener ---
-chrome.storage.onChanged.addListener((changes, area) => {
- if (area === 'local' && changes.serverStatuses) {
- statuses = changes.serverStatuses.newValue || {};
- updateServerListStatuses();
- if (selectedId) {
- const srv = servers.find(s => s.id === selectedId);
- if (srv) updateDetailForServer(srv);
- }
- }
+const $ = id => document.getElementById(id);
+const uid = () => 'srv_' + Math.random().toString(36).slice(2,9);
+
+const inputName = $('inputName');
+const inputUrl = $('inputUrl');
+const inputWpSite = $('inputWpSite');
+const inputWpServerId = $('inputWpServerId');
+const btnAdd = $('btnAddServer');
+const serversContainer = $('serversContainer');
+const serverListPanel = document.querySelector('.server-list');
+const btnRefresh = $('btnRefresh');
+const btnToggleSettings = $('btnToggleSettings');
+const settingsForm = $('settingsForm');
+
+const noSelection = $('noSelection');
+const detailContent = $('detailContent');
+const detailName = $('detailName');
+const detailUrlText = $('detailUrlText');
+const detailStatus = $('detailStatus');
+const detailPulse = $('detailPulse');
+const detailVersion = $('detailVersion');
+const detailPlayers = $('detailPlayers');
+const detailPing = $('detailPing');
+const detailPlayerList = $('detailPlayerList');
+const btnEdit = $('btnEdit');
+const btnDelete = $('btnDelete');
+
+let servers = [];
+let selectedId = null;
+let statuses = {};
+let previousStatuses = {};
+let settingsVisible = false;
+
+document.addEventListener('DOMContentLoaded', init);
+btnAdd.addEventListener('click', handleAdd);
+btnRefresh.addEventListener('click', manualRefresh);
+btnToggleSettings.addEventListener('click', toggleSettings);
+btnEdit.addEventListener('click', handleEdit);
+btnDelete.addEventListener('click', handleDelete);
+
+async function init() {
+ await loadServersFromStorage();
+ await loadStatusesFromStorage();
+ await loadSettingsVisibility();
+ renderServerList();
+
+ if (servers.length === 1) selectedId = servers[0].id;
+ renderDetail(selectedId);
+
+ adjustDetailLayout();
+}
+
+// --- Settings Visibility ---
+async function loadSettingsVisibility() {
+ const obj = await chrome.storage.local.get(['settingsVisible']);
+ settingsVisible = obj.settingsVisible !== undefined ? obj.settingsVisible : false;
+ if (!settingsVisible) settingsForm.classList.add('hidden');
+ else settingsForm.classList.remove('hidden');
+}
+
+async function saveSettingsVisibility() {
+ await chrome.storage.local.set({ settingsVisible });
+}
+
+async function toggleSettings() {
+ settingsVisible = !settingsVisible;
+ settingsForm.classList.toggle('hidden');
+ await saveSettingsVisibility();
+ adjustDetailLayout();
+}
+
+// --- Storage ---
+async function loadServersFromStorage() {
+ const obj = await chrome.storage.local.get(['servers']);
+ servers = obj.servers || [];
+ for (const s of servers) if (!s.id) s.id = uid();
+ await chrome.storage.local.set({ servers });
+}
+
+async function saveServersToStorage() {
+ await chrome.storage.local.set({ servers });
+}
+
+async function loadStatusesFromStorage() {
+ const obj = await chrome.storage.local.get(['serverStatuses']);
+ statuses = obj.serverStatuses || {};
+}
+
+// --- Layout ---
+function adjustDetailLayout() {
+ const settingsHidden = settingsForm.classList.contains('hidden');
+ detailContent.classList.toggle('full-width', settingsHidden);
+ serverListPanel.classList.toggle('hidden', settingsHidden);
+ btnEdit.style.display = settingsHidden ? 'none' : 'inline-block';
+ btnDelete.style.display = settingsHidden ? 'none' : 'inline-block';
+}
+
+// --- Render Server List ---
+function renderServerList() {
+ serversContainer.innerHTML = '';
+ if (servers.length === 0) {
+ serversContainer.innerHTML = 'Noch keine Server hinzugefügt.
';
+ return;
+ }
+
+ for (const s of servers) {
+ const item = document.createElement('li');
+ item.className = 'server-item';
+ item.dataset.id = s.id;
+
+ const meta = document.createElement('div');
+ meta.className = 'meta';
+ const name = document.createElement('div');
+ name.className = 'name';
+ name.textContent = s.name || '(Kein Name)';
+
+ let listUrl = s.url || (s.wpSite ? s.wpSite + ' (WP)' : '');
+ listUrl = listUrl.replace(':9191', '');
+
+ const url = document.createElement('div');
+ url.className = 'url';
+ url.textContent = listUrl;
+ meta.append(name, url);
+
+ const statusBubble = document.createElement('div');
+ statusBubble.className = 'status-bubble';
+ statusBubble.textContent = '—';
+ statusBubble.style.backgroundColor = 'transparent';
+ item.statusBubble = statusBubble;
+
+ item.append(meta, statusBubble);
+ item.addEventListener('click', () => {
+ selectedId = s.id;
+ renderDetail(selectedId);
+ });
+
+ serversContainer.appendChild(item);
+ }
+ updateServerListStatuses(false);
+}
+
+// --- Render Detail ---
+function renderDetail(id) {
+ if (!id) {
+ noSelection.classList.remove('hidden');
+ detailContent.classList.add('hidden');
+ return;
+ }
+ const srv = servers.find(x => x.id === id);
+ if (!srv) {
+ noSelection.classList.remove('hidden');
+ detailContent.classList.add('hidden');
+ return;
+ }
+ noSelection.classList.add('hidden');
+ detailContent.classList.remove('hidden');
+
+ detailName.textContent = srv.name || 'Unbenannter Server';
+
+ let urlToShow = srv.url || (srv.wpSite ? srv.wpSite : 'Lokal');
+ urlToShow = urlToShow.replace(':9191', '');
+
+ detailUrlText.textContent = urlToShow;
+
+ updateDetailForServer(srv, true);
+}
+
+// --- Update Detail ---
+function updateDetailForServer(srv, force = false) {
+ const st = statuses[srv.id];
+ const prevSt = previousStatuses[srv.id];
+
+ const statusChanged = force ||
+ !prevSt ||
+ (prevSt.ok !== st?.ok) ||
+ (prevSt.data?.online !== st?.data?.online);
+
+ if (!st || !st.ok || !st.data) {
+ if (statusChanged) {
+ detailStatus.textContent = 'Offline';
+ detailPulse.classList.remove('online');
+ detailVersion.textContent = '-';
+ detailPlayers.textContent = '-';
+ detailPing.textContent = '-';
+ updatePlayerList([]);
+ }
+ } else {
+ const d = st.data;
+
+ if (statusChanged) {
+ detailStatus.textContent = d.online ? 'Online' : 'Offline';
+ if (d.online) {
+ detailPulse.classList.add('online');
+ } else {
+ detailPulse.classList.remove('online');
+ }
+ }
+
+ const newVersion = d.version || 'unknown';
+ if (force || detailVersion.textContent !== newVersion) {
+ detailVersion.textContent = newVersion;
+ }
+
+ const playersCount = Array.isArray(d.players) ? d.players.length : (typeof d.players === 'number' ? d.players : 0);
+ const maxPlayers = d.max_players;
+ let newPlayersText = String(playersCount);
+ if (maxPlayers && maxPlayers !== '-1') {
+ newPlayersText += ` / ${maxPlayers}`;
+ }
+
+ if (force || detailPlayers.textContent !== newPlayersText) {
+ detailPlayers.textContent = newPlayersText;
+ }
+
+ let pingVal = d.ping || d.latency || '-';
+ if (pingVal !== '-' && typeof pingVal === 'number') {
+ pingVal = pingVal + ' ms';
+ }
+
+ if (force || (pingVal !== '-' && detailPing.textContent !== pingVal)) {
+ detailPing.textContent = pingVal;
+ }
+
+ const currentPlayers = Array.isArray(d.players) ? d.players : [];
+ const prevPlayers = (prevSt && Array.isArray(prevSt.data?.players)) ? prevSt.data.players : [];
+
+ let playersChanged = false;
+ if (force) {
+ playersChanged = true;
+ } else {
+ playersChanged = JSON.stringify(currentPlayers) !== JSON.stringify(prevPlayers);
+ }
+
+ if (playersChanged) {
+ updatePlayerList(currentPlayers);
+ }
+ }
+
+ previousStatuses[srv.id] = st ? JSON.parse(JSON.stringify(st)) : null;
+}
+
+// --- Spielerliste ---
+function updatePlayerList(players) {
+ detailPlayerList.innerHTML = '';
+ if (!players || players.length === 0) {
+ detailPlayerList.innerHTML = 'Keine Spieler online.';
+ return;
+ }
+ for (const p of players) {
+ const li = document.createElement('li');
+ const name = typeof p === 'object' ? p.name || p.username || p.player || '' : String(p);
+
+ if (typeof p === 'object' && p.avatar) {
+ const img = document.createElement('img');
+ img.src = p.avatar;
+ img.className = 'player-avatar';
+ img.title = name;
+ li.appendChild(img);
+ } else {
+ // Falls kein Avatar vorhanden, generiere einen von mc-heads.net
+ const img = document.createElement('img');
+ img.src = `https://mc-heads.net/avatar/${encodeURIComponent(name)}/32`;
+ img.className = 'player-avatar';
+ img.title = name;
+ li.appendChild(img);
+ }
+
+ detailPlayerList.appendChild(li);
+ }
+}
+
+// --- Update Server List Statuses ---
+function updateServerListStatuses() {
+ const items = serversContainer.querySelectorAll('.server-item');
+ items.forEach(item => {
+ const s = servers.find(x => x.id === item.dataset.id);
+ if (!s) return;
+
+ const st = statuses[s.id];
+ const prevSt = previousStatuses[s.id];
+
+ const statusChanged = !prevSt ||
+ (prevSt.ok !== st?.ok) ||
+ (prevSt.data?.online !== st?.data?.online);
+
+ if (!statusChanged) return;
+
+ if (!st || !st.ok || !st.data) {
+ item.statusBubble.textContent = 'Offline';
+ item.statusBubble.style.backgroundColor = 'var(--offline)';
+ } else if (st.data.online) {
+ item.statusBubble.textContent = 'Online';
+ item.statusBubble.style.backgroundColor = 'var(--online)';
+ } else {
+ item.statusBubble.textContent = 'Offline';
+ item.statusBubble.style.backgroundColor = 'var(--offline)';
+ }
+
+ previousStatuses[s.id] = st ? JSON.parse(JSON.stringify(st)) : null;
+ });
+}
+
+// --- Add / Edit / Delete ---
+async function handleAdd() {
+ const name = inputName.value.trim();
+ const url = inputUrl.value.trim();
+ const wpSite = inputWpSite.value.trim();
+ const wpServerId = inputWpServerId.value.trim();
+
+ if (!url && !wpSite) {
+ alert('Bitte URL oder WP Site angeben');
+ return;
+ }
+
+ const s = {
+ id: uid(),
+ name: name || url || wpSite,
+ url: url || null,
+ wpSite: wpSite || null,
+ wpServerId: wpServerId || null
+ };
+
+ servers.push(s);
+ await saveServersToStorage();
+
+ inputName.value = '';
+ inputUrl.value = '';
+ inputWpSite.value = '';
+ inputWpServerId.value = '';
+
+ renderServerList();
+}
+
+async function handleEdit() {
+ if (!selectedId) return;
+ const srv = servers.find(s => s.id === selectedId);
+ if (!srv) return;
+
+ const newName = prompt('Name:', srv.name) || srv.name;
+ const newUrl = prompt('URL:', srv.url || '') || srv.url;
+ const newWpSite = prompt('WP Site:', srv.wpSite || '') || srv.wpSite;
+ const newWpServerId = prompt('WP Server ID:', srv.wpServerId || '') || srv.wpServerId;
+
+ srv.name = newName.trim();
+ srv.url = newUrl.trim();
+ srv.wpSite = newWpSite.trim();
+ srv.wpServerId = newWpServerId.trim();
+
+ await saveServersToStorage();
+ renderServerList();
+ renderDetail(selectedId);
+}
+
+async function handleDelete() {
+ if (!selectedId) return;
+ if (!confirm('Server wirklich löschen?')) return;
+
+ servers = servers.filter(s => s.id !== selectedId);
+ selectedId = null;
+
+ await saveServersToStorage();
+ renderServerList();
+ renderDetail(null);
+}
+
+async function manualRefresh() {
+ try {
+ chrome.runtime.sendMessage({ cmd: 'refreshNow' });
+ } catch(e) {
+ console.error('Refresh fehlgeschlagen:', e);
+ }
+}
+
+// --- Storage Listener ---
+chrome.storage.onChanged.addListener((changes, area) => {
+ if (area === 'local' && changes.serverStatuses) {
+ statuses = changes.serverStatuses.newValue || {};
+ updateServerListStatuses();
+ if (selectedId) {
+ const srv = servers.find(s => s.id === selectedId);
+ if (srv) updateDetailForServer(srv);
+ }
+ }
});
\ No newline at end of file