@@ -1142,6 +1247,7 @@
// Geocache variables
let geocaches = []; // Array of { id, lat, lng, messages: [{author, text, timestamp}] }
let currentGeocache = null; // Currently selected/nearby geocache
+ let currentGeocacheEditMode = false; // Whether we're editing an existing geocache
let geocacheMarkers = {}; // Map of geocache id to marker
let lastGeocacheProximityCheck = 0;
let readGeocaches = JSON.parse(localStorage.getItem('readGeocaches') || '[]'); // Track which caches user has read
@@ -1384,6 +1490,11 @@
// Store user location for geocache proximity checks
userLocation = { lat, lng, accuracy };
+ // Update geocache visibility based on new location
+ if (navMode) {
+ updateGeocacheVisibility();
+ }
+
// Update or create marker
if (!gpsMarker) {
const myIcon = L.divIcon({
@@ -2196,6 +2307,22 @@
return 'gc_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
}
+ function shouldShowGeocache(geocache) {
+ // In edit mode, always show all geocaches
+ if (!navMode) return true;
+
+ // If no visibility restriction, always show
+ if (!geocache.visibilityDistance || geocache.visibilityDistance === 0) return true;
+
+ // In nav mode, only show if user is within visibility distance
+ if (!userLocation) return false;
+
+ const distance = L.latLng(userLocation.lat, userLocation.lng)
+ .distanceTo(L.latLng(geocache.lat, geocache.lng));
+
+ return distance <= geocache.visibilityDistance;
+ }
+
function placeGeocache(latlng) {
const id = generateGeocacheId();
const geocache = {
@@ -2204,6 +2331,8 @@
lng: latlng.lng,
title: '', // Will be set when user submits
icon: 'package-variant', // Default icon
+ color: '#FFA726', // Default orange color
+ visibilityDistance: 0, // 0 = always visible, >0 = only visible within that distance
messages: [],
createdAt: Date.now()
};
@@ -2214,14 +2343,24 @@
}
function createGeocacheMarker(geocache) {
+ // Check visibility based on mode and distance
+ if (!shouldShowGeocache(geocache)) {
+ console.log(`Geocache ${geocache.id} not visible due to distance restriction`);
+ return;
+ }
+
console.log(`Creating geocache marker for ${geocache.id} at ${geocache.lat}, ${geocache.lng}`);
- // Use geocache's custom icon or default
+ // Use geocache's custom icon and color
const iconClass = `mdi-${geocache.icon || 'package-variant'}`;
+ const color = geocache.color || '#FFA726';
+
+ // In edit mode, make secret caches slightly transparent
+ const opacity = (!navMode && geocache.visibilityDistance > 0) ? 0.7 : 1.0;
const marker = L.marker([geocache.lat, geocache.lng], {
icon: L.divIcon({
className: 'geocache-marker',
- html: `
`,
+ html: `
`,
iconSize: [28, 28],
iconAnchor: [14, 28]
}),
@@ -2287,9 +2426,14 @@
const form = document.getElementById('geocacheForm');
const titleGroup = document.getElementById('geocacheTitleGroup');
const iconGroup = document.getElementById('geocacheIconGroup');
+ const colorGroup = document.getElementById('geocacheColorGroup');
+ const visibilityGroup = document.getElementById('geocacheVisibilityGroup');
const titleInput = document.getElementById('geocacheTitleInput');
const iconInput = document.getElementById('geocacheIconInput');
+ const colorInput = document.getElementById('geocacheColorInput');
+ const visibilityInput = document.getElementById('geocacheVisibilityInput');
const dialogTitle = document.getElementById('geocacheTitle');
+ const editBtn = document.getElementById('geocacheEdit');
// Clear previous messages
messagesDiv.innerHTML = '';
@@ -2297,17 +2441,31 @@
// Update dialog title
dialogTitle.textContent = geocache.title ? `📍 ${geocache.title}` : '📍 Geocache';
- // Show/hide title and icon inputs for new geocaches
- if (isNew && !geocache.title) {
+ // Show/hide creation fields for new geocaches or edit mode
+ const isEditing = currentGeocacheEditMode === true;
+ if ((isNew && !geocache.title) || isEditing) {
titleGroup.style.display = 'block';
iconGroup.style.display = 'block';
- titleInput.value = '';
+ colorGroup.style.display = 'block';
+ visibilityGroup.style.display = 'block';
+
+ titleInput.value = isEditing ? geocache.title : '';
iconInput.value = geocache.icon || 'package-variant';
+ colorInput.value = geocache.color || '#FFA726';
+ visibilityInput.value = geocache.visibilityDistance || 0;
+
+ // Update color preview
+ updateColorPreview();
} else {
titleGroup.style.display = 'none';
iconGroup.style.display = 'none';
+ colorGroup.style.display = 'none';
+ visibilityGroup.style.display = 'none';
}
+ // Show edit button only in edit mode and for existing caches
+ editBtn.style.display = (!navMode && geocache.title && !isEditing) ? 'block' : 'none';
+
// Check if user can view messages (within 5m in nav mode, or in edit mode)
const canViewMessages = !navMode || userDistance <= adminSettings.geocacheRange;
@@ -2381,6 +2539,85 @@
function hideGeocacheDialog() {
document.getElementById('geocacheDialog').style.display = 'none';
currentGeocache = null;
+ currentGeocacheEditMode = false;
+ }
+
+ function updateColorPreview() {
+ const iconInput = document.getElementById('geocacheIconInput');
+ const colorInput = document.getElementById('geocacheColorInput');
+ const preview = document.getElementById('geocacheColorPreview');
+
+ const icon = iconInput.value || 'package-variant';
+ const color = colorInput.value || '#FFA726';
+
+ preview.innerHTML = `
`;
+ }
+
+ function startEditingGeocache() {
+ if (!currentGeocache || !currentGeocache.title) return;
+ currentGeocacheEditMode = true;
+ showGeocacheDialog(currentGeocache, false);
+ }
+
+ function updateGeocacheList() {
+ const content = document.getElementById('geocacheListContent');
+ content.innerHTML = '';
+
+ if (geocaches.length === 0) {
+ content.innerHTML = '
No geocaches placed yet
';
+ return;
+ }
+
+ geocaches.forEach(cache => {
+ const div = document.createElement('div');
+ div.className = 'geocache-list-item';
+
+ const titleDiv = document.createElement('div');
+ titleDiv.className = 'geocache-list-item-title';
+ titleDiv.innerHTML = `
+
+
${cache.title || 'Untitled Cache'}
+ ${cache.visibilityDistance > 0 ? '
SECRET' : ''}
+ `;
+
+ const infoDiv = document.createElement('div');
+ infoDiv.className = 'geocache-list-item-info';
+ const messageCount = cache.messages ? cache.messages.length : 0;
+ const createdDate = new Date(cache.createdAt).toLocaleDateString();
+ infoDiv.innerHTML = `
+ ${messageCount} message${messageCount !== 1 ? 's' : ''} • Created ${createdDate}
+ ${cache.visibilityDistance > 0 ? `
Visible within ${cache.visibilityDistance}m` : ''}
+ `;
+
+ div.appendChild(titleDiv);
+ div.appendChild(infoDiv);
+
+ // Click to go to cache
+ div.addEventListener('click', () => {
+ map.setView([cache.lat, cache.lng], 16);
+ showGeocacheDialog(cache, false);
+ document.getElementById('geocacheListSidebar').classList.remove('open');
+ });
+
+ content.appendChild(div);
+ });
+ }
+
+ function updateGeocacheVisibility() {
+ // Update visibility of all geocache markers based on current user location
+ geocaches.forEach(cache => {
+ const shouldShow = shouldShowGeocache(cache);
+ const marker = geocacheMarkers[cache.id];
+
+ if (shouldShow && !marker) {
+ // Create marker if it should be visible but doesn't exist
+ createGeocacheMarker(cache);
+ } else if (!shouldShow && marker) {
+ // Remove marker if it shouldn't be visible
+ map.removeLayer(marker);
+ delete geocacheMarkers[cache.id];
+ }
+ });
}
function updateGeocacheMarkerIcon(geocacheId, isRead) {
@@ -2396,11 +2633,15 @@
const messageInput = document.getElementById('geocacheMessage');
const titleInput = document.getElementById('geocacheTitleInput');
const iconInput = document.getElementById('geocacheIconInput');
+ const colorInput = document.getElementById('geocacheColorInput');
+ const visibilityInput = document.getElementById('geocacheVisibilityInput');
- // For new geocaches without a title, set the title and icon first
- if (!currentGeocache.title) {
+ // For new geocaches or when editing, update all properties
+ if (!currentGeocache.title || currentGeocacheEditMode) {
const title = titleInput.value.trim();
const icon = iconInput.value.trim();
+ const color = colorInput.value || '#FFA726';
+ const visibilityDistance = parseInt(visibilityInput.value) || 0;
if (!title) {
alert('Please enter a title for this geocache');
@@ -2409,16 +2650,31 @@
currentGeocache.title = title;
currentGeocache.icon = icon || 'package-variant';
+ currentGeocache.color = color;
+ currentGeocache.visibilityDistance = visibilityDistance;
- // Update the marker with new icon
+ // Update or recreate the marker with new properties
if (geocacheMarkers[currentGeocache.id]) {
- const marker = geocacheMarkers[currentGeocache.id];
- marker.setIcon(L.divIcon({
- className: 'geocache-marker',
- html: `
`,
- iconSize: [28, 28],
- iconAnchor: [14, 28]
- }));
+ map.removeLayer(geocacheMarkers[currentGeocache.id]);
+ delete geocacheMarkers[currentGeocache.id];
+ }
+ createGeocacheMarker(currentGeocache);
+
+ // If we were editing, exit edit mode
+ if (currentGeocacheEditMode) {
+ currentGeocacheEditMode = false;
+ // Don't add a message when just editing properties
+ if (!messageInput.value.trim()) {
+ showGeocacheDialog(currentGeocache, false);
+ // Broadcast the update
+ if (ws && ws.readyState === WebSocket.OPEN) {
+ ws.send(JSON.stringify({
+ type: 'geocacheUpdate',
+ geocache: currentGeocache
+ }));
+ }
+ return;
+ }
}
}
@@ -2529,6 +2785,24 @@
document.getElementById('geocacheCancel').addEventListener('click', hideGeocacheDialog);
document.getElementById('geocacheSubmit').addEventListener('click', addGeocacheMessage);
document.getElementById('geocacheDelete').addEventListener('click', deleteGeocache);
+ document.getElementById('geocacheEdit').addEventListener('click', startEditingGeocache);
+
+ // Color picker events
+ document.getElementById('geocacheIconInput').addEventListener('input', updateColorPreview);
+ document.getElementById('geocacheColorInput').addEventListener('input', updateColorPreview);
+ document.getElementById('geocacheColorReset').addEventListener('click', () => {
+ document.getElementById('geocacheColorInput').value = '#FFA726';
+ updateColorPreview();
+ });
+
+ // Geocache list sidebar events
+ document.getElementById('geocacheListToggle').addEventListener('click', () => {
+ document.getElementById('geocacheListSidebar').classList.toggle('open');
+ updateGeocacheList();
+ });
+ document.getElementById('geocacheListClose').addEventListener('click', () => {
+ document.getElementById('geocacheListSidebar').classList.remove('open');
+ });
document.getElementById('geocacheAlert').addEventListener('click', function() {
// Find nearest geocache and open it
if (userLocation) {
@@ -3248,6 +3522,10 @@
editContent.classList.add('active');
navMode = false;
+ // Show geocache list toggle in edit mode
+ document.getElementById('geocacheListToggle').style.display = 'flex';
+ updateGeocacheVisibility();
+
// In edit mode, disable auto-center
if (autoCenterMode) {
autoCenterMode = false;
@@ -3272,6 +3550,11 @@
navContent.classList.add('active');
navMode = true;
+ // Hide geocache list toggle in nav mode
+ document.getElementById('geocacheListToggle').style.display = 'none';
+ document.getElementById('geocacheListSidebar').classList.remove('open');
+ updateGeocacheVisibility();
+
// Deactivate edit tools when entering nav mode
Object.values(toolButtons).forEach(btn => btn.classList.remove('active'));
document.getElementById('reshapeControls').style.display = 'none';