fix: implement form-based coordinate sync for single mode map
All checks were successful
Deploy / Build and Deploy to Production (push) Successful in 19s
All checks were successful
Deploy / Build and Deploy to Production (push) Successful in 19s
Fixed marker display and centering in single mode (marker pages) by
changing from props-based to form-based coordinate synchronization.
Issues Fixed:
- Kirby blueprint query syntax {{ page.field }} passed literal strings
instead of values to component props
- Invalid coordinates (NaN, NaN) caused map initialization errors
- Marker not displaying in marker page position tab
- Map not centering on marker location
Solution:
- Remove latitude/longitude props from marker.yml blueprint
- Read coordinates directly from Panel form fields via DOM
- Add event listeners to sync form changes with map
- Bidirectional sync: drag marker → updates form fields
- Robust coordinate validation (check for NaN, null, 0)
Changes:
- MapEditor.vue: Add form field reading and event listeners
- MapEditor.vue: Replace props-based coords with reactive refs
- MapEditor.vue: Update marker drag handler to modify form inputs
- marker.yml: Remove non-functional query string props
- routes.php: Use data() instead of body() for all routes
Single Mode Flow:
1. Component reads latitude/longitude from form inputs on mount
2. Creates marker and centers map on valid coordinates
3. Form changes → updates marker position
4. Marker drag → updates form fields (triggers save on user action)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
32e8301d91
commit
cc44a68e66
3 changed files with 125 additions and 103 deletions
|
|
@ -58,6 +58,4 @@ tabs:
|
||||||
label: Position sur la carte
|
label: Position sur la carte
|
||||||
type: map-editor
|
type: map-editor
|
||||||
mode: single
|
mode: single
|
||||||
latitude: "{{ page.latitude }}"
|
|
||||||
longitude: "{{ page.longitude }}"
|
|
||||||
help: Déplacez le marqueur ou recherchez une adresse
|
help: Déplacez le marqueur ou recherchez une adresse
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -128,14 +128,15 @@ export default {
|
||||||
// Computed: markers based on mode
|
// Computed: markers based on mode
|
||||||
const markers = computed(() => {
|
const markers = computed(() => {
|
||||||
if (props.mode === 'single') {
|
if (props.mode === 'single') {
|
||||||
// Single mode: create one marker from props
|
// Single mode: create one marker from form values
|
||||||
if (props.latitude !== null && props.longitude !== null) {
|
const lat = singleLat.value;
|
||||||
|
const lon = singleLon.value;
|
||||||
|
|
||||||
|
// Only create marker if we have valid coordinates
|
||||||
|
if (!isNaN(lat) && !isNaN(lon) && lat !== null && lon !== null && lat !== 0 && lon !== 0) {
|
||||||
return [{
|
return [{
|
||||||
id: 'single-marker',
|
id: 'single-marker',
|
||||||
position: {
|
position: { lat, lon },
|
||||||
lat: parseFloat(props.latitude),
|
|
||||||
lon: parseFloat(props.longitude),
|
|
||||||
},
|
|
||||||
title: 'Current position',
|
title: 'Current position',
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
@ -149,6 +150,25 @@ export default {
|
||||||
return markers.value.length < props.maxMarkers;
|
return markers.value.length < props.maxMarkers;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Single mode: reactive references for coordinates from form fields
|
||||||
|
const singleLat = ref(null);
|
||||||
|
const singleLon = ref(null);
|
||||||
|
|
||||||
|
// Function to get coordinates from Panel form fields (single mode)
|
||||||
|
function getCoordinatesFromForm() {
|
||||||
|
// Find the latitude and longitude input fields in the same form
|
||||||
|
const form = document.querySelector('.k-form');
|
||||||
|
if (!form) return { lat: null, lon: null };
|
||||||
|
|
||||||
|
const latInput = form.querySelector('input[name*="latitude"]');
|
||||||
|
const lonInput = form.querySelector('input[name*="longitude"]');
|
||||||
|
|
||||||
|
return {
|
||||||
|
lat: latInput ? parseFloat(latInput.value) : null,
|
||||||
|
lon: lonInput ? parseFloat(lonInput.value) : null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Load data on mount
|
// Load data on mount
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
if (props.mode === 'multi') {
|
if (props.mode === 'multi') {
|
||||||
|
|
@ -159,12 +179,25 @@ export default {
|
||||||
console.error('Failed to load markers:', error);
|
console.error('Failed to load markers:', error);
|
||||||
}
|
}
|
||||||
} else if (props.mode === 'single') {
|
} else if (props.mode === 'single') {
|
||||||
// Single mode: center on marker position
|
// Single mode: get coordinates from form
|
||||||
if (props.latitude !== null && props.longitude !== null) {
|
const coords = getCoordinatesFromForm();
|
||||||
center.value = {
|
singleLat.value = coords.lat;
|
||||||
lat: parseFloat(props.latitude),
|
singleLon.value = coords.lon;
|
||||||
lon: parseFloat(props.longitude),
|
|
||||||
};
|
if (!isNaN(coords.lat) && !isNaN(coords.lon) && coords.lat !== 0 && coords.lon !== 0) {
|
||||||
|
center.value = { lat: coords.lat, lon: coords.lon };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watch for changes in the form fields
|
||||||
|
const form = document.querySelector('.k-form');
|
||||||
|
if (form) {
|
||||||
|
form.addEventListener('input', (e) => {
|
||||||
|
if (e.target.name && (e.target.name.includes('latitude') || e.target.name.includes('longitude'))) {
|
||||||
|
const newCoords = getCoordinatesFromForm();
|
||||||
|
singleLat.value = newCoords.lat;
|
||||||
|
singleLon.value = newCoords.lon;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -188,14 +221,16 @@ export default {
|
||||||
{ deep: true }
|
{ deep: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
// Watch latitude/longitude props in single mode
|
// Watch form coordinates in single mode
|
||||||
watch(
|
watch(
|
||||||
() => [props.latitude, props.longitude],
|
() => [singleLat.value, singleLon.value],
|
||||||
([newLat, newLon]) => {
|
([lat, lon]) => {
|
||||||
if (props.mode === 'single' && newLat !== null && newLon !== null) {
|
if (props.mode === 'single') {
|
||||||
// Center map on new position
|
// Center map on new position if valid
|
||||||
|
if (!isNaN(lat) && !isNaN(lon) && lat !== null && lon !== null && lat !== 0 && lon !== 0) {
|
||||||
if (mapPreview.value && mapPreview.value.centerOnPosition) {
|
if (mapPreview.value && mapPreview.value.centerOnPosition) {
|
||||||
mapPreview.value.centerOnPosition(parseFloat(newLat), parseFloat(newLon));
|
mapPreview.value.centerOnPosition(lat, lon);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -267,34 +302,23 @@ export default {
|
||||||
*/
|
*/
|
||||||
async function handleMarkerMoved({ markerId, position }) {
|
async function handleMarkerMoved({ markerId, position }) {
|
||||||
if (props.mode === 'single') {
|
if (props.mode === 'single') {
|
||||||
// Single mode: update current page's coordinates via API
|
// Single mode: update form fields directly
|
||||||
// Extract current page ID from window location
|
const form = document.querySelector('.k-form');
|
||||||
const match = window.location.pathname.match(/\/panel\/pages\/(.+)/);
|
if (form) {
|
||||||
if (match) {
|
const latInput = form.querySelector('input[name*="latitude"]');
|
||||||
const currentPageId = match[1];
|
const lonInput = form.querySelector('input[name*="longitude"]');
|
||||||
try {
|
|
||||||
const csrfToken = document.querySelector('meta[name="csrf"]')?.content || '';
|
|
||||||
const response = await fetch(`/api/map-editor/pages/${currentPageId}/position`, {
|
|
||||||
method: 'PATCH',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'X-CSRF': csrfToken
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
latitude: position.lat,
|
|
||||||
longitude: position.lng
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
if (latInput && lonInput) {
|
||||||
throw new Error('Failed to update position');
|
latInput.value = position.lat;
|
||||||
}
|
lonInput.value = position.lng;
|
||||||
|
|
||||||
// Reload the panel form to reflect updated values
|
// Trigger input event to update Vue/Kirby state
|
||||||
// This is a simple approach - Panel will refresh the form data
|
latInput.dispatchEvent(new Event('input', { bubbles: true }));
|
||||||
console.log('Position updated successfully');
|
lonInput.dispatchEvent(new Event('input', { bubbles: true }));
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to update position:', error);
|
// Update local refs
|
||||||
|
singleLat.value = position.lat;
|
||||||
|
singleLon.value = position.lng;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue