diff --git a/Jasbee Gebäude-Prozentanzeige.js b/Jasbee Gebäude-Prozentanzeige.js
new file mode 100644
index 0000000..2e09b9e
--- /dev/null
+++ b/Jasbee Gebäude-Prozentanzeige.js
@@ -0,0 +1,306 @@
+// ==UserScript==
+// @name Jasbee Gebäude-Prozentanzeige
+// @namespace http://tampermonkey.net/
+// @version 3.2
+// @description Erlaubt das Scannen aller Gebäude im Hintergrund per Klick auf city.php (Mit optischen CSS-Fixes)
+// @author Daniel + Gemini
+// @match https://www.jasbee.de/module/*
+// @grant none
+// ==/UserScript==
+
+(function() {
+ 'use strict';
+
+ // Liste der erlaubten Dateinamen
+ const allowedPages = [
+ 'city.php', 'lager.php', 'baumarkt.php', 'sportsbar.php',
+ 'aliengeb.php', 'sauna.php', 'haus.php', 'fussball.php',
+ 'schwimmhalle.php', 'fabrik.php', 'fitness.php', 'bazar.php'
+ ];
+
+ const currentPath = window.location.pathname;
+ const currentPage = currentPath.substring(currentPath.lastIndexOf('/') + 1).toLowerCase();
+
+ if (!allowedPages.includes(currentPage)) {
+ return;
+ }
+
+ // 1. Popup-Element erstellen und stylen
+ const popup = document.createElement('div');
+ popup.id = 'gebaeude-prozent-popup';
+ popup.style.position = 'fixed';
+ popup.style.top = '10px';
+ popup.style.right = '10px';
+ popup.style.backgroundColor = 'rgba(20, 20, 20, 0.95)';
+ popup.style.color = '#fff';
+ popup.style.padding = '15px';
+ popup.style.borderRadius = '8px';
+ popup.style.boxShadow = '0 4px 15px rgba(0,0,0,0.6)';
+ popup.style.zIndex = '2147483647';
+ popup.style.fontFamily = 'Segoe UI, Arial, sans-serif';
+ popup.style.fontSize = '13px';
+ popup.style.maxHeight = '400px';
+ popup.style.overflowY = 'auto';
+ popup.style.minWidth = '290px';
+ popup.style.border = '1px solid #444';
+ popup.style.userSelect = 'none';
+
+ popup.innerHTML = `
+
+
+ `;
+
+ document.body.appendChild(popup);
+
+ // Scan-Button nur auf city.php einblenden
+ const scanBtn = document.getElementById('scan-jasbee-buildings');
+ if (currentPage === 'city.php') {
+ scanBtn.style.display = 'inline-block';
+ }
+
+ // Drag-and-Drop Steuerung
+ const header = document.getElementById('popup-header');
+ let isDragging = false;
+ let currentX, currentY, initialX, initialY;
+ let xOffset = 0, yOffset = 0;
+
+ const savedPos = localStorage.getItem('jasbee_popup_pos');
+ if (savedPos) {
+ const pos = JSON.parse(savedPos);
+ popup.style.transform = `translate3d(${pos.x}px, ${pos.y}px, 0)`;
+ xOffset = pos.x;
+ yOffset = pos.y;
+ }
+
+ header.addEventListener('mousedown', (e) => {
+ if (e.target === header) {
+ initialX = e.clientX - xOffset;
+ initialY = e.clientY - yOffset;
+ isDragging = true;
+ }
+ });
+
+ document.addEventListener('mousemove', (e) => {
+ if (isDragging) {
+ e.preventDefault();
+ currentX = e.clientX - initialX;
+ currentY = e.clientY - initialY;
+ xOffset = currentX;
+ yOffset = currentY;
+ popup.style.transform = `translate3d(${currentX}px, ${currentY}px, 0)`;
+ }
+ });
+
+ document.addEventListener('mouseup', () => {
+ if (isDragging) {
+ isDragging = false;
+ localStorage.setItem('jasbee_popup_pos', JSON.stringify({x: currentX, y: currentY}));
+ }
+ });
+
+ document.getElementById('clear-jasbee-data').addEventListener('click', () => {
+ if (confirm('Möchtest du alle gespeicherten Zustandswerte löschen?')) {
+ localStorage.removeItem('jasbee_building_data');
+ updateBuildingStatus();
+ }
+ });
+
+ scanBtn.addEventListener('click', startBackgroundScan);
+
+ function getStoredData() {
+ const data = localStorage.getItem('jasbee_building_data');
+ return data ? JSON.parse(data) : {};
+ }
+
+ function saveStoredData(data) {
+ localStorage.setItem('jasbee_building_data', JSON.stringify(data));
+ }
+
+ // Hintergrund-Scanner Funktion
+ function startBackgroundScan() {
+ const links = Array.from(document.querySelectorAll('a[href]'));
+ const targets = [];
+
+ links.forEach(link => {
+ const href = link.getAttribute('href');
+ allowedPages.forEach(page => {
+ if (page !== 'city.php' && href.includes(page) && !targets.includes(href)) {
+ targets.push(href);
+ }
+ });
+ });
+
+ if (targets.length === 0) {
+ alert('Keine Gebäude-Links auf der Seite gefunden!');
+ return;
+ }
+
+ scanBtn.disabled = true;
+ scanBtn.style.background = '#555';
+
+ let index = 0;
+ const iframe = document.createElement('iframe');
+ iframe.style.display = 'none';
+ document.body.appendChild(iframe);
+
+ function loadNext() {
+ if (index >= targets.length) {
+ document.body.removeChild(iframe);
+ scanBtn.disabled = false;
+ scanBtn.style.background = '#ff9800';
+ scanBtn.innerText = 'Alle scannen';
+ updateBuildingStatus();
+ return;
+ }
+
+ scanBtn.innerText = `Scan ${index + 1}/${targets.length}`;
+ iframe.src = targets[index];
+ index++;
+ }
+
+ iframe.addEventListener('load', () => {
+ try {
+ const doc = iframe.contentDocument || iframe.contentWindow.document;
+
+ let buildingName = '';
+ const breadcrumbItems = doc.querySelectorAll('.breadcrumb li');
+ if (breadcrumbItems.length > 0) {
+ buildingName = breadcrumbItems[breadcrumbItems.length - 1].textContent.trim().replace(/[\t\r\n]/g, '');
+ }
+
+ const percentElements = doc.querySelectorAll('.pie-number');
+ let stateValue = '';
+
+ for (let el of percentElements) {
+ const txt = el.textContent.trim();
+ if (txt.includes('%')) {
+ const parentCard = el.closest('.card');
+ if (parentCard) {
+ const cardHeader = parentCard.querySelector('h3');
+ if (cardHeader && cardHeader.textContent.trim() === 'Gebäudezustand') {
+ stateValue = txt;
+ break;
+ }
+ }
+ }
+ }
+
+ if (buildingName && stateValue) {
+ let currentStorage = getStoredData();
+ // Wir speichern Zustand und die genaue URL als Objekt ab
+ currentStorage[buildingName] = {
+ value: stateValue,
+ url: iframe.src
+ };
+ saveStoredData(currentStorage);
+ updateBuildingStatus();
+ }
+ } catch (e) {
+ console.error("Fehler beim Auslesen des Iframes:", e);
+ }
+
+ setTimeout(loadNext, 500);
+ });
+
+ loadNext();
+ }
+
+ // Hauptfunktion zur Anzeige
+ function updateBuildingStatus() {
+ const contentDiv = document.getElementById('popup-content');
+ let currentStorage = getStoredData();
+ let hasNewData = false;
+
+ let buildingName = '';
+ const breadcrumbItems = document.querySelectorAll('.breadcrumb li');
+ if (breadcrumbItems.length > 0) {
+ buildingName = breadcrumbItems[breadcrumbItems.length - 1].textContent.trim().replace(/[\t\r\n]/g, '');
+ }
+
+ const percentElements = document.querySelectorAll('.pie-number');
+
+ if (buildingName && buildingName.toLowerCase() !== 'city' && percentElements.length > 0) {
+ let stateValue = '';
+ for (let el of percentElements) {
+ const txt = el.textContent.trim();
+ if (txt.includes('%')) {
+ const parentCard = el.closest('.card');
+ if (parentCard) {
+ const cardHeader = parentCard.querySelector('h3');
+ if (cardHeader && cardHeader.textContent.trim() === 'Gebäudezustand') {
+ stateValue = txt;
+ break;
+ }
+ }
+ }
+ }
+
+ if (stateValue) {
+ // Abwärtskompatibilität prüfen (falls alte Datenstruktur ohne .value existiert)
+ const oldVal = (typeof currentStorage[buildingName] === 'object') ? currentStorage[buildingName].value : currentStorage[buildingName];
+
+ if (oldVal !== stateValue) {
+ currentStorage[buildingName] = {
+ value: stateValue,
+ url: window.location.href
+ };
+ hasNewData = true;
+ }
+ }
+ }
+
+ if (hasNewData) {
+ saveStoredData(currentStorage);
+ }
+
+ let buildingList = [];
+ for (let name in currentStorage) {
+ const entry = currentStorage[name];
+ // Abwärtskompatibler Check für die Datenstruktur
+ const val = (typeof entry === 'object') ? entry.value : entry;
+ const url = (typeof entry === 'object') ? entry.url : '';
+
+ buildingList.push({
+ name: name,
+ value: val,
+ url: url,
+ numeric: parseFloat(val) || 0
+ });
+ }
+
+ if (buildingList.length === 0) {
+ contentDiv.innerHTML = 'Noch keine Zustände erfasst. Klicke auf "Alle scannen" oder besuche deine Gebäude.';
+ } else {
+ buildingList.sort((a, b) => a.numeric - b.numeric);
+
+ let html = '';
+ buildingList.forEach(item => {
+ let color = '#4caf50';
+ if (item.numeric < 50) color = '#f44336';
+ else if (item.numeric < 90) color = '#ffeb3b';
+
+ const isCurrent = (item.name === buildingName) ? 'background-color: rgba(255,255,255,0.08); font-style: italic;' : '';
+
+ // Falls eine URL vorhanden ist, betten wir den Namen in einen Link ein
+ const nameDisplay = item.url
+ ? `${item.name}`
+ : item.name;
+
+ html += `
+ | ${nameDisplay} |
+ ${item.value} |
+
`;
+ });
+ html += '
';
+ contentDiv.innerHTML = html;
+ }
+ }
+
+ updateBuildingStatus();
+})();
\ No newline at end of file