diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ee2e233..25df552a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - [Updated SQL parser](https://github.com/sqlparser-rs/sqlparser-rs/blob/main/CHANGELOG.md#0470-2024-06-01). Fixes support for `AT TIME ZONE` in postgres. Fixes `GROUP_CONCAT()` in MySQL. - Add a new warning message in the logs when trying to use `SET $x = ` when there is already a form field named `x`. - **Empty Uploaded files**: when a form contains an optional file upload field, and the user does not upload a file, the field used to still be accessible to SQLPage file-related functions such as `sqlpage.uploaded_file_path` and `sqlpage.uploaded_file_mime_type`. This is now fixed, and these functions will return `NULL` when the user does not upload a file. `sqlpage.persist_uploaded_file` will not create an empty file in the target directory when the user does not upload a file, instead it will do nothing and return `NULL`. + - In the [map](https://sql.ophir.dev/documentation.sql?component=map#component) component, when top-level latitude and longitude attributes are omitted, the map will now center on its markers. This makes it easier to create zoomed maps with a single marker. ## 0.22.0 (2024-05-29) - **Important Security Fix:** The behavior of `SET $x` has been modified to match `SELECT $x`. diff --git a/examples/official-site/sqlpage/migrations/10_map.sql b/examples/official-site/sqlpage/migrations/10_map.sql index 3321b7c8..0d31f0e9 100644 --- a/examples/official-site/sqlpage/migrations/10_map.sql +++ b/examples/official-site/sqlpage/migrations/10_map.sql @@ -17,7 +17,7 @@ INSERT INTO parameter ( VALUES ( 'map', 'latitude', - 'Latitude of the center of the map.', + 'Latitude of the center of the map. If omitted, the map will be centered on its markers.', 'REAL', TRUE, TRUE diff --git a/sqlpage/sqlpage.js b/sqlpage/sqlpage.js index fe0403c8..6ede40ef 100644 --- a/sqlpage/sqlpage.js +++ b/sqlpage/sqlpage.js @@ -76,6 +76,9 @@ function sqlpage_map() { if (first_map && is_leaflet_loaded) { onLeafletLoad(); } + function parseCoords(coords) { + return coords && coords.split(",").map(c => parseFloat(c)); + } function onLeafletLoad() { is_leaflet_loaded = true; const maps = document.querySelectorAll("[data-pre-init=map]"); @@ -83,13 +86,19 @@ function sqlpage_map() { const tile_source = m.dataset.tile_source; const maxZoom = +m.dataset.max_zoom; const attribution = m.dataset.attribution; - const center = m.dataset.center.split(",").map(c => parseFloat(c)); const map = L.map(m, { attributionControl: !!attribution }); - map.setView(center, +m.dataset.zoom); + const zoom = m.dataset.zoom; + let center = parseCoords(m.dataset.center); L.tileLayer(tile_source, { attribution, maxZoom }).addTo(map); + const bounds = []; for (const marker_elem of m.getElementsByClassName("marker")) { + bounds.push(parseCoords(marker_elem.dataset.coords)); setTimeout(addMarker, 0, marker_elem, map); } + if (center == null) { + map.fitBounds(bounds); + if (zoom != null) map.setZoom(+zoom); + } else map.setView(center, +zoom); m.removeAttribute("data-pre-init"); } } @@ -107,7 +116,7 @@ function sqlpage_map() { else if (marker_elem.dataset.link) marker.on('click', () => window.location = marker_elem.dataset.link); } function createMarker(marker_elem, options) { - const coords = marker_elem.dataset.coords.split(",").map(c => parseFloat(c)); + const coords = parseCoords(marker_elem.dataset.coords); const icon_obj = marker_elem.getElementsByClassName("mapicon")[0]; if (icon_obj) { const size = 1.5 * +(options.size || icon_obj.firstChild?.getAttribute('width') || 24); diff --git a/sqlpage/templates/map.handlebars b/sqlpage/templates/map.handlebars index 73c49a84..5f6638a1 100644 --- a/sqlpage/templates/map.handlebars +++ b/sqlpage/templates/map.handlebars @@ -4,7 +4,7 @@