Working map journey editor and blog journey editor

This commit is contained in:
Josh-Dev-Quest 2026-03-28 19:28:42 +01:00
parent 0de91bf814
commit a9ab42eda5
No known key found for this signature in database
5 changed files with 539 additions and 403 deletions

View File

@ -8,25 +8,28 @@
{
"lat": 46.638122462379656,
"lng": 4.806518554687501,
"title": "New Marker",
"date": "",
"description": "",
"videoUrl": ""
"title": "New test again",
"date": "2026-03-03",
"description": "asfasfadsfsa",
"image": "",
"videoUrl": "https://duckduckgo.com/?t=ffab&q=pythong+gif&ia=images&iax=images&iai=https%3A%2F%2Fmedia.tenor.com%2FfMUOPRVdSzUAAAAM%2Fpython.gif"
},
{
"lat": 47.12621341795227,
"lng": 6.943359375000001,
"title": "New Marker",
"title": "safasf",
"date": "",
"description": "",
"description": "sdfadsa",
"image": "",
"videoUrl": ""
},
{
"lat": 46.46813299215556,
"lng": 6.7730712890625,
"title": "New Marker",
"title": "asfaf",
"date": "",
"description": "",
"description": "asdfsafa",
"image": "",
"videoUrl": ""
}
],
@ -34,6 +37,14 @@
"visibility": "private",
"shared_read": [],
"shared_edit": [],
"comments": []
"comments": [
{
"id": 1774716476571,
"author_id": 1,
"author_name": "josh",
"text": "safasdf",
"created_at": "2026-03-28T17:47:56.571469"
}
]
}
]

View File

