maplibre-preview 1.9.0 → 1.9.1
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 +5 -0
- data/lib/maplibre-preview/version.rb +1 -1
- data/lib/maplibre-preview/views/maplibre_map.slim +29 -10
- data/spec/maplibre_preview_spec.rb +10 -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: 4804849d0779e4a60b497a251fa9ad350615671a328d446b383c991b6fda041a
|
|
4
|
+
data.tar.gz: 3349b9e73f70f57d3dd83d3c3586c44a5180ec9cc5d93d5932e4b246f82a1003
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c8e02627ba370010afa83daf7e0d2770d6d0ea3dc919761b976789cbcc9f60f88735196c1546c50467e2eca8b468fe0212160b6dd20b88c0982b5787a4313a92
|
|
7
|
+
data.tar.gz: 823cfad1bf6bb3d5f2602d4a592654189b40fb7d594430409bf3d8610827e04069867901a5044abf9408049b29698b2bcd7fa72ff6f36e3e8be8db83e48a6a19
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.9.1] - 2026-05-15
|
|
4
|
+
|
|
5
|
+
### Security
|
|
6
|
+
- **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
|
|
7
|
+
|
|
3
8
|
## [1.9.0] - 2026-05-14
|
|
4
9
|
|
|
5
10
|
### Added
|
|
@@ -774,20 +774,39 @@ 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);
|
|
791
810
|
};
|
|
792
811
|
|
|
793
812
|
const initializeMap = async () => {
|
|
@@ -81,6 +81,16 @@ RSpec.describe MapLibrePreview do
|
|
|
81
81
|
expect(last_response.body).to include('window.toggleStyleParametersPanel')
|
|
82
82
|
end
|
|
83
83
|
|
|
84
|
+
it 'renders feature popup tooltips as DOM text instead of raw HTML' do
|
|
85
|
+
get '/?style_url=https://example.com/style.json'
|
|
86
|
+
expect(last_response).to be_ok
|
|
87
|
+
|
|
88
|
+
expect(last_response.body).to include('createPopupContent')
|
|
89
|
+
expect(last_response.body).to include('item.textContent = tooltip')
|
|
90
|
+
expect(last_response.body).to include('setDOMContent(createPopupContent(tooltips))')
|
|
91
|
+
expect(last_response.body).not_to include('setHTML(tooltips')
|
|
92
|
+
end
|
|
93
|
+
|
|
84
94
|
it 'serves all required JavaScript modules' do
|
|
85
95
|
%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
96
|
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.9.
|
|
4
|
+
version: 1.9.1
|
|
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-15 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rack
|