document.addEventListener('DOMContentLoaded', () => { initMap(); initSidebar(); loadNotepads(true); const form = document.getElementById('form-add-collaborator'); if (form) { form.addEventListener('submit', async (e) => { e.preventDefault(); const padId = document.getElementById('share-pad-id').value; const email = document.getElementById('collaborator-email').value; const permission = document.getElementById('collaborator-permission').value; try { const res = await fetch(`/api/notepads/${padId}/collaborators`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, permission }) }); if (res.ok) { form.reset(); const padName = document.getElementById('share-pad-name').textContent; openShareSettingsModal(padId, padName); } else { const err = await res.json(); alert(`Failed to add collaborator: ${err.error}`); } } catch (err) { console.error(err); alert('An error occurred.'); } }); } const formEditPad = document.getElementById('form-edit-pad'); if (formEditPad) { formEditPad.addEventListener('submit', async (e) => { e.preventDefault(); const padId = document.getElementById('pad-id-edit').value; const name = document.getElementById('pad-name-edit').value; const isPublic = document.getElementById('pad-public-edit').checked; try { const res = await fetch(`/api/notepads/${padId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name, is_public: isPublic }) }); if (res.ok) { document.getElementById('modal-edit-pad').classList.add('hidden'); loadNotepads(); // Refresh everything } else { alert('Failed to update notepad.'); } } catch (err) { console.error(err); } }); } const formEditNote = document.getElementById('form-edit-note'); if (formEditNote) { formEditNote.addEventListener('submit', async (e) => { e.preventDefault(); const noteId = document.getElementById('note-id-edit').value; const title = document.getElementById('note-title-edit').value; const content = document.getElementById('note-content-edit').value; try { const res = await fetch(`/api/notes/${noteId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title, content }) }); if (res.ok) { document.getElementById('modal-edit-note').classList.add('hidden'); // Refresh current view if (activePadId) { loadNotesForPad(activePadId); } else { // This was likely from a search result, which is harder to refresh. // A full reload of notepads is a safe fallback. alert('Note updated. Refreshing list.'); loadNotepads(); } } else { alert('Failed to update note.'); } } catch (err) { console.error(err); } }); } }); let map; let activeNotes = []; let userLocation = null; let activePadName = ""; let activePadId = null; let activePadIsPublic = false; let activePadOwnerId = null; let activePadCanWrite = false; let currentUser = null; let isTracking = false; let userMarker = null; let notifiedNoteIds = new Set(); let isLoggedIn = false; function initMap() { // Default view (e.g., Oklahoma area if geolocation fails) map = L.map('map').setView([35.6528, -97.4781], 10); // Ask for location if (navigator.geolocation) { navigator.geolocation.watchPosition((position) => { const { latitude, longitude } = position.coords; userLocation = { lat: latitude, lng: longitude }; const centerBtn = document.getElementById('btn-center-user'); if (centerBtn) centerBtn.style.display = 'block'; if (isTracking) { map.setView([latitude, longitude]); } else if (!userMarker && !new URLSearchParams(window.location.search).has('pad') && !new URLSearchParams(window.location.search).has('note')) { // Only auto-center if we aren't loading a shared item // First fix map.setView([latitude, longitude], 13); console.log("Map centered on user location:", latitude, longitude); } // Add User Location Dot if (userMarker) { userMarker.setLatLng([latitude, longitude]); } else { userMarker = L.circleMarker([latitude, longitude], { radius: 8, fillColor: "#3388ff", color: "#fff", weight: 2, opacity: 1, fillOpacity: 0.8 }).addTo(map).bindPopup("You are here"); } // Location-Based Browser Alerts const userLatLng = L.latLng(latitude, longitude); if (activeNotes && activeNotes.length > 0) { activeNotes.forEach(note => { const noteLatLng = L.latLng(note.lat, note.lng); if (userLatLng.distanceTo(noteLatLng) <= 50) { if (!notifiedNoteIds.has(note.id)) { notifiedNoteIds.add(note.id); alert(`You are near a note!\n\n${note.title}\n${note.content}`); } } }); } }, (err) => { console.warn("Geolocation error:", err); }, { enableHighAccuracy: true, timeout: 10000, maximumAge: 0 }); } // Add OpenStreetMap tiles L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19, attribution: '© OpenStreetMap' }).addTo(map); // Listen for zoom changes to toggle note display map.on('zoomend', () => { if (activeNotes.length > 0) { renderMapMarkers(); } }); map.on('dragstart', stopTracking); map.on('popupopen', stopTracking); } function initSidebar() { const sidebar = document.getElementById('sidebar'); const toggleBtn = document.getElementById('sidebar-toggle'); toggleBtn.addEventListener('click', () => { sidebar.classList.toggle('collapsed'); // Change arrow direction based on state if (sidebar.classList.contains('collapsed')) { const sections = document.querySelectorAll('.list-section'); sections.forEach(section => { section.querySelector('.list-section-content').style.display = 'none'; }); toggleBtn.innerHTML = '<'; // Point left (open) } else { toggleBtn.innerHTML = '>'; // Point right (close) } }); const centerBtn = document.getElementById('btn-center-user'); if (centerBtn) { centerBtn.addEventListener('click', () => { isTracking = true; updateTrackingUI(); if (userLocation) { map.setView([userLocation.lat, userLocation.lng], 16); } }); } } async function loadNotepads(isInitialLoad = false) { // Reset state activeNotes = []; currentMarkers.forEach(marker => map.removeLayer(marker)); currentMarkers = []; // Check auth first try { const authRes = await fetch('/auth/me'); const authData = await authRes.json(); isLoggedIn = authData.authenticated; currentUser = authData.user || null; } catch (e) { console.error(e); } // Reset Sidebar Header const header = document.querySelector('.sidebar-header'); if (header) { let headerHTML = '

Notepads

'; if (isLoggedIn) { headerHTML += ''; } header.innerHTML = headerHTML; if (isLoggedIn) { document.getElementById('btn-create-pad').addEventListener('click', () => { document.getElementById('modal-create-pad').classList.remove('hidden'); }); } } const sidebarBody = document.getElementById('sidebar-body'); if (isLoggedIn) { sidebarBody.innerHTML = `

Loading...

Loading...

Loading...

`; const listSection = document.querySelectorAll('.list-section-header'); listSection.forEach(header => { header.addEventListener('click',toggleSection) }) setupPublicToggle(); try { await loadNotepadsOfType('favorites', 'favorite-notepads-list'); await loadNotepadsOfType('shared', 'shared-notepads-list'); const res = await fetch('/api/notepads?type=mine'); const notepads = await res.json(); renderNotepadList(notepads, 'my-notepads-list'); } catch (err) { console.error("Failed to load notepads", err); document.getElementById('my-notepads-list').innerHTML = '

Error loading data.

'; } } else { // Logged out: Only Public Notepads sidebarBody.innerHTML = `

Public Notepads

Loading...

`; try { const res = await fetch('/api/notepads?type=public'); const pads = await res.json(); renderNotepadList(pads, 'public-notepads-list'); } catch (err) { console.error(err); } } // Initial Load Logic (Check for URL params first, else default behavior based on auth) if (isInitialLoad === true) { const params = new URLSearchParams(window.location.search); if (params.has('pad')) { const token = params.get('token'); loadNotesForPad(params.get('pad'), undefined, undefined, undefined, true, token); } else if (params.has('note')) { const token = params.get('token'); loadSingleNote(params.get('note'), token); } else if (isLoggedIn) { loadAllMyNotes(); // Default action for logged in users } else { try { const res = await fetch('/api/notepads?type=public'); const pads = await res.json(); const globalPad = pads.find(p => p.name === "Global Public Notes"); if (globalPad) { loadNotesForPad(globalPad.id, globalPad.name, true, globalPad.owner_id); } } catch (err) {} } } } function setupPublicToggle() { const btn = document.getElementById('btn-toggle-public'); const list = document.getElementById('public-notepads-list'); btn.addEventListener('click', async () => { if (list.style.display === 'none') { list.style.display = 'block'; btn.innerHTML = 'Public Notepads ▾'; // Lazy load if empty if (list.innerHTML === '') { list.innerHTML = '

Loading...

'; try { const res = await fetch('/api/notepads?type=public'); const pads = await res.json(); renderNotepadList(pads, 'public-notepads-list'); } catch (err) { list.innerHTML = '

Error loading public pads.

'; } } } else { list.style.display = 'none'; btn.innerHTML = 'Public Notepads ▸'; } }); } function renderNotepadList(pads, containerId, isFavorite) { const container = document.getElementById(containerId); container.innerHTML = ''; if (pads.length === 0) { container.innerHTML = '

No notepads found.

'; return; } pads.forEach(pad => { const item = document.createElement('div'); item.className = 'notepad-item'; item.style.padding = '10px'; item.style.borderBottom = '1px solid #eee'; item.style.cursor = 'pointer'; let icon = pad.is_public ? '🌍' : '🔒'; let favButton = ''; const editBtn = (currentUser && pad.owner_id === currentUser.id) ? `` : ''; const isOwner = currentUser && pad.owner_id === currentUser.id; const manageShareBtn = isOwner ? `` : ''; if(isLoggedIn){ const action = isFavorite ? 'unfavorite' : 'favorite'; const label = isFavorite ? '♥' : '♡'; favButton = ``; } const deleteBtn = isOwner ? `` : ''; const shareToken = pad.share_token || ''; const shareBtn = ``; item.innerHTML = `
${icon} ${escapeHtml(pad.name)}
${editBtn} ${manageShareBtn} ${shareBtn} ${favButton} ${deleteBtn}
${pad.note_count || 0} notes
`; item.addEventListener('click', () => loadNotesForPad(pad.id, pad.name, pad.is_public, pad.owner_id, false, null, pad.can_write)); container.appendChild(item); }); } let currentMarkers = []; let topZIndex = 1000000; async function toggleFavorite(padId, action) { try { const res = await fetch(`/api/notepads/${padId}/${action}`, { method: 'POST' }); if (res.ok) { // Refresh the lists loadNotepadsOfType('favorites', 'favorite-notepads-list'); loadNotepadsOfType('mine', 'my-notepads-list'); loadNotepadsOfType('public', 'public-notepads-list'); } else { alert(`Failed to ${action} notepad`); } } catch (err) { console.error(err); } } async function loadNotepadsOfType(type, containerId) { try { const res = await fetch(`/api/notepads?type=${type}`); const notepads = await res.json(); const isFavorite = type === 'favorites'; renderNotepadList(notepads, containerId, isFavorite); } catch (err) { console.error(`Failed to load ${type} notepads`, err); document.getElementById(containerId).innerHTML = '

Error loading data.

'; } } async function loadNotesForPad(padId, padName, isPublic, ownerId, centerOnFirst = false, token = null, canWrite = undefined) { activePadId = padId; // If metadata is missing (e.g. from URL share), fetch it if (padName === undefined) { try { const res = await fetch(`/api/notepads/${padId}?token=${token || ''}`); const pad = await res.json(); padName = pad.name; isPublic = pad.is_public; ownerId = pad.owner_id; activePadCanWrite = pad.can_write; } catch(e) { console.error(e); activePadCanWrite = false; } } if (padName !== undefined) activePadName = padName; if (isPublic !== undefined) activePadIsPublic = isPublic; if (ownerId !== undefined) activePadOwnerId = ownerId; if (canWrite !== undefined) { activePadCanWrite = canWrite; } else if (padName !== undefined) { // Fallback if not passed: assume true only if owner activePadCanWrite = (currentUser && ownerId === currentUser.id); } const currentName = activePadName; const isOwner = currentUser && activePadOwnerId === currentUser.id; // Clear existing markers currentMarkers.forEach(marker => map.removeLayer(marker)); currentMarkers = []; activeNotes = []; // Update Sidebar Header const header = document.querySelector('.sidebar-header'); if (header) { const addNoteBtn = activePadCanWrite ? `` : ''; const manageShareBtn = isOwner ? `` : ''; const exportBtn = ``; header.innerHTML = `

${escapeHtml(currentName)}

${manageShareBtn} ${exportBtn}
${addNoteBtn} `; document.getElementById('btn-back-pads').addEventListener('click', loadNotepads); } const sidebarBody = document.getElementById('sidebar-body'); sidebarBody.innerHTML = '

Loading notes...

'; try { const res = await fetch(`/api/notepads/${padId}/notes?token=${token || ''}`); const notes = await res.json(); activeNotes = notes; // Render Sidebar List sidebarBody.innerHTML = ''; if (notes.length === 0) { sidebarBody.innerHTML = '

No notes yet.

'; } notes.forEach(note => { const item = document.createElement('div'); item.className = 'sidebar-note-item'; let actionBtns = ''; if (activePadCanWrite) { const escapedTitle = escapeHtml(note.title).replace(/'/g, "\\'").replace(/"/g, '"'); const escapedContent = escapeHtml(note.content).replace(/'/g, "\\'").replace(/"/g, '"').replace(/\n/g, '\\n'); actionBtns = ` `; } else if (activePadIsPublic) { actionBtns = ``; } const dateStr = new Date(note.created_at).toLocaleString(); item.innerHTML = `
${escapeHtml(note.title)}
${escapeHtml(note.content)}
${dateStr}
${note.lat.toFixed(5)}, ${note.lng.toFixed(5)}
${actionBtns}
`; item.addEventListener('click', () => { stopTracking(); map.setView([note.lat, note.lng], 16); }); sidebarBody.appendChild(item); }); renderMapMarkers(); if (centerOnFirst && notes.length > 0) { map.setView([notes[0].lat, notes[0].lng], 13); } } catch (err) { console.error(err); sidebarBody.innerHTML = '

Error loading notes.

'; } } async function loadSingleNote(noteId, token = null) { // Reset state activeNotes = []; currentMarkers.forEach(marker => map.removeLayer(marker)); currentMarkers = []; activePadId = null; const sidebarBody = document.getElementById('sidebar-body'); sidebarBody.innerHTML = '

Loading note...

'; try { const res = await fetch(`/api/notes/${noteId}?token=${token || ''}`); if (!res.ok) throw new Error("Note not found or private"); const note = await res.json(); // Set active notes to just this one so renderMapMarkers works activeNotes = [note]; // Update Header const header = document.querySelector('.sidebar-header'); if (header) { header.innerHTML = `

Shared Note

`; document.getElementById('btn-back-pads').addEventListener('click', loadNotepads); } sidebarBody.innerHTML = ''; const noteInfoDiv = document.createElement('div'); noteInfoDiv.style.padding = '10px'; const p = document.createElement('p'); p.appendChild(document.createTextNode('Viewing single note from ')); if (note.notepad.is_public) { const link = document.createElement('a'); link.href = "#"; link.textContent = note.notepad.name; link.style.fontWeight = 'bold'; link.onclick = (e) => { e.preventDefault(); loadNotesForPad(note.notepad.id, note.notepad.name, true, note.owner_id, false, null, note.notepad.can_write); }; p.appendChild(link); } else { const strong = document.createElement('strong'); strong.textContent = note.notepad.name; p.appendChild(strong); } p.appendChild(document.createTextNode('.')); noteInfoDiv.appendChild(p); sidebarBody.appendChild(noteInfoDiv); renderMapMarkers(); map.setView([note.lat, note.lng], 16); if (window.innerWidth <= 600) { const sidebar = document.getElementById('sidebar'); const toggleBtn = document.getElementById('sidebar-toggle'); if (sidebar && !sidebar.classList.contains('collapsed')) { sidebar.classList.add('collapsed'); if (toggleBtn) toggleBtn.innerHTML = '<'; } } } catch (err) { sidebarBody.innerHTML = '

Failed to load note. It may be private or deleted.

'; } } function renderMapMarkers() { // Clear existing currentMarkers.forEach(marker => map.removeLayer(marker)); currentMarkers = []; const zoom = map.getZoom(); const showFull = zoom >= 14; // Zoom threshold activeNotes.forEach(note => { let marker; let actionBtns = ''; // Determine permissions: Use note-specific info if available (search results), else fall back to pad globals const isOwner = currentUser && (note.owner_id ? note.owner_id === currentUser.id : activePadOwnerId === currentUser.id); const isPublic = note.is_public !== undefined ? note.is_public : activePadIsPublic; const canWrite = (note.notepad && note.notepad.can_write !== undefined) ? note.notepad.can_write : activePadCanWrite; if (canWrite) { const escapedTitle = escapeHtml(note.title).replace(/'/g, "\\'").replace(/"/g, '"'); const escapedContent = escapeHtml(note.content).replace(/'/g, "\\'").replace(/"/g, '"').replace(/\n/g, '\\n'); actionBtns = `
`; } else if (isPublic) { actionBtns = `
`; } const shareToken = note.share_token || ''; const shareBtn = ``; const dateStr = new Date(note.created_at).toLocaleString(); if (showFull) { const icon = L.divIcon({ className: '', html: `
${escapeHtml(note.title)}
${escapeHtml(note.content)}
${dateStr}
${shareBtn} ${actionBtns}
`, iconSize: [200, 'auto'], iconAnchor: [100, 0] }); marker = L.marker([note.lat, note.lng], { icon: icon }).addTo(map); } else { marker = L.marker([note.lat, note.lng]).addTo(map); marker.bindPopup(`${escapeHtml(note.title)}
${escapeHtml(note.content)}
${dateStr}
${shareBtn} ${actionBtns}`); } const bumpZIndex = function() { this.setZIndexOffset(topZIndex++); }; marker.on('click', bumpZIndex); marker.on('mousedown', bumpZIndex); currentMarkers.push(marker); }); } window.displaySearchResults = function(notes, location, query) { // Reset Pad State to "Search Mode" activePadId = null; activePadName = `Search: ${query}`; activePadIsPublic = false; // Mixed results activePadOwnerId = null; // Mixed results activeNotes = notes; // Update Sidebar Header const header = document.querySelector('.sidebar-header'); if (header) { header.innerHTML = `

Results: ${escapeHtml(query)}

`; document.getElementById('btn-back-pads').addEventListener('click', loadNotepads); } const sidebarBody = document.getElementById('sidebar-body'); sidebarBody.innerHTML = ''; if (notes.length === 0 && !location) { sidebarBody.innerHTML = '

No results found.

'; renderMapMarkers(); return; } else if (notes.length === 0 && location) { sidebarBody.innerHTML = '

Location found on map.

'; renderMapMarkers(); map.setView([location.lat, location.lng], 13); return; } // Group notes by section and notepad const sections = { favorites: {}, // Map mine: {}, public: {} }; notes.forEach(note => { const pad = note.notepad; // Helper to add to a section const addToSection = (secKey) => { if (!sections[secKey][pad.id]) { sections[secKey][pad.id] = { pad: pad, notes: [] }; } sections[secKey][pad.id].notes.push(note); }; if (pad.is_favorite) addToSection('favorites'); if (currentUser && pad.owner_id === currentUser.id) addToSection('mine'); if (pad.is_public) addToSection('public'); }); // Helper function to render a collapsible section const renderSection = (title, dataMap, isOpen) => { const sectionDiv = document.createElement('div'); sectionDiv.className = 'list-section'; const arrow = isOpen ? '▾' : '▸'; const display = isOpen ? 'block' : 'none'; const headerBtn = document.createElement('button'); headerBtn.className = 'list-section-header'; headerBtn.innerHTML = `${title} ${arrow}`; headerBtn.onclick = toggleSection; const contentDiv = document.createElement('div'); contentDiv.className = 'list-section-content'; contentDiv.style.display = display; const padIds = Object.keys(dataMap); if (padIds.length === 0) { contentDiv.innerHTML = '

No matching notes.

'; } else { padIds.forEach(padId => { const entry = dataMap[padId]; const pad = entry.pad; // Notepad Header, styled like the default view const padItem = document.createElement('div'); padItem.className = 'notepad-item'; padItem.style.backgroundColor = '#e9ecef'; // Differentiate as a sub-header padItem.style.cursor = 'default'; let icon = pad.is_public ? '🌍' : '🔒'; let favButton = ''; if(isLoggedIn){ const isFavorite = pad.is_favorite; const action = isFavorite ? 'unfavorite' : 'favorite'; const label = isFavorite ? '♥' : '♡'; favButton = ``; } padItem.innerHTML = `
${icon} ${escapeHtml(pad.name)}
${favButton}
`; contentDiv.appendChild(padItem); entry.notes.forEach(note => { const item = document.createElement('div'); item.className = 'sidebar-note-item'; const dateStr = new Date(note.created_at).toLocaleString(); let actionBtn = ''; // Renaming to actionBtns for consistency if (note.notepad && note.notepad.can_write) { const escapedTitle = escapeHtml(note.title).replace(/'/g, "\\'").replace(/"/g, '"'); const escapedContent = escapeHtml(note.content).replace(/'/g, "\\'").replace(/"/g, '"').replace(/\n/g, '\\n'); actionBtn = ` `; } else if (note.is_public) { actionBtn = ``; } item.innerHTML = `
${escapeHtml(note.title)}
${escapeHtml(note.content)}
${dateStr}
${note.lat.toFixed(5)}, ${note.lng.toFixed(5)}
${actionBtn}
`; item.addEventListener('click', () => { stopTracking(); map.setView([note.lat, note.lng], 16); }); contentDiv.appendChild(item); }); }); } sectionDiv.appendChild(headerBtn); sectionDiv.appendChild(contentDiv); sidebarBody.appendChild(sectionDiv); }; if (isLoggedIn) { if (Object.keys(sections.favorites).length > 0) renderSection('Favorite Notepads', sections.favorites, true); if (Object.keys(sections.mine).length > 0) renderSection('My Notepads', sections.mine, true); if (Object.keys(sections.public).length > 0) renderSection('Public Notepads', sections.public, true); } else { if (Object.keys(sections.public).length > 0) renderSection('Public Notepads', sections.public, true); } renderMapMarkers(); if (notes.length > 0) { map.setView([notes[0].lat, notes[0].lng], 15); } else if (location) { map.setView([location.lat, location.lng], 13); } }; window.reportNote = async function(noteId) { if (!confirm("Report this note? It will be hidden from public view.")) return; try { const res = await fetch(`/api/notes/${noteId}/report`, { method: 'POST' }); if (res.ok) { alert("Note reported and hidden."); // Refresh current pad loadNotesForPad(activePadId, activePadName, activePadIsPublic); } } catch (err) { console.error("Error reporting note:", err); } }; window.deleteNotepad = async function(padId) { if (!confirm("Are you sure you want to delete this notepad? All notes inside will be lost.")) return; try { const res = await fetch(`/api/notepads/${padId}`, { method: 'DELETE' }); if (res.ok) { loadNotepads(); // Refresh list } else { alert("Failed to delete notepad."); } } catch (err) { console.error(err); } }; window.openShareSettingsModal = async function(padId, padName) { const modal = document.getElementById('modal-share-settings'); document.getElementById('share-pad-name').textContent = padName; document.getElementById('share-pad-id').value = padId; const listDiv = document.getElementById('collaborators-list'); listDiv.innerHTML = '

Loading...

'; modal.classList.remove('hidden'); try { const res = await fetch(`/api/notepads/${padId}/collaborators`); if (!res.ok) { const err = await res.json(); throw new Error(err.error || 'Failed to load collaborators'); } const collaborators = await res.json(); listDiv.innerHTML = ''; if (collaborators.length === 0) { listDiv.innerHTML = '

No collaborators yet.

'; } else { collaborators.forEach(collab => { const item = document.createElement('div'); item.className = 'collaborator-item'; item.innerHTML = ` ${escapeHtml(collab.email)} (${collab.permission}) `; listDiv.appendChild(item); }); } } catch (err) { listDiv.innerHTML = `

${err.message}

`; } } window.removeCollaborator = async function(padId, userId) { if (!confirm("Are you sure you want to remove this collaborator?")) return; try { const res = await fetch(`/api/notepads/${padId}/collaborators/${userId}`, { method: 'DELETE' }); if (res.ok) { const padName = document.getElementById('share-pad-name').textContent; openShareSettingsModal(padId, padName); } else { const err = await res.json(); alert(`Failed to remove collaborator: ${err.error}`); } } catch (err) { console.error(err); alert('An error occurred.'); } } async function loadAllMyNotes() { activePadId = null; activePadName = "All My Notes"; activePadIsPublic = false; activePadCanWrite = true; if (currentUser) { activePadOwnerId = currentUser.id; } // Clear existing markers currentMarkers.forEach(marker => map.removeLayer(marker)); currentMarkers = []; activeNotes = []; try { const res = await fetch('/api/notes/mine'); if (!res.ok) throw new Error("Failed to load"); const notes = await res.json(); activeNotes = notes; renderMapMarkers(); if (notes.length > 0) { // Auto-center map bounds cleanly around all the user's notes const bounds = L.latLngBounds(notes.map(n => [n.lat, n.lng])); map.fitBounds(bounds, { padding: [50, 50], maxZoom: 15 }); } } catch (err) { console.error("Error loading all my notes:", err); } } window.shareNotepad = function(padId, token) { let url = `${window.location.origin}/?pad=${padId}`; if (token) url += `&token=${token}`; navigator.clipboard.writeText(url).then(() => { alert("Notepad link copied to clipboard!"); }); }; window.shareNote = function(noteId, token) { let url = `${window.location.origin}/?note=${noteId}`; if (token) url += `&token=${token}`; navigator.clipboard.writeText(url).then(() => { alert("Note link copied to clipboard!"); }); }; function stopTracking() { isTracking = false; updateTrackingUI(); } function updateTrackingUI() { const btn = document.getElementById('btn-center-user'); if (btn) { if (isTracking) { btn.textContent = "Tracking Location..."; btn.style.backgroundColor = "#28a745"; } else { btn.textContent = "Target My Location"; btn.style.backgroundColor = ""; } } } function escapeHtml(text) { if (text === null || text === undefined) return ''; return String(text) .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } function toggleSection(event) { const section = event.target.closest('.list-section'); const content = section.querySelector('.list-section-content'); const isCollapsed = content.style.display === 'none'; content.style.display = isCollapsed ? 'block' : 'none'; event.target.innerHTML = isCollapsed ? event.target.innerHTML.replace('▸', '▾') : event.target.innerHTML.replace('▾', '▸'); } window.deleteNote = async function(noteId) { if (!confirm("Delete this note?")) return; try { const res = await fetch(`/api/notes/${noteId}`, { method: 'DELETE' }); if (res.ok) { // If we are in a pad view, reload the pad. if (activePadId) { loadNotesForPad(activePadId); } else { // Otherwise (e.g., search results), the safest refresh is to return to the main list. alert("Note deleted. Returning to notepad list."); loadNotepads(); } } else { alert("Failed to delete note."); } } catch (err) { console.error(err); } };