Skip to content

Commit f2ec195

Browse files
hansthenConengmo
andauthored
Issue 1943 allow jscode in options (#2029)
* First version * Fix trailing commas * Fix typing for GeoJson kwargs * Update folium/utilities.py Co-authored-by: Frank Anema <33519926+Conengmo@users.noreply.github.com> * Update tests/plugins/test_grouped_layer_control.py Co-authored-by: Frank Anema <33519926+Conengmo@users.noreply.github.com> * Update tests/plugins/test_marker_cluster.py Co-authored-by: Frank Anema <33519926+Conengmo@users.noreply.github.com> * Update tests/test_folium.py Co-authored-by: Frank Anema <33519926+Conengmo@users.noreply.github.com> * Update tests/test_raster_layers.py Co-authored-by: Frank Anema <33519926+Conengmo@users.noreply.github.com> --------- Co-authored-by: Frank Anema <33519926+Conengmo@users.noreply.github.com>
1 parent 2a2da39 commit f2ec195

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+213
-313
lines changed

folium/elements.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
from typing import List, Tuple
22

33
from branca.element import CssLink, Element, Figure, JavascriptLink, MacroElement
4-
from jinja2 import Template
54

5+
from folium.template import Template
66
from folium.utilities import JsCode
77

88

folium/features.py

+14-18
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,23 @@
1414
from branca.colormap import ColorMap, LinearColormap, StepColormap
1515
from branca.element import Element, Figure, Html, IFrame, JavascriptLink, MacroElement
1616
from branca.utilities import color_brewer
17-
from jinja2 import Template
1817

1918
from folium.elements import JSCSSMixin
2019
from folium.folium import Map
2120
from folium.map import FeatureGroup, Icon, Layer, Marker, Popup, Tooltip
21+
from folium.template import Template
2222
from folium.utilities import (
2323
TypeJsonValue,
2424
TypeLine,
2525
TypePathOptions,
2626
_parse_size,
27-
camelize,
2827
escape_backticks,
2928
get_bounds,
3029
get_obj_in_upper_tree,
3130
image_to_url,
3231
javascript_identifier_path_to_array_notation,
3332
none_max,
3433
none_min,
35-
parse_options,
3634
validate_locations,
3735
)
3836
from folium.vector_layers import Circle, CircleMarker, PolyLine, path_options
@@ -68,7 +66,7 @@ class RegularPolygonMarker(JSCSSMixin, Marker):
6866
{% macro script(this, kwargs) %}
6967
var {{ this.get_name() }} = new L.RegularPolygonMarker(
7068
{{ this.location|tojson }},
71-
{{ this.options|tojson }}
69+
{{ this.options|tojavascript }}
7270
).addTo({{ this._parent.get_name() }});
7371
{% endmacro %}
7472
"""
@@ -95,7 +93,7 @@ def __init__(
9593
self._name = "RegularPolygonMarker"
9694
self.options = path_options(line=False, radius=radius, **kwargs)
9795
self.options.update(
98-
parse_options(
96+
dict(
9997
number_of_sides=number_of_sides,
10098
rotation=rotation,
10199
)
@@ -627,9 +625,7 @@ class GeoJson(Layer):
627625
{%- if this.marker %}
628626
pointToLayer: {{ this.get_name() }}_pointToLayer,
629627
{%- endif %}
630-
{%- for key, value in this.options.items() %}
631-
{{ key }}: {{ value|tojson }},
632-
{%- endfor %}
628+
...{{this.options | tojavascript }}
633629
});
634630
635631
function {{ this.get_name() }}_add (data) {
@@ -667,7 +663,7 @@ def __init__(
667663
popup: Optional["GeoJsonPopup"] = None,
668664
zoom_on_click: bool = False,
669665
marker: Union[Circle, CircleMarker, Marker, None] = None,
670-
**kwargs: TypeJsonValue,
666+
**kwargs: Any,
671667
):
672668
super().__init__(name=name, overlay=overlay, control=control, show=show)
673669
self._name = "GeoJson"
@@ -692,7 +688,7 @@ def __init__(
692688
self.popup_keep_highlighted = popup_keep_highlighted
693689

694690
self.marker = marker
695-
self.options = parse_options(**kwargs)
691+
self.options = kwargs
696692

697693
self.data = self.process_data(data)
698694

@@ -1267,7 +1263,7 @@ class GeoJsonTooltip(GeoJsonDetail):
12671263
{% macro script(this, kwargs) %}
12681264
{{ this._parent.get_name() }}.bindTooltip("""
12691265
+ GeoJsonDetail.base_template
1270-
+ """,{{ this.tooltip_options | tojson | safe }});
1266+
+ """,{{ this.tooltip_options | tojavascript }});
12711267
{% endmacro %}
12721268
"""
12731269
)
@@ -1293,7 +1289,7 @@ def __init__(
12931289
)
12941290
self._name = "GeoJsonTooltip"
12951291
kwargs.update({"sticky": sticky, "class_name": class_name})
1296-
self.tooltip_options = {camelize(key): kwargs[key] for key in kwargs.keys()}
1292+
self.tooltip_options = kwargs
12971293

12981294

12991295
class GeoJsonPopup(GeoJsonDetail):
@@ -1335,7 +1331,7 @@ class GeoJsonPopup(GeoJsonDetail):
13351331
{% macro script(this, kwargs) %}
13361332
{{ this._parent.get_name() }}.bindPopup("""
13371333
+ GeoJsonDetail.base_template
1338-
+ """,{{ this.popup_options | tojson | safe }});
1334+
+ """,{{ this.popup_options | tojavascript }});
13391335
{% endmacro %}
13401336
"""
13411337
)
@@ -1360,7 +1356,7 @@ def __init__(
13601356
)
13611357
self._name = "GeoJsonPopup"
13621358
kwargs.update({"class_name": self.class_name})
1363-
self.popup_options = {camelize(key): value for key, value in kwargs.items()}
1359+
self.popup_options = kwargs
13641360

13651361

13661362
class Choropleth(FeatureGroup):
@@ -1703,7 +1699,7 @@ class DivIcon(MacroElement):
17031699
_template = Template(
17041700
"""
17051701
{% macro script(this, kwargs) %}
1706-
var {{ this.get_name() }} = L.divIcon({{ this.options|tojson }});
1702+
var {{ this.get_name() }} = L.divIcon({{ this.options|tojavascript }});
17071703
{{this._parent.get_name()}}.setIcon({{this.get_name()}});
17081704
{% endmacro %}
17091705
"""
@@ -1719,7 +1715,7 @@ def __init__(
17191715
):
17201716
super().__init__()
17211717
self._name = "DivIcon"
1722-
self.options = parse_options(
1718+
self.options = dict(
17231719
html=html,
17241720
icon_size=icon_size,
17251721
icon_anchor=icon_anchor,
@@ -1880,7 +1876,7 @@ class CustomIcon(Icon):
18801876
_template = Template(
18811877
"""
18821878
{% macro script(this, kwargs) %}
1883-
var {{ this.get_name() }} = L.icon({{ this.options|tojson }});
1879+
var {{ this.get_name() }} = L.icon({{ this.options|tojavascript }});
18841880
{{ this._parent.get_name() }}.setIcon({{ this.get_name() }});
18851881
{% endmacro %}
18861882
"""
@@ -1898,7 +1894,7 @@ def __init__(
18981894
):
18991895
super(Icon, self).__init__()
19001896
self._name = "CustomIcon"
1901-
self.options = parse_options(
1897+
self.options = dict(
19021898
icon_url=image_to_url(icon_image),
19031899
icon_size=icon_size,
19041900
icon_anchor=icon_anchor,

folium/folium.py

+4-6
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,16 @@
88
from typing import Any, List, Optional, Sequence, Union
99

1010
from branca.element import Element, Figure
11-
from jinja2 import Template
1211

1312
from folium.elements import JSCSSMixin
1413
from folium.map import Evented, FitBounds, Layer
1514
from folium.raster_layers import TileLayer
15+
from folium.template import Template
1616
from folium.utilities import (
1717
TypeBounds,
1818
TypeJsonValue,
1919
_parse_size,
2020
parse_font_size,
21-
parse_options,
2221
temp_html_filepath,
2322
validate_location,
2423
)
@@ -204,9 +203,8 @@ class Map(JSCSSMixin, Evented):
204203
{
205204
center: {{ this.location|tojson }},
206205
crs: L.CRS.{{ this.crs }},
207-
{%- for key, value in this.options.items() %}
208-
{{ key }}: {{ value|tojson }},
209-
{%- endfor %}
206+
...{{this.options|tojavascript}}
207+
210208
}
211209
);
212210
@@ -305,7 +303,7 @@ def __init__(
305303
else:
306304
self.zoom_control_position = False
307305

308-
self.options = parse_options(
306+
self.options = dict(
309307
max_bounds=max_bounds_array,
310308
zoom=zoom_start,
311309
zoom_control=False if self.zoom_control_position else zoom_control,

folium/map.py

+16-45
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,16 @@
55

66
import warnings
77
from collections import OrderedDict
8-
from typing import Dict, List, Optional, Sequence, Tuple, Type, Union
8+
from typing import List, Optional, Sequence, Union
99

1010
from branca.element import Element, Figure, Html, MacroElement
11-
from jinja2 import Template
1211

1312
from folium.elements import ElementAddToElement, EventHandler
13+
from folium.template import Template
1414
from folium.utilities import (
1515
JsCode,
1616
TypeBounds,
1717
TypeJsonValue,
18-
camelize,
1918
escape_backticks,
2019
parse_options,
2120
validate_location,
@@ -109,7 +108,7 @@ class FeatureGroup(Layer):
109108
"""
110109
{% macro script(this, kwargs) %}
111110
var {{ this.get_name() }} = L.featureGroup(
112-
{{ this.options|tojson }}
111+
{{ this.options|tojavascript }}
113112
);
114113
{% endmacro %}
115114
"""
@@ -126,7 +125,7 @@ def __init__(
126125
super().__init__(name=name, overlay=overlay, control=control, show=show)
127126
self._name = "FeatureGroup"
128127
self.tile_name = name if name is not None else self.get_name()
129-
self.options = parse_options(**kwargs)
128+
self.options = kwargs
130129

131130

132131
class LayerControl(MacroElement):
@@ -180,7 +179,7 @@ class LayerControl(MacroElement):
180179
let {{ this.get_name() }} = L.control.layers(
181180
{{ this.get_name() }}_layers.base_layers,
182181
{{ this.get_name() }}_layers.overlays,
183-
{{ this.options|tojson }}
182+
{{ this.options|tojavascript }}
184183
).addTo({{this._parent.get_name()}});
185184
186185
{%- if this.draggable %}
@@ -201,7 +200,7 @@ def __init__(
201200
):
202201
super().__init__()
203202
self._name = "LayerControl"
204-
self.options = parse_options(
203+
self.options = dict(
205204
position=position, collapsed=collapsed, autoZIndex=autoZIndex, **kwargs
206205
)
207206
self.draggable = draggable
@@ -263,7 +262,7 @@ class Icon(MacroElement):
263262
"""
264263
{% macro script(this, kwargs) %}
265264
var {{ this.get_name() }} = L.AwesomeMarkers.icon(
266-
{{ this.options|tojson }}
265+
{{ this.options|tojavascript }}
267266
);
268267
{{ this._parent.get_name() }}.setIcon({{ this.get_name() }});
269268
{% endmacro %}
@@ -307,7 +306,7 @@ def __init__(
307306
f"color argument of Icon should be one of: {self.color_options}.",
308307
stacklevel=2,
309308
)
310-
self.options = parse_options(
309+
self.options = dict(
311310
marker_color=color,
312311
icon_color=icon_color,
313312
icon=icon,
@@ -356,7 +355,7 @@ class Marker(MacroElement):
356355
{% macro script(this, kwargs) %}
357356
var {{ this.get_name() }} = L.marker(
358357
{{ this.location|tojson }},
359-
{{ this.options|tojson }}
358+
{{ this.options|tojavascript }}
360359
).addTo({{ this._parent.get_name() }});
361360
{% endmacro %}
362361
"""
@@ -374,7 +373,7 @@ def __init__(
374373
super().__init__()
375374
self._name = "Marker"
376375
self.location = validate_location(location) if location is not None else None
377-
self.options = parse_options(
376+
self.options = dict(
378377
draggable=draggable or None, autoPan=draggable or None, **kwargs
379378
)
380379
if icon is not None:
@@ -424,7 +423,7 @@ class Popup(Element):
424423

425424
_template = Template(
426425
"""
427-
var {{this.get_name()}} = L.popup({{ this.options|tojson }});
426+
var {{this.get_name()}} = L.popup({{ this.options|tojavascript }});
428427
429428
{% for name, element in this.html._children.items() %}
430429
{% if this.lazy %}
@@ -476,7 +475,7 @@ def __init__(
476475

477476
self.show = show
478477
self.lazy = lazy
479-
self.options = parse_options(
478+
self.options = dict(
480479
max_width=max_width,
481480
autoClose=False if show or sticky else None,
482481
closeOnClick=False if sticky else None,
@@ -526,22 +525,11 @@ class Tooltip(MacroElement):
526525
`<div{% if this.style %} style={{ this.style|tojson }}{% endif %}>
527526
{{ this.text }}
528527
</div>`,
529-
{{ this.options|tojson }}
528+
{{ this.options|tojavascript }}
530529
);
531530
{% endmacro %}
532531
"""
533532
)
534-
valid_options: Dict[str, Tuple[Type, ...]] = {
535-
"pane": (str,),
536-
"offset": (tuple,),
537-
"direction": (str,),
538-
"permanent": (bool,),
539-
"sticky": (bool,),
540-
"interactive": (bool,),
541-
"opacity": (float, int),
542-
"attribution": (str,),
543-
"className": (str,),
544-
}
545533

546534
def __init__(
547535
self,
@@ -556,7 +544,7 @@ def __init__(
556544
self.text = str(text)
557545

558546
kwargs.update({"sticky": sticky})
559-
self.options = self.parse_options(kwargs)
547+
self.options = kwargs
560548

561549
if style:
562550
assert isinstance(
@@ -565,23 +553,6 @@ def __init__(
565553
# noqa outside of type checking.
566554
self.style = style
567555

568-
def parse_options(
569-
self,
570-
kwargs: Dict[str, TypeJsonValue],
571-
) -> Dict[str, TypeJsonValue]:
572-
"""Validate the provided kwargs and return options as json string."""
573-
kwargs = {camelize(key): value for key, value in kwargs.items()}
574-
for key in kwargs.keys():
575-
assert (
576-
key in self.valid_options
577-
), "The option {} is not in the available options: {}.".format(
578-
key, ", ".join(self.valid_options)
579-
)
580-
assert isinstance(
581-
kwargs[key], self.valid_options[key]
582-
), f"The option {key} must be one of the following types: {self.valid_options[key]}."
583-
return kwargs
584-
585556

586557
class FitBounds(MacroElement):
587558
"""Fit the map to contain a bounding box with the
@@ -660,7 +631,7 @@ class FitOverlays(MacroElement):
660631
}
661632
});
662633
if (bounds.isValid()) {
663-
{{ this._parent.get_name() }}.{{ this.method }}(bounds, {{ this.options|tojson }});
634+
{{ this._parent.get_name() }}.{{ this.method }}(bounds, {{ this.options|tojavascript }});
664635
}
665636
}
666637
{{ this._parent.get_name() }}.on('overlayadd', customFlyToBounds);
@@ -682,7 +653,7 @@ def __init__(
682653
self._name = "FitOverlays"
683654
self.method = "flyToBounds" if fly else "fitBounds"
684655
self.fit_on_map_load = fit_on_map_load
685-
self.options = parse_options(padding=(padding, padding), max_zoom=max_zoom)
656+
self.options = dict(padding=(padding, padding), max_zoom=max_zoom)
686657

687658

688659
class CustomPane(MacroElement):

folium/plugins/antpath.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
from jinja2 import Template
2-
31
from folium.elements import JSCSSMixin
2+
from folium.template import Template
43
from folium.vector_layers import BaseMultiLocation, path_options
54

65

@@ -31,7 +30,7 @@ class AntPath(JSCSSMixin, BaseMultiLocation):
3130
{% macro script(this, kwargs) %}
3231
{{ this.get_name() }} = L.polyline.antPath(
3332
{{ this.locations|tojson }},
34-
{{ this.options|tojson }}
33+
{{ this.options|tojavascript }}
3534
).addTo({{this._parent.get_name()}});
3635
{% endmacro %}
3736
"""

0 commit comments

Comments
 (0)