Skip to content

Commit a3034f9

Browse files
authored
add custom Template class with tojavascript filter (#1912)
1 parent 3ec6ad6 commit a3034f9

File tree

2 files changed

+119
-0
lines changed

2 files changed

+119
-0
lines changed

folium/template.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import json
2+
from typing import Union
3+
4+
import jinja2
5+
from branca.element import Element
6+
7+
from folium.utilities import JsCode, TypeJsonValue, camelize
8+
9+
10+
def tojavascript(obj: Union[str, JsCode, dict, list, Element]) -> str:
11+
if isinstance(obj, JsCode):
12+
return obj.js_code
13+
elif isinstance(obj, Element):
14+
return obj.get_name()
15+
elif isinstance(obj, dict):
16+
out = ["{\n"]
17+
for key, value in obj.items():
18+
out.append(f' "{camelize(key)}": ')
19+
out.append(tojavascript(value))
20+
out.append(",\n")
21+
out.append("}")
22+
return "".join(out)
23+
elif isinstance(obj, list):
24+
out = ["[\n"]
25+
for value in obj:
26+
out.append(tojavascript(value))
27+
out.append(",\n")
28+
out.append("]")
29+
return "".join(out)
30+
else:
31+
return _to_escaped_json(obj)
32+
33+
34+
def _to_escaped_json(obj: TypeJsonValue) -> str:
35+
return (
36+
json.dumps(obj)
37+
.replace("<", "\\u003c")
38+
.replace(">", "\\u003e")
39+
.replace("&", "\\u0026")
40+
.replace("'", "\\u0027")
41+
)
42+
43+
44+
class Environment(jinja2.Environment):
45+
def __init__(self, *args, **kwargs):
46+
super().__init__(*args, **kwargs)
47+
self.filters["tojavascript"] = tojavascript
48+
49+
50+
class Template(jinja2.Template):
51+
environment_class = Environment

tests/test_template.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
from branca.element import Element
2+
3+
from folium import JsCode
4+
from folium.template import Environment, Template, _to_escaped_json, tojavascript
5+
6+
7+
def test_tojavascript_with_jscode():
8+
js_code = JsCode("console.log('Hello, World!')")
9+
assert tojavascript(js_code) == "console.log('Hello, World!')"
10+
11+
12+
def test_tojavascript_with_element():
13+
element = Element()
14+
assert tojavascript(element) == element.get_name()
15+
16+
17+
def test_tojavascript_with_dict():
18+
dict_obj = {"key": "value"}
19+
assert tojavascript(dict_obj) == '{\n "key": "value",\n}'
20+
21+
22+
def test_tojavascript_with_list():
23+
list_obj = ["value1", "value2"]
24+
assert tojavascript(list_obj) == '[\n"value1",\n"value2",\n]'
25+
26+
27+
def test_tojavascript_with_string():
28+
assert tojavascript("Hello, World!") == _to_escaped_json("Hello, World!")
29+
30+
31+
def test_tojavascript_with_combined_elements():
32+
js_code = JsCode("console.log('Hello, World!')")
33+
element = Element()
34+
combined_dict = {
35+
"key": "value",
36+
"list": ["value1", "value2", element, js_code],
37+
"nested_dict": {"nested_key": "nested_value"},
38+
}
39+
result = tojavascript(combined_dict)
40+
expected_lines = [
41+
"{",
42+
' "key": "value",',
43+
' "list": [',
44+
'"value1",',
45+
'"value2",',
46+
element.get_name() + ",",
47+
"console.log('Hello, World!'),",
48+
"],",
49+
' "nestedDict": {',
50+
' "nestedKey": "nested_value",',
51+
"},",
52+
"}",
53+
]
54+
for result_line, expected_line in zip(result.splitlines(), expected_lines):
55+
assert result_line == expected_line
56+
57+
58+
def test_to_escaped_json():
59+
assert _to_escaped_json("hi<>&'") == '"hi\\u003c\\u003e\\u0026\\u0027"'
60+
61+
62+
def test_environment_filter():
63+
env = Environment()
64+
assert "tojavascript" in env.filters
65+
66+
67+
def test_template_environment_class():
68+
assert Template.environment_class == Environment

0 commit comments

Comments
 (0)