@ -1,368 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Blog Post Journey Mapper</title>
<!-- Open Props CSS -->
<link rel="stylesheet" href="https://unpkg.com/open-props" />
<link rel="stylesheet" href="https://unpkg.com/open-props/normalize.min.css" />
<!-- Font Awesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" />
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet" />
<style>
* { box-sizing: border-box; }
body {
font-family: var(--font-sans);
background: var(--gray-0);
color: var(--gray-9);
line-height: var(--font-lineheight-3);
margin: 0;
display: flex;
flex-direction: column;
min-height: 100vh;
}
/* Header */
.site-header {
background: var(--gray-9);
padding: var(--size-4) var(--size-6);
border-bottom: 1px solid var(--surface-4);
}
.site-header .container {
max-width: 1400px;
margin: 0 auto;
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: var(--size-2);
}
.site-title {
margin: 0;
font-size: var(--font-size-4);
font-weight: var(--font-weight-6);
}
.site-title a {
color: var(--indigo-4);
text-decoration: none;
}
.site-nav {
display: flex;
gap: var(--size-4);
}
.site-nav a {
color: var(--gray-2);
text-decoration: none;
font-weight: var(--font-weight-5);
transition: color 0.2s;
padding: var(--size-1) var(--size-2);
border-radius: var(--radius-2);
}
.site-nav a:hover {
color: var(--indigo-4);
background: var(--surface-2);
}
/* User menu */
.user-menu {
display: flex;
align-items: center;
gap: var(--size-2);
}
.user-menu .username {
color: var(--gray-2);
font-weight: var(--font-weight-5);
}
.logout-btn {
background: var(--indigo-7);
color: white;
border: none;
border-radius: var(--radius-2);
padding: var(--size-1) var(--size-3);
cursor: pointer;
font-size: var(--font-size-1);
font-weight: var(--font-weight-5);
transition: background 0.2s;
}
.logout-btn:hover {
background: var(--indigo-8);
}
/* Main content */
.post-container {
max-width: 800px;
margin: var(--size-6) auto;
padding: 0 var(--size-4);
}
.post-form {
background: var(--surface-1);
border-radius: var(--radius-3);
padding: var(--size-6);
box-shadow: var(--shadow-2);
}
.form-group {
margin-bottom: var(--size-4);
}
label {
display: block;
margin-bottom: var(--size-2);
font-weight: var(--font-weight-6);
color: var(--gray-8);
}
input[type="text"],
textarea,
select {
width: 100%;
padding: var(--size-2) var(--size-3);
border: 1px solid var(--surface-4);
border-radius: var(--radius-2);
background: var(--surface-2);
color: var(--text-1);
font-family: inherit;
font-size: var(--font-size-2);
}
textarea {
min-height: 200px;
resize: vertical;
}
.image-preview {
margin-top: var(--size-2);
max-width: 100%;
border-radius: var(--radius-2);
overflow: hidden;
}
.image-preview img {
max-width: 100%;
height: auto;
display: block;
}
.button-group {
display: flex;
gap: var(--size-3);
margin-top: var(--size-6);
}
.btn {
padding: var(--size-2) var(--size-4);
border: none;
border-radius: var(--radius-2);
cursor: pointer;
font-size: var(--font-size-2);
font-weight: var(--font-weight-5);
display: inline-flex;
align-items: center;
gap: var(--size-2);
transition: all 0.2s var(--ease-2);
box-shadow: var(--shadow-2);
background: var(--gray-7);
color: white;
text-decoration: none;
}
.btn-primary {
background: var(--indigo-7);
}
.btn-primary:hover {
background: var(--indigo-8);
}
.btn-danger {
background: var(--red-7);
}
.btn-danger:hover {
background: var(--red-8);
}
.btn:hover {
box-shadow: var(--shadow-3);
}
.toast {
position: fixed;
bottom: var(--size-4);
right: var(--size-4);
background: var(--green-7);
color: white;
padding: var(--size-2) var(--size-4);
border-radius: var(--radius-2);
display: none;
z-index: 1100;
}
</style>
</head>
<body>
<header class="site-header">
<div class="container">
<h1 class="site-title"><a href="map-page.html">Journey Mapper</a></h1>
<div style="display: flex; align-items: center; gap: var(--size-4);">
<nav class="site-nav">
<a href="map-page.html">Map</a>
<a href="blog-list.html" class="active">Blog</a>
</nav>
<div class="user-menu" id="user-menu"></div>
</div>
</div>
</header>
<main class="post-container">
<div class="post-form">
<h2 id="form-title">Edit Post</h2>
<form id="post-form">
<div class="form-group">
<label for="post-title">Title</label>
<input type="text" id="post-title" required />
</div>
<div class="form-group">
<label for="post-content">Content</label>
<textarea id="post-content" rows="10" required></textarea>
</div>
<div class="form-group">
<label for="post-journey">Associated Journey ID (optional)</label>
<input type="text" id="post-journey" placeholder="e.g., 3" />
</div>
<div class="form-group">
<label for="post-image">Image URL or Upload</label>
<input type="text" id="post-image-url" placeholder="https://..." />
<div style="margin: 8px 0; text-align: center">or</div>
<input type="file" id="image-upload" accept="image/*" />
<div class="image-preview" id="image-preview"></div>
</div>
<div class="button-group">
<button type="submit" class="btn btn-primary"><i class="fas fa-save"></i> Save</button>
<button type="button" id="delete-post" class="btn btn-danger"><i class="fas fa-trash"></i> Delete</button>
<a href="blog-list.html" class="btn"><i class="fas fa-times"></i> Cancel</a>
</div>
</form>
</div>
</main>
<div id="toast" class="toast"></div>
<script src="js/auth.js"></script>
<script>
let currentPostId = null;
// ==================== POST CRUD ====================
const urlParams = new URLSearchParams(window.location.search);
const postId = urlParams.get('id');
const isNew = urlParams.has('new');
async function loadPost(id) {
try {
const res = await fetch(`${API_BASE}/blog-posts/${id}`, { credentials: 'include' });
if (!res.ok) throw new Error('Post not found');
const post = await res.json();
currentPostId = post.id;
document.getElementById('post-title').value = post.title;
document.getElementById('post-content').value = post.content;
document.getElementById('post-journey').value = post.journeyId || '';
document.getElementById('post-image-url').value = post.image || '';
updateImagePreview(post.image);
document.getElementById('form-title').textContent = 'Edit Post';
} catch (err) {
showToast('Error loading post', true);
}
}
function updateImagePreview(url) {
const preview = document.getElementById('image-preview');
if (url) {
preview.innerHTML = `<img src="${url}" alt="Preview" style="max-width:100%; border-radius: var(--radius-2);">`;
} else {
preview.innerHTML = '';
}
}
async function savePost(event) {
event.preventDefault();
const title = document.getElementById('post-title').value.trim();
const content = document.getElementById('post-content').value.trim();
const journeyId = document.getElementById('post-journey').value.trim();
let image = document.getElementById('post-image-url').value.trim();
if (!title || !content) {
showToast('Title and content are required');
return;
}
const payload = { title, content, journeyId: journeyId || null, image: image || null };
try {
let url, method;
if (isNew) {
url = `${API_BASE}/blog-posts`;
method = 'POST';
} else {
url = `${API_BASE}/blog-posts/${currentPostId}`;
method = 'PUT';
}
const res = await fetch(url, {
method,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
credentials: 'include'
});
if (!res.ok) throw new Error('Save failed');
const data = await res.json();
showToast('Post saved successfully');
// Redirect to the read page
window.location.href = `blog-post.html?id=${data.id}`;
} catch (err) {
showToast('Error saving post', true);
}
}
async function deletePost() {
if (!currentPostId) return;
if (!confirm('Delete this post?')) return;
try {
const res = await fetch(`${API_BASE}/blog-posts/${currentPostId}`, {
method: 'DELETE',
credentials: 'include'
});
if (!res.ok) throw new Error('Delete failed');
showToast('Post deleted');
setTimeout(() => { window.location.href = 'blog-list.html'; }, 1000);
} catch (err) {
showToast('Error deleting post', true);
}
}
// Image upload (convert to base64)
document.getElementById('image-upload').addEventListener('change', function(e) {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function(evt) {
const base64 = evt.target.result;
document.getElementById('post-image-url').value = base64;
updateImagePreview(base64);
};
reader.readAsDataURL(file);
});
document.getElementById('post-form').addEventListener('submit', savePost);
document.getElementById('delete-post').addEventListener('click', deletePost);
// ==================== INITIALIZATION ====================
document.addEventListener('DOMContentLoaded', async () => {
const authenticated = await checkAuthAndRedirect();
if (!authenticated) return;
updateUserMenu();
if (!isNew && postId) {
loadPost(postId);
} else if (isNew) {
currentPostId = null;
document.getElementById('form-title').textContent = 'New Post';
document.getElementById('delete-post').style.display = 'none';
} else {
// No id and not new redirect to list
window.location.href = 'blog-list.html';
}
});
</script>
</body>
</html>

