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
|
||||
type: map-editor
|
||||
mode: single
|
||||
latitude: "{{ page.latitude }}"
|
||||
longitude: "{{ page.longitude }}"
|
||||
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
|
||||
const markers = computed(() => {
|
||||
if (props.mode === 'single') {
|
||||
// Single mode: create one marker from props
|
||||
if (props.latitude !== null && props.longitude !== null) {
|
||||
// Single mode: create one marker from form values
|
||||
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 [{
|
||||
id: 'single-marker',
|
||||
position: {
|
||||
lat: parseFloat(props.latitude),
|
||||
lon: parseFloat(props.longitude),
|
||||
},
|
||||
position: { lat, lon },
|
||||
title: 'Current position',
|
||||
}];
|
||||
}
|
||||
|
|
@ -149,6 +150,25 @@ export default {
|
|||
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
|
||||
onMounted(async () => {
|
||||
if (props.mode === 'multi') {
|
||||
|
|
@ -159,12 +179,25 @@ export default {
|
|||
console.error('Failed to load markers:', error);
|
||||
}
|
||||
} else if (props.mode === 'single') {
|
||||
// Single mode: center on marker position
|
||||
if (props.latitude !== null && props.longitude !== null) {
|
||||
center.value = {
|
||||
lat: parseFloat(props.latitude),
|
||||
lon: parseFloat(props.longitude),
|
||||
};
|
||||
// Single mode: get coordinates from form
|
||||
const coords = getCoordinatesFromForm();
|
||||
singleLat.value = coords.lat;
|
||||
singleLon.value = coords.lon;
|
||||
|
||||
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 }
|
||||
);
|
||||
|
||||
// Watch latitude/longitude props in single mode
|
||||
// Watch form coordinates in single mode
|
||||
watch(
|
||||
() => [props.latitude, props.longitude],
|
||||
([newLat, newLon]) => {
|
||||
if (props.mode === 'single' && newLat !== null && newLon !== null) {
|
||||
// Center map on new position
|
||||
if (mapPreview.value && mapPreview.value.centerOnPosition) {
|
||||
mapPreview.value.centerOnPosition(parseFloat(newLat), parseFloat(newLon));
|
||||
() => [singleLat.value, singleLon.value],
|
||||
([lat, lon]) => {
|
||||
if (props.mode === 'single') {
|
||||
// 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) {
|
||||
mapPreview.value.centerOnPosition(lat, lon);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -267,34 +302,23 @@ export default {
|
|||
*/
|
||||
async function handleMarkerMoved({ markerId, position }) {
|
||||
if (props.mode === 'single') {
|
||||
// Single mode: update current page's coordinates via API
|
||||
// Extract current page ID from window location
|
||||
const match = window.location.pathname.match(/\/panel\/pages\/(.+)/);
|
||||
if (match) {
|
||||
const currentPageId = match[1];
|
||||
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
|
||||
})
|
||||
});
|
||||
// Single mode: update form fields directly
|
||||
const form = document.querySelector('.k-form');
|
||||
if (form) {
|
||||
const latInput = form.querySelector('input[name*="latitude"]');
|
||||
const lonInput = form.querySelector('input[name*="longitude"]');
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to update position');
|
||||
}
|
||||
if (latInput && lonInput) {
|
||||
latInput.value = position.lat;
|
||||
lonInput.value = position.lng;
|
||||
|
||||
// Reload the panel form to reflect updated values
|
||||
// This is a simple approach - Panel will refresh the form data
|
||||
console.log('Position updated successfully');
|
||||
} catch (error) {
|
||||
console.error('Failed to update position:', error);
|
||||
// Trigger input event to update Vue/Kirby state
|
||||
latInput.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
lonInput.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
|
||||
// Update local refs
|
||||
singleLat.value = position.lat;
|
||||
singleLon.value = position.lng;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue