Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 1943 allow jscode in options #2029

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion folium/elements.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from typing import List, Tuple

from branca.element import CssLink, Element, Figure, JavascriptLink, MacroElement
from jinja2 import Template

from folium.template import Template
from folium.utilities import JsCode


Expand Down
32 changes: 14 additions & 18 deletions folium/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,23 @@
from branca.colormap import ColorMap, LinearColormap, StepColormap
from branca.element import Element, Figure, Html, IFrame, JavascriptLink, MacroElement
from branca.utilities import color_brewer
from jinja2 import Template

from folium.elements import JSCSSMixin
from folium.folium import Map
from folium.map import FeatureGroup, Icon, Layer, Marker, Popup, Tooltip
from folium.template import Template
from folium.utilities import (
TypeJsonValue,
TypeLine,
TypePathOptions,
_parse_size,
camelize,
escape_backticks,
get_bounds,
get_obj_in_upper_tree,
image_to_url,
javascript_identifier_path_to_array_notation,
none_max,
none_min,
parse_options,
validate_locations,
)
from folium.vector_layers import Circle, CircleMarker, PolyLine, path_options
Expand Down Expand Up @@ -68,7 +66,7 @@ class RegularPolygonMarker(JSCSSMixin, Marker):
{% macro script(this, kwargs) %}
var {{ this.get_name() }} = new L.RegularPolygonMarker(
{{ this.location|tojson }},
{{ this.options|tojson }}
{{ this.options|tojavascript }}
).addTo({{ this._parent.get_name() }});
{% endmacro %}
"""
Expand All @@ -95,7 +93,7 @@ def __init__(
self._name = "RegularPolygonMarker"
self.options = path_options(line=False, radius=radius, **kwargs)
self.options.update(
parse_options(
dict(
number_of_sides=number_of_sides,
rotation=rotation,
)
Expand Down Expand Up @@ -627,9 +625,7 @@ class GeoJson(Layer):
{%- if this.marker %}
pointToLayer: {{ this.get_name() }}_pointToLayer,
{%- endif %}
{%- for key, value in this.options.items() %}
{{ key }}: {{ value|tojson }},
{%- endfor %}
...{{this.options | tojavascript }}
});

function {{ this.get_name() }}_add (data) {
Expand Down Expand Up @@ -667,7 +663,7 @@ def __init__(
popup: Optional["GeoJsonPopup"] = None,
zoom_on_click: bool = False,
marker: Union[Circle, CircleMarker, Marker, None] = None,
**kwargs: TypeJsonValue,
**kwargs: Any,
):
super().__init__(name=name, overlay=overlay, control=control, show=show)
self._name = "GeoJson"
Expand All @@ -692,7 +688,7 @@ def __init__(
self.popup_keep_highlighted = popup_keep_highlighted

self.marker = marker
self.options = parse_options(**kwargs)
self.options = kwargs

self.data = self.process_data(data)

Expand Down Expand Up @@ -1267,7 +1263,7 @@ class GeoJsonTooltip(GeoJsonDetail):
{% macro script(this, kwargs) %}
{{ this._parent.get_name() }}.bindTooltip("""
+ GeoJsonDetail.base_template
+ """,{{ this.tooltip_options | tojson | safe }});
+ """,{{ this.tooltip_options | tojavascript }});
{% endmacro %}
"""
)
Expand All @@ -1293,7 +1289,7 @@ def __init__(
)
self._name = "GeoJsonTooltip"
kwargs.update({"sticky": sticky, "class_name": class_name})
self.tooltip_options = {camelize(key): kwargs[key] for key in kwargs.keys()}
self.tooltip_options = kwargs


class GeoJsonPopup(GeoJsonDetail):
Expand Down Expand Up @@ -1335,7 +1331,7 @@ class GeoJsonPopup(GeoJsonDetail):
{% macro script(this, kwargs) %}
{{ this._parent.get_name() }}.bindPopup("""
+ GeoJsonDetail.base_template
+ """,{{ this.popup_options | tojson | safe }});
+ """,{{ this.popup_options | tojavascript }});
{% endmacro %}
"""
)
Expand All @@ -1360,7 +1356,7 @@ def __init__(
)
self._name = "GeoJsonPopup"
kwargs.update({"class_name": self.class_name})
self.popup_options = {camelize(key): value for key, value in kwargs.items()}
self.popup_options = kwargs


class Choropleth(FeatureGroup):
Expand Down Expand Up @@ -1703,7 +1699,7 @@ class DivIcon(MacroElement):
_template = Template(
"""
{% macro script(this, kwargs) %}
var {{ this.get_name() }} = L.divIcon({{ this.options|tojson }});
var {{ this.get_name() }} = L.divIcon({{ this.options|tojavascript }});
{{this._parent.get_name()}}.setIcon({{this.get_name()}});
{% endmacro %}
"""
Expand All @@ -1719,7 +1715,7 @@ def __init__(
):
super().__init__()
self._name = "DivIcon"
self.options = parse_options(
self.options = dict(
html=html,
icon_size=icon_size,
icon_anchor=icon_anchor,
Expand Down Expand Up @@ -1880,7 +1876,7 @@ class CustomIcon(Icon):
_template = Template(
"""
{% macro script(this, kwargs) %}
var {{ this.get_name() }} = L.icon({{ this.options|tojson }});
var {{ this.get_name() }} = L.icon({{ this.options|tojavascript }});
{{ this._parent.get_name() }}.setIcon({{ this.get_name() }});
{% endmacro %}
"""
Expand All @@ -1898,7 +1894,7 @@ def __init__(
):
super(Icon, self).__init__()
self._name = "CustomIcon"
self.options = parse_options(
self.options = dict(
icon_url=image_to_url(icon_image),
icon_size=icon_size,
icon_anchor=icon_anchor,
Expand Down
10 changes: 4 additions & 6 deletions folium/folium.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,16 @@
from typing import Any, List, Optional, Sequence, Union

from branca.element import Element, Figure
from jinja2 import Template

from folium.elements import JSCSSMixin
from folium.map import Evented, FitBounds, Layer
from folium.raster_layers import TileLayer
from folium.template import Template
from folium.utilities import (
TypeBounds,
TypeJsonValue,
_parse_size,
parse_font_size,
parse_options,
temp_html_filepath,
validate_location,
)
Expand Down Expand Up @@ -204,9 +203,8 @@ class Map(JSCSSMixin, Evented):
{
center: {{ this.location|tojson }},
crs: L.CRS.{{ this.crs }},
{%- for key, value in this.options.items() %}
{{ key }}: {{ value|tojson }},
{%- endfor %}
...{{this.options|tojavascript}}

}
);

Expand Down Expand Up @@ -305,7 +303,7 @@ def __init__(
else:
self.zoom_control_position = False

self.options = parse_options(
self.options = dict(
max_bounds=max_bounds_array,
zoom=zoom_start,
zoom_control=False if self.zoom_control_position else zoom_control,
Expand Down
61 changes: 16 additions & 45 deletions folium/map.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,16 @@

import warnings
from collections import OrderedDict
from typing import Dict, List, Optional, Sequence, Tuple, Type, Union
from typing import List, Optional, Sequence, Union

from branca.element import Element, Figure, Html, MacroElement
from jinja2 import Template

from folium.elements import ElementAddToElement, EventHandler
from folium.template import Template
from folium.utilities import (
JsCode,
TypeBounds,
TypeJsonValue,
camelize,
escape_backticks,
parse_options,
validate_location,
Expand Down Expand Up @@ -109,7 +108,7 @@ class FeatureGroup(Layer):
"""
{% macro script(this, kwargs) %}
var {{ this.get_name() }} = L.featureGroup(
{{ this.options|tojson }}
{{ this.options|tojavascript }}
);
{% endmacro %}
"""
Expand All @@ -126,7 +125,7 @@ def __init__(
super().__init__(name=name, overlay=overlay, control=control, show=show)
self._name = "FeatureGroup"
self.tile_name = name if name is not None else self.get_name()
self.options = parse_options(**kwargs)
self.options = kwargs


class LayerControl(MacroElement):
Expand Down Expand Up @@ -180,7 +179,7 @@ class LayerControl(MacroElement):
let {{ this.get_name() }} = L.control.layers(
{{ this.get_name() }}_layers.base_layers,
{{ this.get_name() }}_layers.overlays,
{{ this.options|tojson }}
{{ this.options|tojavascript }}
).addTo({{this._parent.get_name()}});

{%- if this.draggable %}
Expand All @@ -201,7 +200,7 @@ def __init__(
):
super().__init__()
self._name = "LayerControl"
self.options = parse_options(
self.options = dict(
position=position, collapsed=collapsed, autoZIndex=autoZIndex, **kwargs
)
self.draggable = draggable
Expand Down Expand Up @@ -263,7 +262,7 @@ class Icon(MacroElement):
"""
{% macro script(this, kwargs) %}
var {{ this.get_name() }} = L.AwesomeMarkers.icon(
{{ this.options|tojson }}
{{ this.options|tojavascript }}
);
{{ this._parent.get_name() }}.setIcon({{ this.get_name() }});
{% endmacro %}
Expand Down Expand Up @@ -307,7 +306,7 @@ def __init__(
f"color argument of Icon should be one of: {self.color_options}.",
stacklevel=2,
)
self.options = parse_options(
self.options = dict(
marker_color=color,
icon_color=icon_color,
icon=icon,
Expand Down Expand Up @@ -356,7 +355,7 @@ class Marker(MacroElement):
{% macro script(this, kwargs) %}
var {{ this.get_name() }} = L.marker(
{{ this.location|tojson }},
{{ this.options|tojson }}
{{ this.options|tojavascript }}
).addTo({{ this._parent.get_name() }});
{% endmacro %}
"""
Expand All @@ -374,7 +373,7 @@ def __init__(
super().__init__()
self._name = "Marker"
self.location = validate_location(location) if location is not None else None
self.options = parse_options(
self.options = dict(
draggable=draggable or None, autoPan=draggable or None, **kwargs
)
if icon is not None:
Expand Down Expand Up @@ -424,7 +423,7 @@ class Popup(Element):

_template = Template(
"""
var {{this.get_name()}} = L.popup({{ this.options|tojson }});
var {{this.get_name()}} = L.popup({{ this.options|tojavascript }});

{% for name, element in this.html._children.items() %}
{% if this.lazy %}
Expand Down Expand Up @@ -476,7 +475,7 @@ def __init__(

self.show = show
self.lazy = lazy
self.options = parse_options(
self.options = dict(
max_width=max_width,
autoClose=False if show or sticky else None,
closeOnClick=False if sticky else None,
Expand Down Expand Up @@ -526,22 +525,11 @@ class Tooltip(MacroElement):
`<div{% if this.style %} style={{ this.style|tojson }}{% endif %}>
{{ this.text }}
</div>`,
{{ this.options|tojson }}
{{ this.options|tojavascript }}
);
{% endmacro %}
"""
)
valid_options: Dict[str, Tuple[Type, ...]] = {
"pane": (str,),
"offset": (tuple,),
"direction": (str,),
"permanent": (bool,),
"sticky": (bool,),
"interactive": (bool,),
"opacity": (float, int),
"attribution": (str,),
"className": (str,),
}

def __init__(
self,
Expand All @@ -556,7 +544,7 @@ def __init__(
self.text = str(text)

kwargs.update({"sticky": sticky})
self.options = self.parse_options(kwargs)
self.options = kwargs

if style:
assert isinstance(
Expand All @@ -565,23 +553,6 @@ def __init__(
# noqa outside of type checking.
self.style = style

def parse_options(
self,
kwargs: Dict[str, TypeJsonValue],
) -> Dict[str, TypeJsonValue]:
"""Validate the provided kwargs and return options as json string."""
kwargs = {camelize(key): value for key, value in kwargs.items()}
for key in kwargs.keys():
assert (
key in self.valid_options
), "The option {} is not in the available options: {}.".format(
key, ", ".join(self.valid_options)
)
assert isinstance(
kwargs[key], self.valid_options[key]
), f"The option {key} must be one of the following types: {self.valid_options[key]}."
return kwargs


class FitBounds(MacroElement):
"""Fit the map to contain a bounding box with the
Expand Down Expand Up @@ -660,7 +631,7 @@ class FitOverlays(MacroElement):
}
});
if (bounds.isValid()) {
{{ this._parent.get_name() }}.{{ this.method }}(bounds, {{ this.options|tojson }});
{{ this._parent.get_name() }}.{{ this.method }}(bounds, {{ this.options|tojavascript }});
}
}
{{ this._parent.get_name() }}.on('overlayadd', customFlyToBounds);
Expand All @@ -682,7 +653,7 @@ def __init__(
self._name = "FitOverlays"
self.method = "flyToBounds" if fly else "fitBounds"
self.fit_on_map_load = fit_on_map_load
self.options = parse_options(padding=(padding, padding), max_zoom=max_zoom)
self.options = dict(padding=(padding, padding), max_zoom=max_zoom)


class CustomPane(MacroElement):
Expand Down
5 changes: 2 additions & 3 deletions folium/plugins/antpath.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from jinja2 import Template

from folium.elements import JSCSSMixin
from folium.template import Template
from folium.vector_layers import BaseMultiLocation, path_options


Expand Down Expand Up @@ -31,7 +30,7 @@ class AntPath(JSCSSMixin, BaseMultiLocation):
{% macro script(this, kwargs) %}
{{ this.get_name() }} = L.polyline.antPath(
{{ this.locations|tojson }},
{{ this.options|tojson }}
{{ this.options|tojavascript }}
).addTo({{this._parent.get_name()}});
{% endmacro %}
"""
Expand Down
Loading