// ==UserScript==
// @name WME Quick Zoom Button
// @name:en WME Quick Zoom Button
// @name:es Botón de Zoom Rápido WME
// @version 2025.08.05
// @description Fügt einen Button für temporären Zoom hinzu für bessere Chat sichtbarkeit und Auto-Sichtbarkeit
// @description:en Adds a button for temporary zoom for better chat visibility and auto-visibility
// @description:es Agrega un botón para zoom temporal para una mejor visibilidad del chat y auto-visibilidad
// @author Hiwi234
// @match https://www.waze.com/editor*
// @match https://www.waze.com/*/editor*
// @match https://beta.waze.com/editor*
// @match https://beta.waze.com/*/editor*
// @grant none
// @license MIT
// @namespace https://gf.qytechs.cn/de/users/863740-horst-wittlich
// ==/UserScript==
(function() {
'use strict';
const STORAGE_KEY = {
AUTO: 'wme-quick-zoom-auto',
ZOOM: 'wme-quick-zoom-level',
VISIBILITY: 'wme-auto-visibility'
};
const translations = {
'de': {
buttonText: 'Quick Zoom',
buttonTooltip: 'Temporär auf Zoomstufe zoomen',
sliderLabel: 'Maximale Zoomstufe:',
autoLoadLabel: 'Automatisch beim Laden',
visibilityLabel: 'Immer sichtbar bleiben'
},
'en': {
buttonText: 'Quick Zoom',
buttonTooltip: 'Temporarily zoom to level',
sliderLabel: 'Maximum zoom level:',
autoLoadLabel: 'Automatic on load',
visibilityLabel: 'Always stay visible'
},
'es': {
buttonText: 'Zoom Rápido',
buttonTooltip: 'Zoom temporal al nivel',
sliderLabel: 'Nivel máximo de zoom:',
autoLoadLabel: 'Automático al cargar',
visibilityLabel: 'Permanecer siempre visible'
}
};
// State management
let isZooming = false;
let visibilityObserver = null;
let visibilityInterval = null;
let focusHandler = null;
function getLanguage() {
const lang = navigator.language.split('-')[0];
return translations[lang] ? lang : 'en';
}
function getAutoZoomSetting() {
try {
const stored = localStorage.getItem(STORAGE_KEY.AUTO);
// Standardmäßig AKTIV wenn noch nicht gesetzt
return stored === null ? true : stored === 'true';
} catch (e) {
console.warn('[WME Quick Zoom] localStorage access failed:', e);
return true; // Standard: aktiv
}
}
function setAutoZoomSetting(value) {
try {
localStorage.setItem(STORAGE_KEY.AUTO, String(value));
} catch (e) {
console.warn('[WME Quick Zoom] localStorage write failed:', e);
}
}
function getVisibilitySetting() {
try {
const stored = localStorage.getItem(STORAGE_KEY.VISIBILITY);
// Standardmäßig AKTIV wenn noch nicht gesetzt
return stored === null ? true : stored === 'true';
} catch (e) {
console.warn('[WME Quick Zoom] localStorage access failed:', e);
return true; // Standard: aktiv
}
}
function setVisibilitySetting(value) {
try {
localStorage.setItem(STORAGE_KEY.VISIBILITY, String(value));
} catch (e) {
console.warn('[WME Quick Zoom] localStorage write failed:', e);
}
}
function getZoomLevel() {
try {
const stored = localStorage.getItem(STORAGE_KEY.ZOOM);
return stored ? parseInt(stored) : 7;
} catch (e) {
console.warn('[WME Quick Zoom] localStorage access failed:', e);
return 7;
}
}
function setZoomLevel(value) {
try {
localStorage.setItem(STORAGE_KEY.ZOOM, String(value));
} catch (e) {
console.warn('[WME Quick Zoom] localStorage write failed:', e);
}
}
function ensureVisibility() {
if (!getVisibilitySetting()) return;
try {
console.log('[WME Quick Zoom] Prüfe Sichtbarkeit...');
// Strategie 1: Direkte Suche nach dem "unsichtbar" Text und w-icon-invisible
const invisibleIndicators = [
// Text-basierte Suche
'span.button-text:contains("unsichtbar")',
'span.button-text:contains("invisible")',
'span.button-text:contains("offline")',
// Icon-basierte Suche
'.w-icon-invisible',
'wz-icon[name="invisible"]',
'[class*="invisible"]',
// Kombinierte Suche
'wz-button:has(.w-icon-invisible)',
'button:has(.w-icon-invisible)'
];
// Custom contains selector (da :contains nicht in querySelectorAll funktioniert)
const findElementsWithText = (text) => {
const elements = [];
const walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_TEXT,
null,
false
);
let node;
while (node = walker.nextNode()) {
if (node.textContent.toLowerCase().includes(text.toLowerCase())) {
elements.push(node.parentElement);
}
}
return elements;
};
// Suche nach "unsichtbar" Text
const unsichtbarElements = findElementsWithText('unsichtbar');
for (const element of unsichtbarElements) {
const clickable = findClickableParent(element);
if (clickable) {
console.log('[WME Quick Zoom] Unsichtbar-Text gefunden, klicke Button...');
simulateClick(clickable);
return true;
}
}
// Suche nach w-icon-invisible Icon
const invisibleIcons = document.querySelectorAll('.w-icon-invisible, [class*="invisible"]');
for (const icon of invisibleIcons) {
console.log('[WME Quick Zoom] Invisible-Icon gefunden:', icon.className);
const clickable = findClickableParent(icon);
if (clickable) {
console.log('[WME Quick Zoom] Klicke Invisible-Icon Button...');
simulateClick(clickable);
return true;
}
}
// Strategie 2: Suche in der Online-Editoren-Liste speziell
const onlineEditorsList = document.querySelector('#online-editors, .online-editors-list, wz-list[data-qa="online-editors"]');
if (onlineEditorsList) {
console.log('[WME Quick Zoom] Durchsuche Online-Editoren-Liste...');
// Suche nach dem aktuellen Benutzer
const userItems = onlineEditorsList.querySelectorAll('wz-list-item, li, [class*="editor"]');
for (const item of userItems) {
// Prüfe ob es der aktuelle Benutzer ist (verschiedene Indikatoren)
const isCurrentUser = item.querySelector('.current-user') ||
item.classList.contains('current-user') ||
item.getAttribute('data-current') === 'true' ||
item.querySelector('[data-current="true"]') ||
// Suche nach "Du" Text (deutscher Waze)
(item.textContent && item.textContent.includes('Du')) ||
// Oder nach dem ersten Eintrag (oft der aktuelle Benutzer)
(Array.from(userItems).indexOf(item) === 0);
if (isCurrentUser) {
console.log('[WME Quick Zoom] Aktueller Benutzer gefunden');
// Suche nach Invisible-Indikatoren in diesem Item
const invisibleInItem = item.querySelector('.w-icon-invisible, [class*="invisible"]') ||
(item.textContent && item.textContent.toLowerCase().includes('unsichtbar'));
if (invisibleInItem) {
const clickable = item.querySelector('wz-button, button, [role="button"]') ||
findClickableParent(item);
if (clickable) {
console.log('[WME Quick Zoom] Visibility-Button im User-Item gefunden');
simulateClick(clickable);
return true;
}
}
}
}
}
// Strategie 3: Suche nach allen wz-button Elementen mit invisible Kontext
const allButtons = document.querySelectorAll('wz-button');
for (const button of allButtons) {
const hasInvisibleIcon = button.querySelector('.w-icon-invisible, [class*="invisible"]');
const hasInvisibleText = button.textContent && button.textContent.toLowerCase().includes('unsichtbar');
if (hasInvisibleIcon || hasInvisibleText) {
console.log('[WME Quick Zoom] Invisible-Button gefunden via wz-button Suche');
simulateClick(button);
return true;
}
}
// Strategie 4: Erweiterte DOM-Suche
const selectors = [
'wz-button[class*="invisible"]',
'button[class*="invisible"]',
'[data-qa*="visibility"]',
'[data-testid*="visibility"]',
'wz-tooltip-target:has(.w-icon-invisible)',
'.sc-wz-basic-tooltip:has(.w-icon-invisible)'
];
for (const selector of selectors) {
try {
const elements = document.querySelectorAll(selector.replace(':has(.w-icon-invisible)', ''));
for (const element of elements) {
if (selector.includes(':has(') || element.querySelector('.w-icon-invisible')) {
console.log('[WME Quick Zoom] Element mit Invisible-Kontext gefunden:', selector);
simulateClick(element);
return true;
}
}
} catch (error) {
// Selector nicht unterstützt, weiter
continue;
}
}
console.log('[WME Quick Zoom] Keine Sichtbarkeits-Einstellung gefunden');
return false;
} catch (error) {
console.warn('[WME Quick Zoom] Fehler beim Setzen der Sichtbarkeit:', error);
return false;
}
}
function findClickableParent(element) {
// Erweiterte Suche nach klickbaren Elementen
const strategies = [
// Direkt das Element
() => element.matches && element.matches('button, wz-button, [role="button"], [clickable="true"]') ? element : null,
// Parent-Kette durchsuchen
() => element.closest('button, wz-button, [role="button"], [clickable="true"]'),
// Spezifische Waze-Container
() => element.closest('wz-list-item, wz-tooltip-target')?.querySelector('wz-button, button'),
// Sibling-Suche
() => {
const parent = element.parentElement;
return parent?.querySelector('wz-button, button, [role="button"]');
},
// Container-basierte Suche
() => {
const container = element.closest('.sc-wz-basic-tooltip, wz-tooltip, .tooltip');
return container?.querySelector('wz-button, button');
},
// Erweiterte Parent-Suche
() => {
let current = element;
while (current && current !== document.body) {
if (current.tagName === 'WZ-BUTTON' || current.tagName === 'BUTTON') {
return current;
}
if (current.onclick || current.getAttribute('onclick')) {
return current;
}
current = current.parentElement;
}
return null;
}
];
for (const strategy of strategies) {
try {
const clickable = strategy();
if (clickable && (typeof clickable.click === 'function' || clickable.onclick)) {
console.log('[WME Quick Zoom] Klickbares Element gefunden:', clickable.tagName, clickable.className);
return clickable;
}
} catch (error) {
continue;
}
}
return null;
}
function simulateClick(element) {
try {
console.log('[WME Quick Zoom] Simuliere Klick auf:', element.tagName, element.className);
// Verschiedene Click-Strategien für maximale Kompatibilität
const clickStrategies = [
// Standard Click
() => element.click(),
// MouseEvent Simulation
() => {
const events = ['mousedown', 'mouseup', 'click'];
events.forEach(eventType => {
const event = new MouseEvent(eventType, {
bubbles: true,
cancelable: true,
view: window,
button: 0
});
element.dispatchEvent(event);
});
},
// Pointer Events (für moderne Browser)
() => {
const events = ['pointerdown', 'pointerup'];
events.forEach(eventType => {
const event = new PointerEvent(eventType, {
bubbles: true,
cancelable: true,
pointerId: 1,
button: 0
});
element.dispatchEvent(event);
});
element.click();
},
// Touch Events (für Touch-Geräte)
() => {
const touch = new Touch({
identifier: 1,
target: element,
clientX: element.getBoundingClientRect().left + 5,
clientY: element.getBoundingClientRect().top + 5
});
const events = ['touchstart', 'touchend'];
events.forEach(eventType => {
const event = new TouchEvent(eventType, {
bubbles: true,
cancelable: true,
touches: eventType === 'touchstart' ? [touch] : [],
targetTouches: eventType === 'touchstart' ? [touch] : [],
changedTouches: [touch]
});
element.dispatchEvent(event);
});
}
];
// Versuche verschiedene Click-Strategien
for (let i = 0; i < clickStrategies.length; i++) {
try {
clickStrategies[i]();
console.log(`[WME Quick Zoom] Click-Strategie ${i + 1} erfolgreich`);
// Kurz warten und Status prüfen
setTimeout(() => {
const stillInvisible = document.querySelector('.w-icon-invisible') ||
(document.body.textContent && document.body.textContent.includes('unsichtbar'));
if (!stillInvisible) {
console.log('[WME Quick Zoom] Sichtbarkeit erfolgreich geändert!');
}
}, 500);
break; // Erfolgreich, stoppe weitere Versuche
} catch (strategyError) {
console.log(`[WME Quick Zoom] Click-Strategie ${i + 1} fehlgeschlagen:`, strategyError.message);
continue;
}
}
} catch (error) {
console.error('[WME Quick Zoom] Fehler beim Simulieren des Klicks:', error);
}
}
function stopVisibilityMonitoring() {
if (visibilityObserver) {
visibilityObserver.disconnect();
visibilityObserver = null;
console.log('[WME Quick Zoom] MutationObserver gestoppt');
}
if (visibilityInterval) {
clearInterval(visibilityInterval);
visibilityInterval = null;
console.log('[WME Quick Zoom] Interval gestoppt');
}
// Cleanup aller Event Handler
if (window.wmeQuickZoomEventHandlers) {
Object.entries(window.wmeQuickZoomEventHandlers).forEach(([event, handler]) => {
try {
window.removeEventListener(event, handler);
document.removeEventListener(event, handler);
} catch (error) {
// Event removal failed, continue
}
});
delete window.wmeQuickZoomEventHandlers;
}
// Cleanup Timeout
if (window.wmeQuickZoomVisibilityTimeout) {
clearTimeout(window.wmeQuickZoomVisibilityTimeout);
delete window.wmeQuickZoomVisibilityTimeout;
}
if (focusHandler) {
window.removeEventListener('focus', focusHandler);
focusHandler = null;
}
}
function startVisibilityMonitoring() {
if (!getVisibilitySetting()) return;
// Stoppe vorherige Überwachung
stopVisibilityMonitoring();
console.log('[WME Quick Zoom] Starte erweiterte Sichtbarkeits-Überwachung...');
// Multi-Strategy MutationObserver
visibilityObserver = new MutationObserver((mutations) => {
try {
let shouldCheck = false;
for (const mutation of mutations) {
// Überwache verschiedene Arten von Änderungen
if (mutation.type === 'childList') {
// Neue Elemente hinzugefügt/entfernt
const relevantChanges = [...mutation.addedNodes, ...mutation.removedNodes]
.some(node => {
if (node.nodeType === Node.ELEMENT_NODE) {
return isRelevantForVisibility(node);
}
return false;
});
if (relevantChanges) shouldCheck = true;
}
if (mutation.type === 'attributes') {
// Attribut-Änderungen
const target = mutation.target;
if (isRelevantForVisibility(target) ||
target.closest?.('.online-editors-list, [class*="editor"], [class*="visibility"]')) {
shouldCheck = true;
}
}
if (mutation.type === 'characterData') {
// Text-Änderungen
const parent = mutation.target.parentElement;
if (parent && isRelevantForVisibility(parent)) {
shouldCheck = true;
}
}
}
if (shouldCheck) {
// Debounced Check - verhindert zu häufige Ausführungen
clearTimeout(window.wmeQuickZoomVisibilityTimeout);
window.wmeQuickZoomVisibilityTimeout = setTimeout(() => {
ensureVisibility();
}, 300);
}
} catch (error) {
console.warn('[WME Quick Zoom] Fehler in MutationObserver:', error);
}
});
// Erweiterte Beobachtung verschiedener Container
const observeTargets = [
// Haupt-Editoren Container
() => document.getElementById('online-editors'),
() => document.querySelector('.online-editors-list'),
() => document.querySelector('[class*="editor-list"]'),
() => document.querySelector('#sidebar'),
() => document.querySelector('.sidebar'),
// Fallback: Body
() => document.body
];
for (const getTarget of observeTargets) {
try {
const target = getTarget();
if (target) {
visibilityObserver.observe(target, {
childList: true,
subtree: true,
attributes: true,
characterData: true,
attributeFilter: [
'class', 'aria-label', 'title', 'data-testid',
'data-qa', 'name', 'tooltip', 'data-current',
'data-visible', 'data-status'
]
});
console.log('[WME Quick Zoom] Observer aktiv auf:', target.tagName, target.className);
break; // Nur ersten verfügbaren Container überwachen
}
} catch (error) {
console.warn('[WME Quick Zoom] Fehler beim Observer-Setup:', error);
continue;
}
}
// Adaptive Interval-Überprüfung - Viel aggressiver für Visibility
let intervalDuration = 3000; // Start mit 3 Sekunden (sehr aggressiv)
const maxInterval = 15000; // Maximum 15 Sekunden
const minInterval = 2000; // Minimum 2 Sekunden
const intervalFunction = () => {
try {
const wasVisible = checkCurrentVisibilityState();
ensureVisibility(); // Erzwinge Sichtbarkeit
// Sehr aggressive Interval-Anpassung
if (!wasVisible) {
// Wenn unsichtbar war, überprüfe noch häufiger
intervalDuration = minInterval;
console.log('[WME Quick Zoom] Immer noch unsichtbar - aggressive Überprüfung alle', intervalDuration, 'ms');
} else {
// Wenn sichtbar war, überprüfe etwas seltener, aber immer noch regelmäßig
intervalDuration = Math.min(maxInterval, intervalDuration + 2000);
}
// Restart interval mit neuer Duration
clearInterval(visibilityInterval);
visibilityInterval = setInterval(intervalFunction, intervalDuration);
} catch (error) {
console.warn('[WME Quick Zoom] Fehler im Visibility-Interval:', error);
}
};
visibilityInterval = setInterval(intervalFunction, intervalDuration);
// Event-basierte Trigger
const eventHandlers = {
// Fokus-Events
focus: () => setTimeout(ensureVisibility, 1000),
// Visibility API
visibilitychange: () => {
if (!document.hidden) {
setTimeout(ensureVisibility, 500);
}
},
// Custom Waze Events (falls verfügbar)
'wme-sidebar-change': () => setTimeout(ensureVisibility, 200),
'wme-tab-switch': () => setTimeout(ensureVisibility, 200),
// Resize Events (UI könnte sich ändern)
resize: () => setTimeout(ensureVisibility, 1000)
};
Object.entries(eventHandlers).forEach(([event, handler]) => {
try {
window.addEventListener(event, handler, { passive: true });
document.addEventListener(event, handler, { passive: true });
} catch (error) {
// Event nicht unterstützt, ignorieren
}
});
// Storage für Event Cleanup
window.wmeQuickZoomEventHandlers = eventHandlers;
// Erste Überprüfung mit verschiedenen Delays - sehr aggressiv
[500, 1000, 2000, 3000, 5000, 8000].forEach(delay => {
setTimeout(() => {
try {
console.log(`[WME Quick Zoom] Erzwinge Sichtbarkeit nach ${delay}ms...`);
ensureVisibility();
} catch (error) {
console.warn(`[WME Quick Zoom] Fehler bei verzögerter Überprüfung (${delay}ms):`, error);
}
}, delay);
});
}
function isRelevantForVisibility(element) {
if (!element || !element.tagName) return false;
const relevantSelectors = [
'online-editors', 'editor-visibility', 'visibility',
'editor-list', 'user-list', 'editor-item', 'wz-button',
'icon', 'eye', 'current-user', 'editor-status'
];
const elementInfo = `${element.className} ${element.id} ${element.tagName}`.toLowerCase();
return relevantSelectors.some(selector =>
elementInfo.includes(selector)) ||
element.querySelector?.('.editor-visibility, [class*="visibility"], wz-button') ||
element.matches?.('wz-button, [role="button"], [class*="visibility"]');
}
function checkCurrentVisibilityState() {
try {
// Versuche aktuellen Status zu ermitteln
const invisibleTexts = ['unsichtbar', 'invisible', 'offline', 'hidden'];
const allElements = document.querySelectorAll('[class*="visibility"], [class*="editor"], .online-editors-list *');
for (const element of allElements) {
const text = (element.textContent || '').toLowerCase();
const className = (element.className || '').toLowerCase();
const ariaLabel = (element.getAttribute('aria-label') || '').toLowerCase();
if (invisibleTexts.some(invisible =>
text.includes(invisible) || className.includes(invisible) || ariaLabel.includes(invisible))) {
return false; // Unsichtbar gefunden
}
}
return true; // Annahme: Sichtbar
} catch (error) {
return true; // Bei Fehler annehmen dass sichtbar
}
}
async function performQuickZoom() {
if (isZooming) {
console.log('[WME Quick Zoom] Zoom bereits aktiv, überspringe...');
return;
}
try {
if (!window.W?.map?.olMap) {
console.warn('[WME Quick Zoom] WME map nicht verfügbar');
return;
}
isZooming = true;
const originalZoom = W.map.olMap.getZoom();
const targetZoom = getZoomLevel();
console.log(`[WME Quick Zoom] Zooming from ${originalZoom} to ${targetZoom}`);
W.map.olMap.zoomTo(targetZoom);
// Promise für verzögerte Rückkehr zum ursprünglichen Zoom
return new Promise(resolve => {
setTimeout(() => {
try {
if (window.W?.map?.olMap) {
W.map.olMap.zoomTo(originalZoom);
console.log(`[WME Quick Zoom] Restored zoom to ${originalZoom}`);
}
} catch (error) {
console.error('[WME Quick Zoom] Error restoring zoom:', error);
} finally {
isZooming = false;
resolve();
}
}, 2000);
});
} catch (error) {
console.error('[WME Quick Zoom] Error in performQuickZoom:', error);
isZooming = false;
}
}
function createStyles() {
// Prüfe ob Styles bereits existieren
if (document.getElementById('wme-quick-zoom-styles')) {
return;
}
const style = document.createElement('style');
style.id = 'wme-quick-zoom-styles';
style.textContent = `
.quick-zoom-container {
display: flex;
flex-direction: column;
gap: 10px;
padding: 10px;
}
.quick-zoom-slider-container {
display: flex;
flex-direction: column;
gap: 5px;
}
.quick-zoom-checkbox-container {
display: flex;
align-items: center;
gap: 5px;
}
.quick-zoom-label {
font-size: 12px;
color: inherit;
}
.quick-zoom-slider {
width: 100%;
}
.quick-zoom-floating-button {
position: fixed;
bottom: 20px;
left: 20px;
z-index: 1000;
background-color: #ffffff;
border: 1px solid #cccccc;
padding: 8px 15px;
border-radius: 20px;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
cursor: pointer;
font-weight: bold;
font-family: inherit;
font-size: 12px;
transition: background-color 0.3s ease, box-shadow 0.3s ease;
}
.quick-zoom-floating-button:hover {
background-color: #f0f0f0;
box-shadow: 0 4px 8px rgba(0,0,0,0.3);
}
.quick-zoom-floating-button:active {
background-color: #e0e0e0;
transform: translateY(1px);
}
`;
document.head.appendChild(style);
}
async function initializeQuickZoom() {
try {
// Warte bis WME vollständig geladen ist
if (!window.W?.userscripts?.registerSidebarTab) {
console.warn('[WME Quick Zoom] WME userscripts nicht verfügbar, warte...');
setTimeout(initializeQuickZoom, 1000);
return;
}
console.log('[WME Quick Zoom] Initialisiere...');
const i18n = translations[getLanguage()];
// Erstelle CSS-Styles
createStyles();
// Registriere Sidebar-Tab
const { tabLabel, tabPane } = W.userscripts.registerSidebarTab("quick-zoom-script");
tabLabel.innerText = 'QZ';
tabLabel.title = i18n.buttonText;
// Erstelle Container
const container = document.createElement('div');
container.className = 'quick-zoom-container';
// Sidebar Button
const sidebarButton = document.createElement('button');
sidebarButton.className = 'waze-btn waze-btn-small';
sidebarButton.innerText = i18n.buttonText;
sidebarButton.title = `${i18n.buttonTooltip} ${getZoomLevel()}`;
sidebarButton.type = 'button';
// Floating Button
const floatingButton = document.createElement('button');
floatingButton.innerText = 'QZ';
floatingButton.title = `${i18n.buttonTooltip} ${getZoomLevel()}`;
floatingButton.className = 'quick-zoom-floating-button';
floatingButton.type = 'button';
// Slider Container
const sliderContainer = document.createElement('div');
sliderContainer.className = 'quick-zoom-slider-container';
const sliderLabel = document.createElement('label');
sliderLabel.textContent = i18n.sliderLabel;
sliderLabel.className = 'quick-zoom-label';
const sliderValue = document.createElement('span');
sliderValue.className = 'quick-zoom-label';
sliderValue.textContent = getZoomLevel();
const slider = document.createElement('input');
slider.type = 'range';
slider.min = '4';
slider.max = '12';
slider.value = getZoomLevel();
slider.className = 'quick-zoom-slider';
// Event Handlers mit passiven Events
const zoomHandler = (event) => {
event.preventDefault();
if (!isZooming) {
performQuickZoom().catch(error => {
console.error('[WME Quick Zoom] Zoom-Fehler:', error);
});
}
};
const sliderHandler = (event) => {
const value = event.target.value;
sliderValue.textContent = value;
setZoomLevel(value);
const tooltip = `${i18n.buttonTooltip} ${value}`;
sidebarButton.title = tooltip;
floatingButton.title = tooltip;
};
// Event Listeners hinzufügen
slider.addEventListener('input', sliderHandler, { passive: true });
sidebarButton.addEventListener('click', zoomHandler);
floatingButton.addEventListener('click', zoomHandler);
// Auto-Zoom Checkbox
const checkboxContainer = document.createElement('div');
checkboxContainer.className = 'quick-zoom-checkbox-container';
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.id = 'auto-quick-zoom-' + Date.now();
checkbox.checked = getAutoZoomSetting();
const label = document.createElement('label');
label.htmlFor = checkbox.id;
label.textContent = i18n.autoLoadLabel;
label.className = 'quick-zoom-label';
checkbox.addEventListener('change', (event) => {
setAutoZoomSetting(event.target.checked);
}, { passive: true });
// Visibility Checkbox
const visibilityCheckboxContainer = document.createElement('div');
visibilityCheckboxContainer.className = 'quick-zoom-checkbox-container';
const visibilityCheckbox = document.createElement('input');
visibilityCheckbox.type = 'checkbox';
visibilityCheckbox.id = 'auto-visibility-' + Date.now();
visibilityCheckbox.checked = getVisibilitySetting();
const visibilityLabel = document.createElement('label');
visibilityLabel.htmlFor = visibilityCheckbox.id;
visibilityLabel.textContent = i18n.visibilityLabel;
visibilityLabel.className = 'quick-zoom-label';
visibilityCheckbox.addEventListener('change', (event) => {
setVisibilitySetting(event.target.checked);
if (event.target.checked) {
setTimeout(startVisibilityMonitoring, 500);
} else {
stopVisibilityMonitoring();
}
}, { passive: true });
// DOM aufbauen
sliderContainer.appendChild(sliderLabel);
sliderContainer.appendChild(slider);
sliderContainer.appendChild(sliderValue);
checkboxContainer.appendChild(checkbox);
checkboxContainer.appendChild(label);
visibilityCheckboxContainer.appendChild(visibilityCheckbox);
visibilityCheckboxContainer.appendChild(visibilityLabel);
container.appendChild(sidebarButton);
container.appendChild(sliderContainer);
container.appendChild(checkboxContainer);
container.appendChild(visibilityCheckboxContainer);
tabPane.appendChild(container);
document.body.appendChild(floatingButton);
// Warte bis Tab verbunden ist
await W.userscripts.waitForElementConnected(tabPane);
// SOFORTIGE und aggressive Sichtbarkeits-Erzwingung
console.log('[WME Quick Zoom] Starte SOFORTIGE Sichtbarkeits-Erzwingung...');
// Mehrfache sofortige Versuche
for (let i = 0; i < 3; i++) {
setTimeout(() => {
ensureVisibility();
}, i * 500);
}
// Auto-Zoom ausführen wenn aktiviert
if (getAutoZoomSetting()) {
setTimeout(() => {
performQuickZoom().catch(error => {
console.error('[WME Quick Zoom] Auto-Zoom Fehler:', error);
});
}, 2000);
}
// Visibility Monitoring IMMER starten (erzwungen)
setTimeout(() => {
console.log('[WME Quick Zoom] Starte ERZWUNGENES Visibility-Monitoring...');
startVisibilityMonitoring();
}, 1000);
console.log('[WME Quick Zoom] Erfolgreich initialisiert');
} catch (error) {
console.error('[WME Quick Zoom] Initialisierungs-Fehler:', error);
}
}
// Cleanup beim Verlassen der Seite
window.addEventListener('beforeunload', () => {
stopVisibilityMonitoring();
}, { passive: true });
// Verbesserte Initialisierung
function initialize() {
try {
if (window.W?.userscripts?.state?.isReady) {
initializeQuickZoom();
} else if (window.W?.userscripts) {
document.addEventListener("wme-ready", initializeQuickZoom, {
once: true,
passive: true
});
} else {
// Warte auf WME
let attempts = 0;
const maxAttempts = 60; // 30 Sekunden maximum
const checkWME = () => {
attempts++;
if (window.W?.userscripts) {
if (window.W.userscripts.state?.isReady) {
initializeQuickZoom();
} else {
document.addEventListener("wme-ready", initializeQuickZoom, {
once: true,
passive: true
});
}
} else if (attempts < maxAttempts) {
setTimeout(checkWME, 500);
} else {
console.error('[WME Quick Zoom] WME konnte nicht geladen werden nach', maxAttempts * 500, 'ms');
}
};
checkWME();
}
} catch (error) {
console.error('[WME Quick Zoom] Initialisierungs-Setup-Fehler:', error);
}
}
// Start initialization
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initialize, {
once: true,
passive: true
});
} else {
initialize();
}
})();