View File

@ -319,7 +319,7 @@
${chaptersHtml}
${isOwner ? `
<div style="margin-top: var(--size-4); display: flex; gap: var(--size-2);">
<a href="map-page.html?journey=${currentJourney.id}" class="btn btn-sm"><i class="fas fa-edit"></i> Edit</a>
<a href="journey-edit.html?id=${currentJourney.id}" class="btn btn-sm"><i class="fas fa-edit"></i> Edit</a>
<button id="delete-journey-btn" class="btn btn-danger btn-sm"><i class="fas fa-trash"></i> Delete</button>
</div>
` : ''}

501
journey-edit.html Normal file
View File

@ -0,0 +1,501 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Edit Journey Journey Mapper</title>
<!-- Open Props CSS -->
<link rel="stylesheet" href="https://unpkg.com/open-props"/>
<link rel="stylesheet" href="https://unpkg.com/open-props/normalize.min.css"/>
<!-- Font Awesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<style>
* { box-sizing: border-box; }
body {
font-family: var(--font-sans);
background: var(--gray-0);
color: var(--gray-9);
line-height: var(--font-lineheight-3);
margin: 0;
display: flex;
flex-direction: column;
min-height: 100vh;
}
/* Header */
.site-header {
background: var(--gray-9);
padding: var(--size-4) var(--size-6);
border-bottom: 1px solid var(--surface-4);
}
.site-header .container {
max-width: 1400px;
margin: 0 auto;
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: var(--size-2);
}
.site-title {
margin: 0;
font-size: var(--font-size-4);
font-weight: var(--font-weight-6);
}
.site-title a {
color: var(--indigo-4);
text-decoration: none;
}
.site-nav {
display: flex;
gap: var(--size-4);
}
.site-nav a {
color: var(--gray-2);
text-decoration: none;
font-weight: var(--font-weight-5);
transition: color 0.2s;
padding: var(--size-1) var(--size-2);
border-radius: var(--radius-2);
}
.site-nav a:hover,
.site-nav a.active {
color: var(--indigo-4);
background: var(--surface-2);
}
/* User menu */
.user-menu {
display: flex;
align-items: center;
gap: var(--size-2);
}
.user-menu .username {
color: var(--gray-2);
font-weight: var(--font-weight-5);
}
.logout-btn {
background: var(--indigo-7);
color: white;
border: none;
border-radius: var(--radius-2);
padding: var(--size-1) var(--size-3);
cursor: pointer;
font-size: var(--font-size-1);
font-weight: var(--font-weight-5);
transition: background 0.2s;
}
.logout-btn:hover {
background: var(--indigo-8);
}
/* Main content */
.editor-container {
max-width: 1000px;
margin: var(--size-6) auto;
padding: 0 var(--size-4);
}
.editor-form {
background: var(--surface-1);
border-radius: var(--radius-3);
padding: var(--size-6);
box-shadow: var(--shadow-2);
}
.form-group {
margin-bottom: var(--size-4);
}
label {
display: block;
margin-bottom: var(--size-2);
font-weight: var(--font-weight-6);
color: var(--gray-8);
}
input[type="text"],
textarea,
select {
width: 100%;
padding: var(--size-2) var(--size-3);
border: 1px solid var(--surface-4);
border-radius: var(--radius-2);
background: var(--surface-2);
color: var(--text-1);
font-family: inherit;
font-size: var(--font-size-2);
}
textarea {
min-height: 120px;
resize: vertical;
}
.marker-card {
background: var(--surface-2);
border-radius: var(--radius-2);
padding: var(--size-4);
margin-bottom: var(--size-4);
border: 1px solid var(--surface-4);
position: relative;
}
.marker-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--size-2);
cursor: move;
}
.marker-header h4 {
margin: 0;
font-size: var(--font-size-3);
}
.remove-marker {
background: none;
border: none;
color: var(--red-6);
cursor: pointer;
font-size: var(--font-size-3);
}
.remove-marker:hover {
color: var(--red-8);
}
.marker-coords {
font-size: var(--font-size-0);
color: var(--gray-6);
margin-bottom: var(--size-2);
}
.btn {
padding: var(--size-2) var(--size-4);
border: none;
border-radius: var(--radius-2);
cursor: pointer;
font-size: var(--font-size-2);
font-weight: var(--font-weight-5);
display: inline-flex;
align-items: center;
gap: var(--size-2);
transition: all 0.2s var(--ease-2);
box-shadow: var(--shadow-2);
background: var(--gray-7);
color: white;
text-decoration: none;
}
.btn-primary {
background: var(--indigo-7);
}
.btn-primary:hover {
background: var(--indigo-8);
}
.btn-success {
background: var(--green-7);
}
.btn-success:hover {
background: var(--green-8);
}
.btn-danger {
background: var(--red-7);
}
.btn-danger:hover {
background: var(--red-8);
}
.btn-outline {
background: transparent;
border: 1px solid var(--surface-4);
color: var(--text-2);
box-shadow: none;
}
.btn-outline:hover {
background: var(--surface-3);
}
.button-group {
display: flex;
gap: var(--size-3);
margin-top: var(--size-6);
flex-wrap: wrap;
}
.toast {
position: fixed;
bottom: var(--size-4);
right: var(--size-4);
background: var(--green-7);
color: white;
padding: var(--size-2) var(--size-4);
border-radius: var(--radius-2);
display: none;
z-index: 1100;
}
</style>
</head>
<body>
<header class="site-header">
<div class="container">
<h1 class="site-title"><a href="map-page.html">Journey Mapper</a></h1>
<div style="display: flex; align-items: center; gap: var(--size-4);">
<nav class="site-nav">
<a href="map-page.html">Map</a>
<a href="blog-list.html">Blog</a>
</nav>
<div class="user-menu" id="user-menu"></div>
</div>
</div>
</header>
<main class="editor-container">
<div class="editor-form">
<h2 id="form-title">Edit Journey</h2>
<form id="journey-form">
<div class="form-group">
<label for="journey-title">Title</label>
<input type="text" id="journey-title" required>
</div>
<div class="form-group">
<label for="journey-description">Description</label>
<textarea id="journey-description" rows="4"></textarea>
</div>
<div class="form-group">
<label for="journey-visibility">Visibility</label>
<select id="journey-visibility">
<option value="private">Private (only you)</option>
<option value="public">Public (anyone can view)</option>
<option value="shared">Shared (with specific users)</option>
</select>
</div>
<h3><i class="fas fa-map-marker-alt"></i> Chapters (Markers)</h3>
<div id="markers-container"></div>
<div class="button-group">
<button type="button" id="add-marker" class="btn btn-outline"><i class="fas fa-plus"></i> Add Chapter</button>
</div>
<div class="button-group">
<button type="submit" class="btn btn-primary"><i class="fas fa-save"></i> Save Journey</button>
<a href="blog-list.html" class="btn"><i class="fas fa-times"></i> Cancel</a>
</div>
</form>
</div>
</main>
<div id="toast" class="toast"></div>
<script src="js/auth.js"></script>
<script>
// ==================== GLOBALS ====================
let currentJourneyId = null;
let markersData = [];
const urlParams = new URLSearchParams(window.location.search);
const journeyId = urlParams.get('id');
const isNew = urlParams.has('new');
// ==================== UI HELPERS ====================
function showToast(message, isError = false) {
const toast = document.getElementById('toast');
toast.textContent = message;
toast.style.backgroundColor = isError ? 'var(--red-7)' : 'var(--green-7)';
toast.style.display = 'block';
setTimeout(() => { toast.style.display = 'none'; }, 3000);
}
// ==================== RENDER MARKERS ====================
function renderMarkers() {
const container = document.getElementById('markers-container');
if (!markersData.length) {
container.innerHTML = '<p class="empty-state" style="text-align:center; color: var(--gray-6);">No chapters yet. Click "Add Chapter" to create one.</p>';
return;
}
container.innerHTML = markersData.map((marker, idx) => `
<div class="marker-card" data-marker-index="${idx}">
<div class="marker-header">
<h4><i class="fas fa-map-pin"></i> Chapter ${idx+1}</h4>
<button type="button" class="remove-marker" data-index="${idx}"><i class="fas fa-trash-alt"></i></button>
</div>
<div class="marker-coords">
<i class="fas fa-location-dot"></i> ${marker.lat.toFixed(6)}, ${marker.lng.toFixed(6)}
</div>
<div class="form-group">
<label>Chapter Title</label>
<input type="text" class="marker-title" data-index="${idx}" value="${escapeHtml(marker.title || '')}" placeholder="Title">
</div>
<div class="form-group">
<label>Date (optional)</label>
<input type="date" class="marker-date" data-index="${idx}" value="${marker.date || ''}">
</div>
<div class="form-group">
<label>Description</label>
<textarea class="marker-description" data-index="${idx}" rows="3" placeholder="Write about this chapter...">${escapeHtml(marker.description || '')}</textarea>
</div>
<div class="form-group">
<label>Image URL</label>
<input type="text" class="marker-image" data-index="${idx}" value="${escapeHtml(marker.image || '')}" placeholder="https://...">
</div>
<div class="form-group">
<label>Video URL</label>
<input type="text" class="marker-video" data-index="${idx}" value="${escapeHtml(marker.videoUrl || '')}" placeholder="https://youtu.be/...">
</div>
</div>
`).join('');
// Attach remove listeners
document.querySelectorAll('.remove-marker').forEach(btn => {
btn.addEventListener('click', (e) => {
const idx = parseInt(btn.dataset.index);
markersData.splice(idx, 1);
renderMarkers();
});
});
// Attach input listeners to update markersData
document.querySelectorAll('.marker-title').forEach(input => {
input.addEventListener('input', (e) => {
const idx = parseInt(input.dataset.index);
markersData[idx].title = input.value;
});
});
document.querySelectorAll('.marker-date').forEach(input => {
input.addEventListener('input', (e) => {
const idx = parseInt(input.dataset.index);
markersData[idx].date = input.value;
});
});
document.querySelectorAll('.marker-description').forEach(textarea => {
textarea.addEventListener('input', (e) => {
const idx = parseInt(textarea.dataset.index);
markersData[idx].description = textarea.value;
});
});
document.querySelectorAll('.marker-image').forEach(input => {
input.addEventListener('input', (e) => {
const idx = parseInt(input.dataset.index);
markersData[idx].image = input.value;
});
});
document.querySelectorAll('.marker-video').forEach(input => {
input.addEventListener('input', (e) => {
const idx = parseInt(input.dataset.index);
markersData[idx].videoUrl = input.value;
});
});
}
// ==================== LOAD JOURNEY ====================
async function loadJourney(id) {
console.log('Loading journey with id:', id);
try {
const res = await fetch(`${API_BASE}/journeys/${id}`, { credentials: 'include' });
if (!res.ok) {
console.error('Failed to fetch journey, status:', res.status);
throw new Error('Journey not found');
}
const journey = await res.json();
console.log('Journey data:', journey);
currentJourneyId = journey.id;
document.getElementById('journey-title').value = journey.title;
document.getElementById('journey-description').value = journey.description || '';
document.getElementById('journey-visibility').value = journey.visibility || 'private';
markersData = journey.markers || [];
console.log('Markers data loaded:', markersData);
renderMarkers();
document.getElementById('form-title').textContent = 'Edit Journey';
} catch (err) {
console.error('Error loading journey:', err);
showToast('Error loading journey: ' + err.message, true);
// Optionally redirect after a delay
setTimeout(() => window.location.href = 'blog-list.html', 2000);
}
}
// ==================== SAVE JOURNEY ====================
async function saveJourney(event) {
event.preventDefault();
const title = document.getElementById('journey-title').value.trim();
const description = document.getElementById('journey-description').value.trim();
const visibility = document.getElementById('journey-visibility').value;
if (!title) {
showToast('Please enter a title', true);
return;
}
// Build markers array from current form data (already in markersData)
const markers = markersData.map(m => ({
lat: m.lat,
lng: m.lng,
title: m.title || '',
date: m.date || '',
description: m.description || '',
image: m.image || '',
videoUrl: m.videoUrl || ''
}));
const payload = { title, description, markers, visibility };
console.log('Saving payload:', payload);
try {
let res;
if (isNew) {
res = await fetch(`${API_BASE}/journeys`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
credentials: 'include'
});
} else {
res = await fetch(`${API_BASE}/journeys/${currentJourneyId}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
credentials: 'include'
});
}
if (!res.ok) throw new Error('Save failed');
const data = await res.json();
console.log('Save response:', data);
showToast('Journey saved!');
// Redirect to read view
window.location.href = `blog-post.html?id=${data.id}`;
} catch (err) {
console.error('Error saving journey:', err);
showToast('Error saving journey: ' + err.message, true);
}
}
// ==================== ADD MARKER ====================
function addMarker() {
console.log('Adding new marker');
markersData.push({
lat: 46.8182,
lng: 8.2275,
title: 'New Chapter',
date: '',
description: '',
image: '',
videoUrl: ''
});
renderMarkers();
}
// ==================== INITIALIZATION ====================
document.addEventListener('DOMContentLoaded', async () => {
const authenticated = await checkAuthAndRedirect();
if (!authenticated) return;
updateUserMenu();
if (!isNew && journeyId) {
loadJourney(journeyId);
} else if (isNew) {
currentJourneyId = null;
document.getElementById('form-title').textContent = 'New Journey';
markersData = [];
renderMarkers();
} else {
window.location.href = 'blog-list.html';
}
document.getElementById('journey-form').addEventListener('submit', saveJourney);
document.getElementById('add-marker').addEventListener('click', addMarker);
});
</script>
</body>
</html>

View File

@ -1009,41 +1009,33 @@
activeMarker = null;
}
function saveMarker() {
async function saveMarker() {
if (!activeMarker) return;
const title =
document.getElementById("marker-title").value ||
"Untitled";
const title = document.getElementById("marker-title").value || "Untitled";
const date = document.getElementById("marker-date").value;
const description =
document.getElementById("marker-text").value;
const description = document.getElementById("marker-text").value;
const videoUrl = document.getElementById("video-url").value;
activeMarker.setTitle(title);
// Update marker's tooltip title and popup
activeMarker.options.title = title;
activeMarker.setPopupContent(`<strong>${title}</strong>`);
activeMarker._content = {
title,
date,
description,
videoUrl,
};
// Store content for saving
activeMarker._content = { title, date, description, videoUrl };
// Update the list item in the sidebar
const latlng = activeMarker.getLatLng();
const items = document.querySelectorAll(
"#current-markers-container .marker-item",
);
const items = document.querySelectorAll("#current-markers-container .marker-item");
for (let item of items) {
if (
item.dataset.lat == latlng.lat &&
item.dataset.lng == latlng.lng
) {
item.querySelector(".marker-title").textContent =
title;
if (item.dataset.lat == latlng.lat && item.dataset.lng == latlng.lng) {
item.querySelector(".marker-title").textContent = title;
break;
}
}
closeModal();
showToast("Marker updated");
showToast("Saving journey...");
await saveJourneyToAPI();
}
function deleteMarkerFromMap() {