diff --git a/docs/user_guide/plugins/mouse_position.md b/docs/user_guide/plugins/mouse_position.md index 823054d17..148d35001 100644 --- a/docs/user_guide/plugins/mouse_position.md +++ b/docs/user_guide/plugins/mouse_position.md @@ -20,7 +20,7 @@ m ```{code-cell} ipython3 m = folium.Map() -formatter = "function(num) {return L.Util.formatNum(num, 3) + ' ° ';};" +formatter = "function(num) {return L.Util.formatNum(num, 3) + ' ° '}" MousePosition( position="topright", diff --git a/folium/elements.py b/folium/elements.py index 416ad3845..185953caf 100644 --- a/folium/elements.py +++ b/folium/elements.py @@ -1,7 +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 class JSCSSMixin(Element): diff --git a/folium/features.py b/folium/features.py index 041559b61..75f516cbc 100644 --- a/folium/features.py +++ b/folium/features.py @@ -14,11 +14,11 @@ 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, diff --git a/folium/folium.py b/folium/folium.py index 60e4f905a..628b42a90 100644 --- a/folium/folium.py +++ b/folium/folium.py @@ -8,11 +8,11 @@ from typing import Any, List, Optional, Sequence, Union from branca.element import Element, Figure, MacroElement -from jinja2 import Template from folium.elements import JSCSSMixin from folium.map import FitBounds, Layer from folium.raster_layers import TileLayer +from folium.template import Template from folium.utilities import ( TypeBounds, TypeJsonValue, diff --git a/folium/map.py b/folium/map.py index e3356c275..5f47e3446 100644 --- a/folium/map.py +++ b/folium/map.py @@ -7,10 +7,11 @@ from typing import Dict, List, Optional, Sequence, Tuple, Type, Union from branca.element import Element, Figure, Html, MacroElement -from jinja2 import Template from folium.elements import ElementAddToElement +from folium.template import Template from folium.utilities import ( + JsCode, TypeBounds, TypeJsonValue, camelize, @@ -147,21 +148,9 @@ class LayerControl(MacroElement): _template = Template( """ {% macro script(this,kwargs) %} - var {{ this.get_name() }}_layers = { - base_layers : { - {%- for key, val in this.base_layers.items() %} - {{ key|tojson }} : {{val}}, - {%- endfor %} - }, - overlays : { - {%- for key, val in this.overlays.items() %} - {{ key|tojson }} : {{val}}, - {%- endfor %} - }, - }; let {{ this.get_name() }} = L.control.layers( - {{ this.get_name() }}_layers.base_layers, - {{ this.get_name() }}_layers.overlays, + {{ this.base_layers|tojavascript }}, + {{ this.overlays|tojavascript }}, {{ this.options|tojson }} ).addTo({{this._parent.get_name()}}); @@ -187,8 +176,8 @@ def __init__( position=position, collapsed=collapsed, autoZIndex=autoZIndex, **kwargs ) self.draggable = draggable - self.base_layers: OrderedDict[str, str] = OrderedDict() - self.overlays: OrderedDict[str, str] = OrderedDict() + self.base_layers: OrderedDict[str, JsCode] = OrderedDict() + self.overlays: OrderedDict[str, JsCode] = OrderedDict() def reset(self) -> None: self.base_layers = OrderedDict() @@ -202,9 +191,9 @@ def render(self, **kwargs) -> None: continue key = item.layer_name if not item.overlay: - self.base_layers[key] = item.get_name() + self.base_layers[key] = JsCode(item.get_name()) else: - self.overlays[key] = item.get_name() + self.overlays[key] = JsCode(item.get_name()) super().render() diff --git a/folium/plugins/antpath.py b/folium/plugins/antpath.py index c578a3ec2..d5977d303 100644 --- a/folium/plugins/antpath.py +++ b/folium/plugins/antpath.py @@ -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 diff --git a/folium/plugins/beautify_icon.py b/folium/plugins/beautify_icon.py index d45e9eb58..8d53d1b94 100644 --- a/folium/plugins/beautify_icon.py +++ b/folium/plugins/beautify_icon.py @@ -1,7 +1,7 @@ from branca.element import MacroElement -from jinja2 import Template from folium.elements import JSCSSMixin +from folium.template import Template from folium.utilities import parse_options diff --git a/folium/plugins/boat_marker.py b/folium/plugins/boat_marker.py index f53ba99cc..ef61db545 100644 --- a/folium/plugins/boat_marker.py +++ b/folium/plugins/boat_marker.py @@ -1,7 +1,6 @@ -from jinja2 import Template - from folium.elements import JSCSSMixin from folium.map import Marker +from folium.template import Template from folium.utilities import parse_options diff --git a/folium/plugins/draw.py b/folium/plugins/draw.py index 95155f8e1..183e0f2c0 100644 --- a/folium/plugins/draw.py +++ b/folium/plugins/draw.py @@ -1,7 +1,7 @@ from branca.element import Element, Figure, MacroElement -from jinja2 import Template from folium.elements import JSCSSMixin +from folium.template import Template class Draw(JSCSSMixin, MacroElement): diff --git a/folium/plugins/dual_map.py b/folium/plugins/dual_map.py index 2e1000f4a..ffd760f64 100644 --- a/folium/plugins/dual_map.py +++ b/folium/plugins/dual_map.py @@ -1,9 +1,9 @@ from branca.element import Figure, MacroElement -from jinja2 import Template from folium.elements import JSCSSMixin from folium.folium import Map from folium.map import LayerControl +from folium.template import Template from folium.utilities import deep_copy diff --git a/folium/plugins/fast_marker_cluster.py b/folium/plugins/fast_marker_cluster.py index 0a55ab37c..22218ab55 100644 --- a/folium/plugins/fast_marker_cluster.py +++ b/folium/plugins/fast_marker_cluster.py @@ -1,6 +1,5 @@ -from jinja2 import Template - from folium.plugins.marker_cluster import MarkerCluster +from folium.template import Template from folium.utilities import if_pandas_df_convert_to_numpy, validate_location diff --git a/folium/plugins/feature_group_sub_group.py b/folium/plugins/feature_group_sub_group.py index ae07e0320..81245ff3f 100644 --- a/folium/plugins/feature_group_sub_group.py +++ b/folium/plugins/feature_group_sub_group.py @@ -1,7 +1,6 @@ -from jinja2 import Template - from folium.elements import JSCSSMixin from folium.map import Layer +from folium.template import Template class FeatureGroupSubGroup(JSCSSMixin, Layer): diff --git a/folium/plugins/float_image.py b/folium/plugins/float_image.py index 2f171d21c..d0f5ad5ea 100644 --- a/folium/plugins/float_image.py +++ b/folium/plugins/float_image.py @@ -1,5 +1,6 @@ from branca.element import MacroElement -from jinja2 import Template + +from folium.template import Template class FloatImage(MacroElement): diff --git a/folium/plugins/fullscreen.py b/folium/plugins/fullscreen.py index 84ab7e730..bf99e928b 100644 --- a/folium/plugins/fullscreen.py +++ b/folium/plugins/fullscreen.py @@ -1,7 +1,7 @@ from branca.element import MacroElement -from jinja2 import Template from folium.elements import JSCSSMixin +from folium.template import Template from folium.utilities import parse_options diff --git a/folium/plugins/geocoder.py b/folium/plugins/geocoder.py index 418dcb9d0..884081429 100644 --- a/folium/plugins/geocoder.py +++ b/folium/plugins/geocoder.py @@ -1,7 +1,7 @@ from branca.element import MacroElement -from jinja2 import Template from folium.elements import JSCSSMixin +from folium.template import Template from folium.utilities import parse_options diff --git a/folium/plugins/groupedlayercontrol.py b/folium/plugins/groupedlayercontrol.py index 6745f8aa4..d523bbfb8 100644 --- a/folium/plugins/groupedlayercontrol.py +++ b/folium/plugins/groupedlayercontrol.py @@ -1,7 +1,7 @@ from branca.element import MacroElement -from jinja2 import Template from folium.elements import JSCSSMixin +from folium.template import Template from folium.utilities import parse_options diff --git a/folium/plugins/heat_map.py b/folium/plugins/heat_map.py index cc6a981d5..b4fccda16 100644 --- a/folium/plugins/heat_map.py +++ b/folium/plugins/heat_map.py @@ -1,10 +1,10 @@ import warnings import numpy as np -from jinja2 import Template from folium.elements import JSCSSMixin from folium.map import Layer +from folium.template import Template from folium.utilities import ( if_pandas_df_convert_to_numpy, none_max, diff --git a/folium/plugins/heat_map_withtime.py b/folium/plugins/heat_map_withtime.py index 9a556773c..64789d4f4 100644 --- a/folium/plugins/heat_map_withtime.py +++ b/folium/plugins/heat_map_withtime.py @@ -1,8 +1,8 @@ from branca.element import Element, Figure -from jinja2 import Template from folium.elements import JSCSSMixin from folium.map import Layer +from folium.template import Template from folium.utilities import none_max, none_min diff --git a/folium/plugins/locate_control.py b/folium/plugins/locate_control.py index fb1c825d1..c6a7012cb 100644 --- a/folium/plugins/locate_control.py +++ b/folium/plugins/locate_control.py @@ -4,9 +4,9 @@ """ from branca.element import MacroElement -from jinja2 import Template from folium.elements import JSCSSMixin +from folium.template import Template from folium.utilities import parse_options diff --git a/folium/plugins/marker_cluster.py b/folium/plugins/marker_cluster.py index b6460e088..90f87e977 100644 --- a/folium/plugins/marker_cluster.py +++ b/folium/plugins/marker_cluster.py @@ -1,7 +1,6 @@ -from jinja2 import Template - from folium.elements import JSCSSMixin from folium.map import Layer, Marker +from folium.template import Template from folium.utilities import parse_options, validate_locations diff --git a/folium/plugins/measure_control.py b/folium/plugins/measure_control.py index 4b543dc2f..63414e0a2 100644 --- a/folium/plugins/measure_control.py +++ b/folium/plugins/measure_control.py @@ -1,7 +1,7 @@ from branca.element import MacroElement -from jinja2 import Template from folium.elements import JSCSSMixin +from folium.template import Template from folium.utilities import parse_options diff --git a/folium/plugins/minimap.py b/folium/plugins/minimap.py index 999cabd25..e5e27b158 100644 --- a/folium/plugins/minimap.py +++ b/folium/plugins/minimap.py @@ -1,8 +1,8 @@ from branca.element import MacroElement -from jinja2 import Template from folium.elements import JSCSSMixin from folium.raster_layers import TileLayer +from folium.template import Template from folium.utilities import parse_options diff --git a/folium/plugins/mouse_position.py b/folium/plugins/mouse_position.py index 2c1b1b6f3..92f21612e 100644 --- a/folium/plugins/mouse_position.py +++ b/folium/plugins/mouse_position.py @@ -1,8 +1,8 @@ from branca.element import MacroElement -from jinja2 import Template from folium.elements import JSCSSMixin -from folium.utilities import parse_options +from folium.template import Template +from folium.utilities import JsCode, TypeJsFunctionArg class MousePosition(JSCSSMixin, MacroElement): @@ -27,14 +27,14 @@ class MousePosition(JSCSSMixin, MacroElement): longitude and latitude decimal degree values. prefix : str, default '' A string to be prepended to the coordinates. - lat_formatter : str, default None + lat_formatter : str or JsCode, optional Custom Javascript function to format the latitude value. - lng_formatter : str, default None + lng_formatter : str or JsCode, optional Custom Javascript function to format the longitude value. Examples -------- - >>> fmtr = "function(num) {return L.Util.formatNum(num, 3) + ' º ';};" + >>> fmtr = "function(num) {return L.Util.formatNum(num, 3) + ' º '}" >>> MousePosition( ... position="topright", ... separator=" | ", @@ -49,12 +49,8 @@ class MousePosition(JSCSSMixin, MacroElement): """ {% macro script(this, kwargs) %} var {{ this.get_name() }} = new L.Control.MousePosition( - {{ this.options|tojson }} + {{ this.options|tojavascript }} ); - {{ this.get_name() }}.options["latFormatter"] = - {{ this.lat_formatter }}; - {{ this.get_name() }}.options["lngFormatter"] = - {{ this.lng_formatter }}; {{ this._parent.get_name() }}.addControl({{ this.get_name() }}); {% endmacro %} """ @@ -81,21 +77,21 @@ def __init__( lng_first=False, num_digits=5, prefix="", - lat_formatter=None, - lng_formatter=None, + lat_formatter: TypeJsFunctionArg = None, + lng_formatter: TypeJsFunctionArg = None, **kwargs ): super().__init__() self._name = "MousePosition" - self.options = parse_options( + self.options = dict( position=position, separator=separator, empty_string=empty_string, lng_first=lng_first, num_digits=num_digits, prefix=prefix, + lat_formatter=JsCode.optional_create(lat_formatter), + lng_formatter=JsCode.optional_create(lng_formatter), **kwargs ) - self.lat_formatter = lat_formatter or "undefined" - self.lng_formatter = lng_formatter or "undefined" diff --git a/folium/plugins/pattern.py b/folium/plugins/pattern.py index 2f90d32df..05017a2cc 100644 --- a/folium/plugins/pattern.py +++ b/folium/plugins/pattern.py @@ -1,8 +1,8 @@ from branca.element import MacroElement -from jinja2 import Template from folium.elements import JSCSSMixin from folium.folium import Map +from folium.template import Template from folium.utilities import get_obj_in_upper_tree, parse_options diff --git a/folium/plugins/polyline_text_path.py b/folium/plugins/polyline_text_path.py index 660d15909..9527f525f 100644 --- a/folium/plugins/polyline_text_path.py +++ b/folium/plugins/polyline_text_path.py @@ -1,7 +1,6 @@ -from jinja2 import Template - from folium.elements import JSCSSMixin from folium.features import MacroElement +from folium.template import Template from folium.utilities import parse_options diff --git a/folium/plugins/realtime.py b/folium/plugins/realtime.py index 429a40955..5c36dbeff 100644 --- a/folium/plugins/realtime.py +++ b/folium/plugins/realtime.py @@ -1,10 +1,10 @@ -from typing import Optional, Union +from typing import Union from branca.element import MacroElement -from jinja2 import Template from folium.elements import JSCSSMixin -from folium.utilities import JsCode, camelize, parse_options +from folium.template import Template +from folium.utilities import JsCode, TypeJsFunctionArg class Realtime(JSCSSMixin, MacroElement): @@ -27,11 +27,11 @@ class Realtime(JSCSSMixin, MacroElement): on the map and stopped when layer is removed from the map interval: int, default 60000 Automatic update interval, in milliseconds - get_feature_id: JsCode, optional + get_feature_id: str or JsCode, optional A JS function with a geojson `feature` as parameter default returns `feature.properties.id` Function to get an identifier to uniquely identify a feature over time - update_feature: JsCode, optional + update_feature: str or JsCode, optional A JS function with a geojson `feature` as parameter Used to update an existing feature's layer; by default, points (markers) are updated, other layers are discarded @@ -44,7 +44,8 @@ class Realtime(JSCSSMixin, MacroElement): Other keyword arguments are passed to the GeoJson layer, so you can pass - `style`, `point_to_layer` and/or `on_each_feature`. + `style`, `point_to_layer` and/or `on_each_feature`. Make sure to wrap + Javascript functions in the JsCode class. Examples -------- @@ -52,7 +53,7 @@ class Realtime(JSCSSMixin, MacroElement): >>> m = folium.Map(location=[40.73, -73.94], zoom_start=12) >>> rt = Realtime( ... "https://raw.githubusercontent.com/python-visualization/folium-example-data/main/subway_stations.geojson", - ... get_feature_id=JsCode("(f) => { return f.properties.objectid; }"), + ... get_feature_id="(f) => { return f.properties.objectid; }", ... point_to_layer=JsCode( ... "(f, latlng) => { return L.circleMarker(latlng, {radius: 8, fillOpacity: 0.2})}" ... ), @@ -64,18 +65,9 @@ class Realtime(JSCSSMixin, MacroElement): _template = Template( """ {% macro script(this, kwargs) %} - var {{ this.get_name() }}_options = {{ this.options|tojson }}; - {% for key, value in this.functions.items() %} - {{ this.get_name() }}_options["{{key}}"] = {{ value }}; - {% endfor %} - var {{ this.get_name() }} = new L.realtime( - {% if this.src is string or this.src is mapping -%} - {{ this.src|tojson }}, - {% else -%} - {{ this.src.js_code }}, - {% endif -%} - {{ this.get_name() }}_options + {{ this.src|tojavascript }}, + {{ this.options|tojavascript }} ); {{ this._parent.get_name() }}.addLayer( {{ this.get_name() }}._container); @@ -95,28 +87,19 @@ def __init__( source: Union[str, dict, JsCode], start: bool = True, interval: int = 60000, - get_feature_id: Optional[JsCode] = None, - update_feature: Optional[JsCode] = None, + get_feature_id: TypeJsFunctionArg = None, + update_feature: TypeJsFunctionArg = None, remove_missing: bool = False, **kwargs ): super().__init__() self._name = "Realtime" self.src = source - - kwargs["start"] = start - kwargs["interval"] = interval - if get_feature_id is not None: - kwargs["get_feature_id"] = get_feature_id - if update_feature is not None: - kwargs["update_feature"] = update_feature - kwargs["remove_missing"] = remove_missing - - # extract JsCode objects - self.functions = {} - for key, value in list(kwargs.items()): - if isinstance(value, JsCode): - self.functions[camelize(key)] = value.js_code - kwargs.pop(key) - - self.options = parse_options(**kwargs) + self.options = dict( + start=start, + interval=interval, + get_feature_id=JsCode.optional_create(get_feature_id), + update_feature=JsCode.optional_create(update_feature), + remove_missing=remove_missing, + **kwargs + ) diff --git a/folium/plugins/scroll_zoom_toggler.py b/folium/plugins/scroll_zoom_toggler.py index a8061b5a8..f932e1abb 100644 --- a/folium/plugins/scroll_zoom_toggler.py +++ b/folium/plugins/scroll_zoom_toggler.py @@ -1,5 +1,6 @@ from branca.element import MacroElement -from jinja2 import Template + +from folium.template import Template class ScrollZoomToggler(MacroElement): diff --git a/folium/plugins/search.py b/folium/plugins/search.py index b477456b5..b98773699 100644 --- a/folium/plugins/search.py +++ b/folium/plugins/search.py @@ -1,10 +1,10 @@ from branca.element import MacroElement -from jinja2 import Template from folium import Map from folium.elements import JSCSSMixin from folium.features import FeatureGroup, GeoJson, TopoJson from folium.plugins import MarkerCluster +from folium.template import Template from folium.utilities import parse_options diff --git a/folium/plugins/semicircle.py b/folium/plugins/semicircle.py index 6e85b1b1b..13639098f 100644 --- a/folium/plugins/semicircle.py +++ b/folium/plugins/semicircle.py @@ -1,7 +1,6 @@ -from jinja2 import Template - from folium.elements import JSCSSMixin from folium.map import Marker +from folium.template import Template from folium.utilities import parse_options from folium.vector_layers import path_options diff --git a/folium/plugins/side_by_side.py b/folium/plugins/side_by_side.py index 9df98973c..e62ce3aa5 100644 --- a/folium/plugins/side_by_side.py +++ b/folium/plugins/side_by_side.py @@ -1,7 +1,7 @@ from branca.element import MacroElement -from jinja2 import Template from folium.elements import JSCSSMixin +from folium.template import Template class SideBySideLayers(JSCSSMixin, MacroElement): diff --git a/folium/plugins/tag_filter_button.py b/folium/plugins/tag_filter_button.py index 2210112f8..c10587ac5 100644 --- a/folium/plugins/tag_filter_button.py +++ b/folium/plugins/tag_filter_button.py @@ -1,7 +1,7 @@ from branca.element import MacroElement -from jinja2 import Template from folium.elements import JSCSSMixin +from folium.template import Template from folium.utilities import parse_options diff --git a/folium/plugins/terminator.py b/folium/plugins/terminator.py index a345ebe10..4be68ca5f 100644 --- a/folium/plugins/terminator.py +++ b/folium/plugins/terminator.py @@ -1,7 +1,7 @@ from branca.element import MacroElement -from jinja2 import Template from folium.elements import JSCSSMixin +from folium.template import Template class Terminator(JSCSSMixin, MacroElement): diff --git a/folium/plugins/time_slider_choropleth.py b/folium/plugins/time_slider_choropleth.py index 9065af0e7..2c7ffcf44 100644 --- a/folium/plugins/time_slider_choropleth.py +++ b/folium/plugins/time_slider_choropleth.py @@ -1,8 +1,7 @@ -from jinja2 import Template - from folium.elements import JSCSSMixin from folium.features import GeoJson from folium.map import Layer +from folium.template import Template class TimeSliderChoropleth(JSCSSMixin, Layer): diff --git a/folium/plugins/timestamped_geo_json.py b/folium/plugins/timestamped_geo_json.py index 3fe66ac04..6cb73e5a9 100644 --- a/folium/plugins/timestamped_geo_json.py +++ b/folium/plugins/timestamped_geo_json.py @@ -1,10 +1,10 @@ import json from branca.element import MacroElement -from jinja2 import Template from folium.elements import JSCSSMixin from folium.folium import Map +from folium.template import Template from folium.utilities import get_bounds, parse_options diff --git a/folium/plugins/timestamped_wmstilelayer.py b/folium/plugins/timestamped_wmstilelayer.py index 6f1147638..e02ee5399 100644 --- a/folium/plugins/timestamped_wmstilelayer.py +++ b/folium/plugins/timestamped_wmstilelayer.py @@ -1,8 +1,8 @@ from branca.element import MacroElement -from jinja2 import Template from folium.elements import JSCSSMixin from folium.raster_layers import WmsTileLayer +from folium.template import Template from folium.utilities import parse_options diff --git a/folium/plugins/vectorgrid_protobuf.py b/folium/plugins/vectorgrid_protobuf.py index 9a37cac7f..1cc7ecec2 100644 --- a/folium/plugins/vectorgrid_protobuf.py +++ b/folium/plugins/vectorgrid_protobuf.py @@ -1,9 +1,8 @@ from typing import Optional, Union -from jinja2 import Template - from folium.elements import JSCSSMixin from folium.map import Layer +from folium.template import Template class VectorGridProtobuf(JSCSSMixin, Layer): diff --git a/folium/raster_layers.py b/folium/raster_layers.py index ea0e6d180..3c8ed84e8 100644 --- a/folium/raster_layers.py +++ b/folium/raster_layers.py @@ -6,9 +6,9 @@ import xyzservices from branca.element import Element, Figure -from jinja2 import Template from folium.map import Layer +from folium.template import Template from folium.utilities import ( TypeBounds, TypeJsonValue, diff --git a/folium/template.py b/folium/template.py new file mode 100644 index 000000000..83d4e273a --- /dev/null +++ b/folium/template.py @@ -0,0 +1,42 @@ +import json +from typing import Union + +import jinja2 + +from folium.utilities import JsCode, camelize + + +def tojavascript(obj: Union[str, JsCode, dict]) -> str: + if isinstance(obj, (str, JsCode)): + return obj + elif isinstance(obj, dict): + out = ["{\n"] + for key, value in obj.items(): + if value is None: + continue + out.append(f' "{camelize(key)}": ') + if isinstance(value, JsCode): + out.append(value) + else: + out.append( + json.dumps(obj) + .replace("<", "\\u003c") + .replace(">", "\\u003e") + .replace("&", "\\u0026") + .replace("'", "\\u0027") + ) + out.append(",\n") + out.append("}") + return "".join(out) + else: + raise TypeError(f"Unsupported type: {type(obj)}") + + +class Environment(jinja2.Environment): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.filters["tojavascript"] = tojavascript + + +class Template(jinja2.Template): + environment_class = Environment diff --git a/folium/utilities.py b/folium/utilities.py index afc4fc531..cb5282af2 100644 --- a/folium/utilities.py +++ b/folium/utilities.py @@ -412,8 +412,19 @@ def get_and_assert_figure_root(obj: Element) -> Figure: return figure -class JsCode: +class JsCode(str): """Wrapper around Javascript code.""" - def __init__(self, js_code: str): - self.js_code = js_code + @staticmethod + def optional_create(value: "TypeJsFunctionArg") -> Optional["JsCode"]: + """Return a JsCode object if value is not None.""" + if value is None: + return None + elif isinstance(value, JsCode): + return value + else: + assert isinstance(value, str) + return JsCode(value) + + +TypeJsFunctionArg = Union[None, str, JsCode] diff --git a/folium/vector_layers.py b/folium/vector_layers.py index 6e0350610..e7ee401eb 100644 --- a/folium/vector_layers.py +++ b/folium/vector_layers.py @@ -5,9 +5,9 @@ from typing import List, Optional, Sequence, Union from branca.element import MacroElement -from jinja2 import Template from folium.map import Marker, Popup, Tooltip +from folium.template import Template from folium.utilities import ( TypeLine, TypeMultiLine,