feat: create new base template for public occupation authorization requests

This commit is contained in:
Karl Determe 2026-08-25 10:08:36 +02:00
parent c90ee9ece5
commit cb9e8a1c8b

View file

@ -219,9 +219,6 @@
<button type="button" id="poly-draw-btn" class="btn btn-sm btn-outline-success">
<i class="bi bi-pentagon"></i> {% translate "Dessiner un polygone" %}
</button>
<button type="button" id="poly-finish-btn" class="btn btn-sm btn-success d-none">
<i class="bi bi-check-circle"></i> {% translate "Terminer" %}
</button>
<button type="button" id="poly-clear-btn" class="btn btn-sm btn-outline-danger">
<i class="bi bi-x-circle"></i> {% translate "Effacer" %}
</button>
@ -478,52 +475,118 @@
if (!drawing) return;
addVertex(e.lngLat.lng, e.lngLat.lat);
});
map.on('dblclick', function (e) {
if (!drawing) return;
e.preventDefault();
handleDoubleClick();
});
}
function addVertex(lng, lat) {
vertices.push([lng, lat]);
const isFirst = markers.length === 0;
const el = document.createElement('div');
el.style.cssText = 'width:10px;height:10px;border-radius:50%;background:#0d6efd;border:2px solid #fff;box-shadow:0 0 3px rgba(0,0,0,.4);cursor:pointer;';
if (isFirst) {
el.className = 'poly-marker poly-marker-first';
el.style.cssText = 'width:14px;height:14px;border-radius:50%;background:#198754;border:2px solid #fff;box-shadow:0 0 4px rgba(0,0,0,.5);cursor:pointer;transition:transform 0.15s;';
el.title = '{% translate "Cliquer pour fermer le polygone" %}';
el.addEventListener('mouseenter', function () {
if (vertices.length >= 3) el.style.transform = 'scale(1.3)';
});
el.addEventListener('mouseleave', function () {
el.style.transform = 'scale(1)';
});
el.addEventListener('click', function (ev) {
ev.stopPropagation();
if (vertices.length >= 3) {
finishPolygon();
}
});
} else {
el.className = 'poly-marker';
el.style.cssText = 'width:10px;height:10px;border-radius:50%;background:#0d6efd;border:2px solid #fff;box-shadow:0 0 3px rgba(0,0,0,.4);cursor:default;';
}
const marker = new maplibregl.Marker({ element: el }).setLngLat([lng, lat]).addTo(map);
markers.push(marker);
// Clicking the first vertex closes the polygon
if (markers.length === 1) {
el.title = '{% translate "Cliquer pour fermer le polygone" %}';
el.addEventListener('click', function (ev) {
ev.stopPropagation();
finishPolygon();
});
}
renderPreview();
updateGeoJSON();
updateHint();
}
function handleDoubleClick() {
if (!drawing) return;
// In MapLibre, dblclick triggers two click events first.
// Remove the duplicated last vertex if close to the preceding one.
if (vertices.length >= 2) {
const last = vertices[vertices.length - 1];
const prev = vertices[vertices.length - 2];
if (Math.hypot(last[0] - prev[0], last[1] - prev[1]) < 0.0001) {
vertices.pop();
const lastMarker = markers.pop();
if (lastMarker) lastMarker.remove();
}
}
if (vertices.length >= 3) {
finishPolygon();
}
}
function updateGeoJSON() {
if (vertices.length >= 3) {
const coords = [vertices.concat([vertices[0]])];
const geojson = JSON.stringify({ type: 'Polygon', coordinates: coords });
document.getElementById('id_geom_geojson').value = geojson;
} else {
document.getElementById('id_geom_geojson').value = '';
}
}
function renderPreview() {
if (!map.getSource('poly-preview')) return;
const coords = vertices.length >= 3
? [vertices.concat([vertices[0]])]
: [];
const geojson = coords.length ? {
type: 'Feature',
geometry: { type: 'Polygon', coordinates: coords },
} : { type: 'FeatureCollection', features: [] };
map.getSource('poly-preview').setData(geojson);
if (vertices.length >= 3) {
const coords = [vertices.concat([vertices[0]])];
map.getSource('poly-preview').setData({
type: 'Feature',
geometry: { type: 'Polygon', coordinates: coords },
});
} else if (vertices.length === 2) {
map.getSource('poly-preview').setData({
type: 'Feature',
geometry: { type: 'LineString', coordinates: vertices },
});
} else {
map.getSource('poly-preview').setData({
type: 'FeatureCollection',
features: [],
});
}
}
function finishPolygon() {
if (vertices.length < 3) return;
drawing = false;
const geojson = JSON.stringify({ type: 'Polygon', coordinates: [vertices.concat([vertices[0]])] });
document.getElementById('id_geom_geojson').value = geojson;
renderPreview();
updateUI(false);
document.getElementById('poly-hint').textContent =
'{% translate "Polygone enregistré. Cliquez sur « Dessiner » pour le redessiner." %}';
map.getCanvas().style.cursor = 'default';
function updateHint() {
const hintEl = document.getElementById('poly-hint');
if (!hintEl) return;
if (!drawing) {
if (vertices.length >= 3 || document.getElementById('id_geom_geojson').value) {
hintEl.textContent = '{% translate "Polygone enregistré. Cliquez sur « Dessiner » pour le redessiner." %}';
} else {
hintEl.textContent = '{% translate "Cliquez sur « Dessiner un polygone » puis cliquez sur la carte pour ajouter des sommets. Cliquez sur le premier sommet pour fermer le polygone." %}';
}
return;
}
if (vertices.length <= 1) {
hintEl.textContent = '{% translate "Cliquez sur la carte pour ajouter des sommets." %}';
} else {
hintEl.textContent = '{% translate "Cliquez sur la carte pour ajouter des sommets. Cliquez sur le premier sommet pour fermer le polygone." %}';
}
}
function clearPolygon() {
drawing = false;
function startDrawing() {
drawing = true;
vertices = [];
markers.forEach(m => m.remove());
markers = [];
@ -531,35 +594,45 @@
if (map.getSource('poly-preview')) {
map.getSource('poly-preview').setData({ type: 'FeatureCollection', features: [] });
}
updateUI(false);
document.getElementById('poly-hint').textContent =
'{% translate "Cliquez sur « Dessiner un polygone » puis cliquez sur la carte pour ajouter des sommets." %}';
map.getCanvas().style.cursor = 'default';
map.doubleClickZoom.disable();
map.getCanvas().style.cursor = 'crosshair';
document.getElementById('poly-draw-btn').classList.add('active');
updateHint();
}
function updateUI(isDrawing) {
document.getElementById('poly-draw-btn').classList.toggle('d-none', isDrawing);
document.getElementById('poly-finish-btn').classList.toggle('d-none', !isDrawing);
map.getCanvas().style.cursor = isDrawing ? 'crosshair' : 'default';
function finishPolygon() {
if (vertices.length < 3) return;
drawing = false;
map.doubleClickZoom.enable();
map.getCanvas().style.cursor = 'default';
updateGeoJSON();
renderPreview();
document.getElementById('poly-draw-btn').classList.remove('active');
updateHint();
}
function clearPolygon() {
drawing = false;
map.doubleClickZoom.enable();
map.getCanvas().style.cursor = 'default';
vertices = [];
markers.forEach(m => m.remove());
markers = [];
document.getElementById('id_geom_geojson').value = '';
if (map.getSource('poly-preview')) {
map.getSource('poly-preview').setData({ type: 'FeatureCollection', features: [] });
}
document.getElementById('poly-draw-btn').classList.remove('active');
updateHint();
}
document.addEventListener('DOMContentLoaded', function () {
initMap();
document.getElementById('poly-draw-btn').addEventListener('click', function () {
drawing = true;
vertices = [];
markers.forEach(m => m.remove());
markers = [];
if (map.getSource('poly-preview')) {
map.getSource('poly-preview').setData({ type: 'FeatureCollection', features: [] });
}
updateUI(true);
document.getElementById('poly-hint').textContent =
'{% translate "Cliquez sur la carte pour ajouter des sommets. Cliquez sur le premier sommet pour fermer le polygone." %}';
startDrawing();
});
document.getElementById('poly-finish-btn').addEventListener('click', finishPolygon);
document.getElementById('poly-clear-btn').addEventListener('click', clearPolygon);
// -----------------------------------------------------------------------