templatetags: backport json_script from django 2.1 (#40768)

This commit is contained in:
Frédéric Péters 2020-03-16 20:25:31 +01:00
parent 90f17f8595
commit 6b329e6b48
2 changed files with 33 additions and 0 deletions

View File

@ -25,12 +25,15 @@ from django import template
from django.conf import settings
from django.core import signing
from django.core.exceptions import PermissionDenied
from django.core.serializers.json import DjangoJSONEncoder
from django.template import VariableDoesNotExist
from django.template.base import TOKEN_BLOCK, TOKEN_VAR, TOKEN_COMMENT
from django.template import defaultfilters
from django.template.defaultfilters import stringfilter
from django.utils import dateparse, six
from django.utils.encoding import force_text
from django.utils.html import format_html
from django.utils.safestring import mark_safe
from combo.data.models import Page, Placeholder
from combo.public.menu import get_menu_context
@ -38,6 +41,7 @@ from combo.utils import NothingInCacheException, flatten_context
from combo.utils.date import make_date, make_datetime
from combo.apps.dashboard.models import DashboardCell, Tile
register = template.Library()
def skeleton_text(context, placeholder_name, content=''):
@ -430,3 +434,27 @@ def decimal(value, arg=None):
if arg is None:
return value
return defaultfilters.floatformat(value, arg=arg)
_json_script_escapes = {
ord('>'): '\\u003E',
ord('<'): '\\u003C',
ord('&'): '\\u0026',
}
@register.filter(is_safe=True)
def json_script(value, element_id):
"""
Escape all the HTML/XML special characters with their unicode escapes, so
value is safe to be output anywhere except for inside a tag attribute. Wrap
the escaped JSON in a script tag.
--
This is a backport from Django 2.1; it should be removed once Combo bumps
its minimal dependency to 2.1.
"""
json_str = json.dumps(value, cls=DjangoJSONEncoder).translate(_json_script_escapes)
return format_html(
'<script id="{}" type="application/json">{}</script>',
element_id, mark_safe(json_str)
)

View File

@ -531,3 +531,8 @@ def test_decimal_templatetag():
assert tmpl.render(Context()) == 'hello'
tmpl = Template('{% if 3|decimal|decimal == 3 %}hello{% endif %}')
assert tmpl.render(Context()) == 'hello'
def test_json_script():
tmpl = Template('{{ plop|json_script:"toto" }}')
assert tmpl.render(Context({'plop': {'a': 'b'}})) == '<script id="toto" type="application/json">{"a": "b"}</script>'