Merge "Fix on async messaging to don't escape message string marked as safe."
This commit is contained in:
commit
216d566c9c
@ -22,6 +22,7 @@ messaging needs (e.g. AJAX communication, etc.).
|
|||||||
from django.contrib import messages as _messages
|
from django.contrib import messages as _messages
|
||||||
from django.contrib.messages import constants
|
from django.contrib.messages import constants
|
||||||
from django.utils.encoding import force_unicode
|
from django.utils.encoding import force_unicode
|
||||||
|
from django.utils.safestring import SafeData
|
||||||
|
|
||||||
|
|
||||||
def add_message(request, level, message, extra_tags='', fail_silently=False):
|
def add_message(request, level, message, extra_tags='', fail_silently=False):
|
||||||
@ -30,8 +31,13 @@ def add_message(request, level, message, extra_tags='', fail_silently=False):
|
|||||||
"""
|
"""
|
||||||
if request.is_ajax():
|
if request.is_ajax():
|
||||||
tag = constants.DEFAULT_TAGS[level]
|
tag = constants.DEFAULT_TAGS[level]
|
||||||
|
# if message is marked as safe, pass "safe" tag as extra_tags so that
|
||||||
|
# client can skip HTML escape for the message when rendering
|
||||||
|
if isinstance(message, SafeData):
|
||||||
|
extra_tags = extra_tags + ' safe'
|
||||||
request.horizon['async_messages'].append([tag,
|
request.horizon['async_messages'].append([tag,
|
||||||
force_unicode(message)])
|
force_unicode(message),
|
||||||
|
extra_tags])
|
||||||
else:
|
else:
|
||||||
return _messages.add_message(request, level, message,
|
return _messages.add_message(request, level, message,
|
||||||
extra_tags, fail_silently)
|
extra_tags, fail_silently)
|
||||||
|
@ -98,8 +98,8 @@ class HorizonMiddleware(object):
|
|||||||
# Drop our messages back into the session as per usual so they
|
# Drop our messages back into the session as per usual so they
|
||||||
# don't disappear during the redirect. Not that we explicitly
|
# don't disappear during the redirect. Not that we explicitly
|
||||||
# use django's messages methods here.
|
# use django's messages methods here.
|
||||||
for tag, message in queued_msgs:
|
for tag, message, extra_tags in queued_msgs:
|
||||||
getattr(django_messages, tag)(request, message)
|
getattr(django_messages, tag)(request, message, extra_tags)
|
||||||
redirect_response = http.HttpResponse()
|
redirect_response = http.HttpResponse()
|
||||||
redirect_response['X-Horizon-Location'] = response['location']
|
redirect_response['X-Horizon-Location'] = response['location']
|
||||||
return redirect_response
|
return redirect_response
|
||||||
|
@ -1,9 +1,15 @@
|
|||||||
horizon.alert = function (type, message) {
|
horizon.alert = function (type, message, extra_tags) {
|
||||||
|
safe = false
|
||||||
|
// Check if the message is tagged as safe.
|
||||||
|
if (typeof(extra_tags) !== "undefined" && _.contains(extra_tags.split(' '), 'safe')) {
|
||||||
|
safe = true
|
||||||
|
}
|
||||||
var template = horizon.templates.compiled_templates["#alert_message_template"],
|
var template = horizon.templates.compiled_templates["#alert_message_template"],
|
||||||
params = {
|
params = {
|
||||||
"type": type,
|
"type": type,
|
||||||
"type_capitalized": horizon.utils.capitalize(type),
|
"type_capitalized": horizon.utils.capitalize(type),
|
||||||
"message": message
|
"message": message,
|
||||||
|
"safe": safe
|
||||||
};
|
};
|
||||||
return $(template.render(params)).hide().prependTo("#main_content .messages").fadeIn(100);
|
return $(template.render(params)).hide().prependTo("#main_content .messages").fadeIn(100);
|
||||||
};
|
};
|
||||||
@ -26,7 +32,7 @@ horizon.addInitFunction(function () {
|
|||||||
$("body").ajaxComplete(function(event, request, settings){
|
$("body").ajaxComplete(function(event, request, settings){
|
||||||
var message_array = $.parseJSON(horizon.ajax.get_messages(request));
|
var message_array = $.parseJSON(horizon.ajax.get_messages(request));
|
||||||
$(message_array).each(function (index, item) {
|
$(message_array).each(function (index, item) {
|
||||||
horizon.alert(item[0], item[1]);
|
horizon.alert(item[0], item[1], item[2]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -25,4 +25,14 @@ horizon.addInitFunction(function () {
|
|||||||
equal($('#main_content .messages .alert-success').length, 0, "Verify our success message was removed.");
|
equal($('#main_content .messages .alert-success').length, 0, "Verify our success message was removed.");
|
||||||
equal($('#main_content .messages .alert').length, 0, "Verify no messages remain.");
|
equal($('#main_content .messages .alert').length, 0, "Verify no messages remain.");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("Alert With HTML Tag", function () {
|
||||||
|
safe_string = "A safe message <a>here</a>!"
|
||||||
|
message = horizon.alert("success", safe_string, "safe");
|
||||||
|
ok(message, "Create a message with extra tag.");
|
||||||
|
ok((message.html().indexOf(safe_string ) != -1), 'Verify the message with HTML tag was not escaped.');
|
||||||
|
equal($('#main_content .messages .alert').length, 1, "Verify our message was added to the DOM.");
|
||||||
|
horizon.clearAllMessages();
|
||||||
|
equal($('#main_content .messages .alert').length, 0, "Verify our message was removed.");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -7,7 +7,15 @@
|
|||||||
{% jstemplate %}
|
{% jstemplate %}
|
||||||
<div class="alert alert-block fade in alert-[[type]]">
|
<div class="alert alert-block fade in alert-[[type]]">
|
||||||
<a class="close" data-dismiss="alert" href="#">×</a>
|
<a class="close" data-dismiss="alert" href="#">×</a>
|
||||||
<p><strong>[[type_capitalized]]: </strong>[[message]]</p>
|
<p>
|
||||||
|
<strong>[[type_capitalized]]: </strong>
|
||||||
|
[[#safe]]
|
||||||
|
[[[message]]]
|
||||||
|
[[/safe]]
|
||||||
|
[[^safe]]
|
||||||
|
[[message]]
|
||||||
|
[[/safe]]
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{% endjstemplate %}
|
{% endjstemplate %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -120,6 +120,7 @@ class JSTemplateNode(template.Node):
|
|||||||
|
|
||||||
def render(self, context, ):
|
def render(self, context, ):
|
||||||
output = self.nodelist.render(context)
|
output = self.nodelist.render(context)
|
||||||
|
output = output.replace('[[[', '{{{').replace(']]]', '}}}')
|
||||||
output = output.replace('[[', '{{').replace(']]', '}}')
|
output = output.replace('[[', '{{').replace(']]', '}}')
|
||||||
output = output.replace('[%', '{%').replace('%]', '%}')
|
output = output.replace('[%', '{%').replace('%]', '%}')
|
||||||
return output
|
return output
|
||||||
@ -128,7 +129,8 @@ class JSTemplateNode(template.Node):
|
|||||||
@register.tag
|
@register.tag
|
||||||
def jstemplate(parser, token):
|
def jstemplate(parser, token):
|
||||||
"""
|
"""
|
||||||
Replaces ``[[`` and ``]]`` with ``{{`` and ``}}`` and
|
Replaces ``[[[`` and ``]]]`` with ``{{{`` and ``}}}``,
|
||||||
|
``[[`` and ``]]`` with ``{{`` and ``}}`` and
|
||||||
``[%`` and ``%]`` with ``{%`` and ``%}`` to avoid conflicts
|
``[%`` and ``%]`` with ``{%`` and ``%}`` to avoid conflicts
|
||||||
with Django's template engine when using any of the Mustache-based
|
with Django's template engine when using any of the Mustache-based
|
||||||
templating libraries.
|
templating libraries.
|
||||||
|
@ -18,6 +18,7 @@ import json
|
|||||||
|
|
||||||
from django import http
|
from django import http
|
||||||
from django.utils.encoding import force_unicode
|
from django.utils.encoding import force_unicode
|
||||||
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from horizon import messages
|
from horizon import messages
|
||||||
@ -29,7 +30,21 @@ class MessageTests(test.TestCase):
|
|||||||
def test_middleware_header(self):
|
def test_middleware_header(self):
|
||||||
req = self.request
|
req = self.request
|
||||||
string = _("Giant ants are attacking San Francisco!")
|
string = _("Giant ants are attacking San Francisco!")
|
||||||
expected = ["error", force_unicode(string)]
|
expected = ["error", force_unicode(string), ""]
|
||||||
|
self.assertTrue("async_messages" in req.horizon)
|
||||||
|
self.assertItemsEqual(req.horizon['async_messages'], [])
|
||||||
|
req.META['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
|
||||||
|
messages.error(req, string)
|
||||||
|
self.assertItemsEqual(req.horizon['async_messages'], [expected])
|
||||||
|
res = http.HttpResponse()
|
||||||
|
res = middleware.HorizonMiddleware().process_response(req, res)
|
||||||
|
self.assertEqual(res['X-Horizon-Messages'],
|
||||||
|
json.dumps([expected]))
|
||||||
|
|
||||||
|
def test_safe_message(self):
|
||||||
|
req = self.request
|
||||||
|
string = mark_safe(_("We are now safe from ants! Go <a>here</a>!"))
|
||||||
|
expected = ["error", force_unicode(string), " safe"]
|
||||||
self.assertTrue("async_messages" in req.horizon)
|
self.assertTrue("async_messages" in req.horizon)
|
||||||
self.assertItemsEqual(req.horizon['async_messages'], [])
|
self.assertItemsEqual(req.horizon['async_messages'], [])
|
||||||
req.META['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
|
req.META['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user