Closes the "no map view" gap for origin zones: the polygon was stored as coordinates and shown as raw JSON, so the shape could not be checked by eye. - vendor Leaflet 1.9.4 into apps/core/static/vendor/leaflet. Self-hosted rather than pulled from a CDN, because this renders supplier-location data. PROVENANCE.md records the version, source, licence (BSD-2-Clause), checksums and upgrade steps; the checksums match the SRI hashes Leaflet publishes - OriginZoneAdmin gains an "Area on a map" read-only row and its Media assets; apps/compliance/static/js/ixg_zone_map.js draws the polygon from the stored geometry, passed through a data attribute rather than injected into a script - the tile source is a setting (LEAFLET_TILE_URL), so moving to self-hosted tiles is a config change, not a code change Deliberately display only: it draws what is stored. It does not validate the geometry, and it does not verify the zone - both remain open work, and the page says so where the map appears. Tests cover the drawn map, a zone with no coordinates, and the add page.
68 lines
1.9 KiB
JavaScript
68 lines
1.9 KiB
JavaScript
/* Draw the stored origin-zone polygon on a Leaflet map.
|
|
*
|
|
* Display only: this renders what is already stored on the record. It does not
|
|
* validate the geometry, and it does not approve the zone. Validation and the
|
|
* two-step verification are separate pieces of work.
|
|
*
|
|
* The geometry is passed in a data-* attribute so the browser decodes it (no
|
|
* JSON injected into a script block).
|
|
*/
|
|
(function () {
|
|
"use strict";
|
|
|
|
var OSM_ATTRIBUTION =
|
|
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors';
|
|
|
|
function init() {
|
|
var el = document.getElementById("zone-map");
|
|
if (!el || typeof L === "undefined") {
|
|
return;
|
|
}
|
|
|
|
var geometry;
|
|
try {
|
|
geometry = JSON.parse(el.dataset.geometry || "null");
|
|
} catch (err) {
|
|
el.innerHTML =
|
|
'<p style="padding:1rem;color:#b91c1c">Stored geometry is not valid JSON, so it cannot be drawn.</p>';
|
|
return;
|
|
}
|
|
if (!geometry || !geometry.coordinates) {
|
|
return;
|
|
}
|
|
|
|
var map = L.map(el, { scrollWheelZoom: false });
|
|
|
|
if (el.dataset.tileUrl) {
|
|
L.tileLayer(el.dataset.tileUrl, {
|
|
maxZoom: 19,
|
|
attribution: OSM_ATTRIBUTION,
|
|
}).addTo(map);
|
|
}
|
|
|
|
var layer = L.geoJSON(geometry, {
|
|
style: { color: "#0f766e", weight: 2, fillColor: "#14b8a6", fillOpacity: 0.25 },
|
|
}).addTo(map);
|
|
|
|
var bounds = layer.getBounds();
|
|
if (bounds && bounds.isValid()) {
|
|
map.fitBounds(bounds.pad(0.25));
|
|
} else {
|
|
map.setView([0, 0], 2);
|
|
}
|
|
|
|
// Grappelli lays the form out after load; a stale size leaves grey tiles.
|
|
setTimeout(function () {
|
|
map.invalidateSize();
|
|
if (bounds && bounds.isValid()) {
|
|
map.fitBounds(bounds.pad(0.25));
|
|
}
|
|
}, 250);
|
|
}
|
|
|
|
if (document.readyState === "loading") {
|
|
document.addEventListener("DOMContentLoaded", init);
|
|
} else {
|
|
init();
|
|
}
|
|
})();
|