Jasbee Gebäude-Prozentanzeige.js hinzugefügt
This commit is contained in:
@@ -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 = `
|
||||||
|
<div id="popup-header" style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; border-bottom: 1px solid #555; padding-bottom: 6px; cursor: move; gap: 15px;">
|
||||||
|
<h4 style="margin: 0; color: #ffca28; font-size: 14px; pointer-events: none; white-space: nowrap;">📌 Gebäude Zustand</h4>
|
||||||
|
<div style="display: flex; gap: 6px; align-items: center;">
|
||||||
|
<button id="scan-jasbee-buildings" style="background: #ff9800; color: white; border: none; padding: 3px 8px; border-radius: 4px; cursor: pointer; font-size: 10px; font-weight: bold; white-space: nowrap; display: none;">Alle scannen</button>
|
||||||
|
<button id="clear-jasbee-data" style="background: #f44336; color: white; border: none; padding: 3px 8px; border-radius: 4px; cursor: pointer; font-size: 10px; font-weight: bold; white-space: nowrap;">Reset</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="popup-content">Lade Daten...</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
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 = '<span style="color: #aaa;">Noch keine Zustände erfasst. Klicke auf "Alle scannen" oder besuche deine Gebäude.</span>';
|
||||||
|
} else {
|
||||||
|
buildingList.sort((a, b) => a.numeric - b.numeric);
|
||||||
|
|
||||||
|
let html = '<table style="width:100%; border-collapse: collapse;">';
|
||||||
|
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
|
||||||
|
? `<a href="${item.url}" style="color: #ddd; text-decoration: none; border-bottom: 1px dashed #666; transition: color 0.2s;" onmouseover="this.style.color='#ffca28'" onmouseout="this.style.color='#ddd'">${item.name}</a>`
|
||||||
|
: item.name;
|
||||||
|
|
||||||
|
html += `<tr style="border-bottom: 1px solid #333; ${isCurrent}">
|
||||||
|
<td style="padding: 6px 4px; padding-right: 15px;">${nameDisplay}</td>
|
||||||
|
<td style="padding: 6px 4px; text-align: right; font-weight: bold; color: ${color}; white-space: nowrap;">${item.value}</td>
|
||||||
|
</tr>`;
|
||||||
|
});
|
||||||
|
html += '</table>';
|
||||||
|
contentDiv.innerHTML = html;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateBuildingStatus();
|
||||||
|
})();
|
||||||
Reference in New Issue
Block a user