// ==UserScript==
// @name WME Map Nav History
// @name:de WME Karten-Navigations-Historie
// @name:es WME Historial de Navegación del Mapa
// @description Navigate through map history using Alt + arrow keys and mouse control
// @description:de Ermöglicht die Navigation durch die Kartenhistorie mit Alt + Pfeiltasten und Maussteuerung
// @description:es Permite navegar por el historial del mapa usando Alt + teclas de flecha y control del ratón
// @namespace https://greasyfork.org/de/users/863740-horst-wittlich
// @version 2025.05.17
// @author hiwi234
// @include https://www.waze.com/editor*
// @include https://www.waze.com/*/editor*
// @include https://beta.waze.com/*
// @exclude https://www.waze.com/user/*editor/*
// @exclude https://www.waze.com/*/user/*editor/*
// @grant none
// @license MIT
// ==/UserScript==
/* global W */
(function() {
'use strict';
let navigationHistory = [];
let currentIndex = -1;
let isInitialized = false;
let currentLanguage = (navigator.language || navigator.userLanguage).substring(0, 2);
const translations = {
en: {
scriptActive: "Script active",
back: "Back",
forward: "Forward",
controls: "Controls",
previousPosition: "Previous position",
nextPosition: "Next position",
backButton: "Back button",
forwardButton: "Forward button",
hints: "Hints",
historyLimit: "History stores up to 100 positions",
autoSave: "New positions are automatically saved when moving the map"
},
de: {
scriptActive: "Script aktiv",
back: "Zurück",
forward: "Vorwärts",
controls: "Steuerung",
previousPosition: "Vorherige Position",
nextPosition: "Nächste Position",
backButton: "Zurück-Button",
forwardButton: "Vorwärts-Button",
hints: "Hinweise",
historyLimit: "Die Historie speichert bis zu 100 Positionen",
autoSave: "Neue Positionen werden beim Verschieben der Karte automatisch gespeichert"
},
es: {
scriptActive: "Script activo",
back: "Atrás",
forward: "Adelante",
controls: "Controles",
previousPosition: "Posición anterior",
nextPosition: "Siguiente posición",
backButton: "Botón atrás",
forwardButton: "Botón adelante",
hints: "Consejos",
historyLimit: "El historial almacena hasta 100 posiciones",
autoSave: "Las nuevas posiciones se guardan automáticamente al mover el mapa"
}
};
const t = (key) => {
return (translations[currentLanguage] && translations[currentLanguage][key]) || translations.en[key];
};
function saveCurrentPosition() {
if (!isInitialized || !W.map) return;
const center = W.map.getCenter();
const zoom = W.map.getZoom();
const lastEntry = navigationHistory[currentIndex];
if (lastEntry &&
lastEntry.lat === center.lat &&
lastEntry.lon === center.lon &&
lastEntry.zoom === zoom) {
return;
}
navigationHistory = navigationHistory.slice(0, currentIndex + 1);
navigationHistory.push({
lat: center.lat,
lon: center.lon,
zoom: zoom
});
currentIndex++;
if (navigationHistory.length > 100) {
navigationHistory.shift();
currentIndex--;
}
updateNavigationButtons();
}
function navigateToPosition(position) {
if (!position || !isInitialized || !W.map) return;
try {
const lonlat = new OpenLayers.LonLat(position.lon, position.lat);
W.map.setCenter(lonlat, position.zoom);
} catch (error) {
console.error('WME Map Nav History: Navigation error:', error);
}
}
function handleKeyDown(e) {
if (!isInitialized) return;
if (e.altKey && e.keyCode === 37) {
navigateBack();
e.preventDefault();
}
else if (e.altKey && e.keyCode === 39) {
navigateForward();
e.preventDefault();
}
}
function navigateBack() {
if (currentIndex > 0) {
currentIndex--;
navigateToPosition(navigationHistory[currentIndex]);
updateNavigationButtons();
}
}
function navigateForward() {
if (currentIndex < navigationHistory.length - 1) {
currentIndex++;
navigateToPosition(navigationHistory[currentIndex]);
updateNavigationButtons();
}
}
function updateNavigationButtons() {
const backBtn = document.getElementById('nav-history-back');
const forwardBtn = document.getElementById('nav-history-forward');
if (backBtn) {
backBtn.disabled = currentIndex <= 0;
backBtn.style.opacity = currentIndex <= 0 ? '0.5' : '1';
}
if (forwardBtn) {
forwardBtn.disabled = currentIndex >= navigationHistory.length - 1;
forwardBtn.style.opacity = currentIndex >= navigationHistory.length - 1 ? '0.5' : '1';
}
}
async function createSidebarTab() {
try {
const { tabLabel, tabPane } = W.userscripts.registerSidebarTab("wme-nav-history");
tabLabel.innerText = 'NAV';
tabLabel.title = '<h4>Map Navigation History</h4>';
await W.userscripts.waitForElementConnected(tabPane);
const styleSheet = document.createElement("style");
styleSheet.textContent = `
.nav-history-button {
padding: 8px 15px;
cursor: pointer;
background: #4a89dc;
color: white;
border: none;
border-radius: 4px;
font-weight: 600;
transition: all 0.3s ease;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
min-width: 100px;
display: flex;
align-items: center;
justify-content: center;
gap: 5px;
}
.nav-history-button:hover {
background: #5d9cec;
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
transform: translateY(-1px);
}
.nav-history-button:active {
transform: translateY(1px);
box-shadow: 0 1px 2px rgba(0,0,0,0.1);
}
.nav-history-button:disabled {
background: #b5b5b5;
cursor: not-allowed;
transform: none;
box-shadow: none;
}
.nav-history-container {
background: #f8f9fa;
border-radius: 8px;
padding: 20px;
margin: 10px 0;
box-shadow: 0 2px 6px rgba(0,0,0,0.05);
}
`;
document.head.appendChild(styleSheet);
tabPane.innerHTML = `
<div class="nav-history-container">
<p style="margin-top: 0; color: #2c3e50;"><h4>WME Map Nav History</h4></p>
<p style="color: #4CAF50; display: flex; align-items: center; gap: 5px;">
<span style="font-size: 18px;">✓</span> ${t('scriptActive')}
</p>
<div style="display: flex; gap: 15px; margin: 20px 0;">
<button id="nav-history-back" class="nav-history-button">
<span style="font-size: 16px;">⬅️</span> ${t('back')}
</button>
<button id="nav-history-forward" class="nav-history-button">
${t('forward')} <span style="font-size: 16px;">➡️</span>
</button>
</div>
<hr style="border: none; height: 1px; background: #e1e4e8; margin: 15px 0;">
<div style="background: #fff; padding: 15px; border-radius: 6px; border: 1px solid #e1e4e8;">
<b style="margin-top: 0; color: #2c3e50;">${t('controls')}:</b>
<ul style="padding-left: 20px; color: #4a5568;">
<li><strong>Alt + ←</strong> ${t('previousPosition')}</li>
<li><strong>Alt + →</strong> ${t('nextPosition')}</li>
</ul>
<b style="margin-top: 15px; color: #2c3e50;">${t('hints')}:</b>
<ul style="padding-left: 20px; color: #4a5568;">
<li>${t('historyLimit')}</li>
<li>${t('autoSave')}</li>
</ul>
</div>
</div>
`;
const backBtn = tabPane.querySelector('#nav-history-back');
const forwardBtn = tabPane.querySelector('#nav-history-forward');
backBtn.addEventListener('click', navigateBack);
forwardBtn.addEventListener('click', navigateForward);
updateNavigationButtons();
return true;
} catch (error) {
console.error('WME Map Nav History: Error creating sidebar tab:', error);
return false;
}
}
function initializeScript() {
if (isInitialized) return;
try {
W.map.events.register('moveend', null, saveCurrentPosition);
document.addEventListener('keydown', handleKeyDown);
createSidebarTab();
isInitialized = true;
saveCurrentPosition();
console.log('WME Map Nav History: Successfully initialized');
} catch (error) {
console.error('WME Map Nav History: Initialization error:', error);
isInitialized = false;
}
}
if (W?.userscripts?.state.isInitialized) {
initializeScript();
} else {
document.addEventListener("wme-initialized", initializeScript, {
once: true,
});
}
})();