maplibre-preview 1.9.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/lib/maplibre-preview/version.rb +1 -1
- data/lib/maplibre-preview/views/maplibre_map.slim +42 -10
- data/lib/maplibre-preview.rb +1 -1
- data/spec/maplibre_preview_spec.rb +19 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d77238823bad1c9b83f993dab458e964ffd16fb6015f3506bbd62d86b690e131
|
|
4
|
+
data.tar.gz: 70b749547c4d2115fc20a0bde6c43ceb3303ddf1b22a1fc4a570e1ae12117552
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0e64e1a5d7e2334ad705a18ccca590143d33c1c562094a0fb216aa2502b4b2666736633404e08d1233f5d260d978c7e8006a4f96e02122303199a066f2a8b20e
|
|
7
|
+
data.tar.gz: 51dbf7525797540e8de7ba77400d4d062bfb8cf2a6bbb1248b7c8e8b5027341825afe2654bc76bac64f5af6f6cc9e36b0d43b339534f6f7749b779a36c9867bd
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.10.0] - 2026-05-20
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- **Host coordinate selection** - emit `maplibre-preview:coordinate-selected` with `lat` and `lon` on map clicks for embedded host applications
|
|
7
|
+
|
|
8
|
+
### Changed
|
|
9
|
+
- **Embedded preview route** - pass configured preview options into the `/maplibre_preview` template route
|
|
10
|
+
|
|
11
|
+
## [1.9.1] - 2026-05-15
|
|
12
|
+
|
|
13
|
+
### Security
|
|
14
|
+
- **Feature popup tooltips** - render style and feature tooltip values as DOM text instead of raw HTML to prevent script execution from untrusted style or tile data
|
|
15
|
+
|
|
3
16
|
## [1.9.0] - 2026-05-14
|
|
4
17
|
|
|
5
18
|
### Added
|
|
@@ -774,20 +774,50 @@ javascript:
|
|
|
774
774
|
return modifiedStyle;
|
|
775
775
|
};
|
|
776
776
|
|
|
777
|
-
const
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
777
|
+
const tooltipValue = (feat, prop) => {
|
|
778
|
+
let value = feat;
|
|
779
|
+
for (const p of prop.split('.')) {
|
|
780
|
+
value = value?.[p];
|
|
781
|
+
}
|
|
782
|
+
return typeof value === 'object' ? JSON.stringify(value, null, 2) : (value || '');
|
|
783
|
+
};
|
|
784
|
+
|
|
785
|
+
const tooltipText = (tooltip, feat) => tooltip?.replace(/\{([^}]+)\}/g, (match, prop) => tooltipValue(feat, prop));
|
|
786
|
+
|
|
787
|
+
const defaultTooltipText = (feat) => [
|
|
788
|
+
`"id": ${tooltipValue(feat, 'id')}`,
|
|
789
|
+
`"source": ${tooltipValue(feat, 'source')}`,
|
|
790
|
+
`"source-layer": ${tooltipValue(feat, 'sourceLayer')}`,
|
|
791
|
+
`"properties": ${tooltipValue(feat, 'properties')}`
|
|
792
|
+
].join('\n');
|
|
793
|
+
|
|
794
|
+
const createPopupContent = (tooltips) => {
|
|
795
|
+
const fragment = document.createDocumentFragment();
|
|
796
|
+
tooltips.forEach((tooltip, index) => {
|
|
797
|
+
if (index > 0) fragment.appendChild(document.createElement('br'));
|
|
798
|
+
const item = document.createElement('pre');
|
|
799
|
+
item.textContent = tooltip;
|
|
800
|
+
fragment.appendChild(item);
|
|
784
801
|
});
|
|
802
|
+
return fragment;
|
|
803
|
+
};
|
|
785
804
|
|
|
805
|
+
const popupFeature = (features, e, popup) => {
|
|
786
806
|
const tooltips = features.map((feat) =>
|
|
787
|
-
|
|
788
|
-
tt(`<pre>"id": {id},\n"source": {source},\n"source-layer": {sourceLayer},\n"properties": {properties}</pre>`, feat)
|
|
807
|
+
tooltipText(feat.layer.metadata?.tooltip, feat) || defaultTooltipText(feat)
|
|
789
808
|
);
|
|
790
|
-
popup.setLngLat(e.lngLat).
|
|
809
|
+
popup.setLngLat(e.lngLat).setDOMContent(createPopupContent(tooltips)).addTo(map);
|
|
810
|
+
};
|
|
811
|
+
|
|
812
|
+
const emitCoordinateSelection = (lngLat) => {
|
|
813
|
+
const payload = {
|
|
814
|
+
type: 'maplibre-preview:coordinate-selected',
|
|
815
|
+
lat: lngLat.lat,
|
|
816
|
+
lon: lngLat.lng
|
|
817
|
+
};
|
|
818
|
+
|
|
819
|
+
window.dispatchEvent(new CustomEvent(payload.type, {detail: payload}));
|
|
820
|
+
window.parent !== window && window.parent.postMessage(payload, window.location.origin);
|
|
791
821
|
};
|
|
792
822
|
|
|
793
823
|
const initializeMap = async () => {
|
|
@@ -899,6 +929,8 @@ javascript:
|
|
|
899
929
|
const popup = new maplibregl.Popup({closeButton: false, closeOnClick: false});
|
|
900
930
|
|
|
901
931
|
map.on('click', function (e) {
|
|
932
|
+
emitCoordinateSelection(e.lngLat);
|
|
933
|
+
|
|
902
934
|
if (profileMode) {
|
|
903
935
|
handleProfileClick(e);
|
|
904
936
|
return;
|
data/lib/maplibre-preview.rb
CHANGED
|
@@ -33,7 +33,7 @@ module MapLibrePreview
|
|
|
33
33
|
app.set :maplibre_preview_options, {}
|
|
34
34
|
|
|
35
35
|
app.get '/maplibre_preview' do
|
|
36
|
-
slim :maplibre_map, layout: :maplibre_layout
|
|
36
|
+
slim :maplibre_map, layout: :maplibre_layout, locals: { options: settings.maplibre_preview_options }
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
end
|
|
@@ -15,6 +15,7 @@ RSpec.describe MapLibrePreview do
|
|
|
15
15
|
expect(last_response.body).to include('maplibre-contour')
|
|
16
16
|
expect(last_response.body).to include('d3')
|
|
17
17
|
expect(last_response.body).to include('overlay_layout')
|
|
18
|
+
expect(last_response.body).to include('maplibre-preview:coordinate-selected')
|
|
18
19
|
end
|
|
19
20
|
|
|
20
21
|
it 'renders map cache toggle wiring' do
|
|
@@ -81,6 +82,24 @@ RSpec.describe MapLibrePreview do
|
|
|
81
82
|
expect(last_response.body).to include('window.toggleStyleParametersPanel')
|
|
82
83
|
end
|
|
83
84
|
|
|
85
|
+
it 'renders feature popup tooltips as DOM text instead of raw HTML' do
|
|
86
|
+
get '/?style_url=https://example.com/style.json'
|
|
87
|
+
expect(last_response).to be_ok
|
|
88
|
+
|
|
89
|
+
expect(last_response.body).to include('createPopupContent')
|
|
90
|
+
expect(last_response.body).to include('item.textContent = tooltip')
|
|
91
|
+
expect(last_response.body).to include('setDOMContent(createPopupContent(tooltips))')
|
|
92
|
+
expect(last_response.body).not_to include('setHTML(tooltips')
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
it 'emits selected coordinates for host applications' do
|
|
96
|
+
get '/'
|
|
97
|
+
expect(last_response).to be_ok
|
|
98
|
+
|
|
99
|
+
expect(last_response.body).to include('emitCoordinateSelection(e.lngLat)')
|
|
100
|
+
expect(last_response.body).to include('window.parent.postMessage(payload, window.location.origin)')
|
|
101
|
+
end
|
|
102
|
+
|
|
84
103
|
it 'serves all required JavaScript modules' do
|
|
85
104
|
%w[/js/overlay_layout.js /js/filters.js /js/contour.js /js/tilegrid.js /js/temporal_picker.js /vendor/maplibre-gl/maplibre-gl.js /vendor/maplibre-contour/index.min.js /vendor/d3/d3.v7.min.js].each do |js_file|
|
|
86
105
|
get js_file
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: maplibre-preview
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.10.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alexander Ludov
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-05-
|
|
11
|
+
date: 2026-05-20 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rack
|