Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

[1.2.X] Fixed #2986 -- Made the JavaScript code that drives related m…

…odel instance addition in a popup window handle a model representation containing new lines. Also, moved the escapejs functionality to django.utils.html so it can be used from Python code. Thanks andrewwatts for the patch.

Backport of [15131] from trunk

git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.2.X@15191 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 3297c09da4426b6dd2b7122d67a103536b26bce9 1 parent 58038a8
Ramiro Morales authored January 13, 2011
4  django/contrib/admin/options.py
@@ -18,7 +18,7 @@
18 18
 from django.utils.decorators import method_decorator
19 19
 from django.utils.datastructures import SortedDict
20 20
 from django.utils.functional import update_wrapper
21  
-from django.utils.html import escape
  21
+from django.utils.html import escape, escapejs
22 22
 from django.utils.safestring import mark_safe
23 23
 from django.utils.functional import curry
24 24
 from django.utils.text import capfirst, get_text_list
@@ -702,7 +702,7 @@ def response_add(self, request, obj, post_url_continue='../%s/'):
702 702
         if request.POST.has_key("_popup"):
703 703
             return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, "%s", "%s");</script>' % \
704 704
                 # escape() calls force_unicode.
705  
-                (escape(pk_value), escape(obj)))
  705
+                (escape(pk_value), escapejs(obj)))
706 706
         elif request.POST.has_key("_addanother"):
707 707
             self.message_user(request, msg + ' ' + (_("You may add another %s below.") % force_unicode(opts.verbose_name)))
708 708
             return HttpResponseRedirect(request.path)
24  django/template/defaultfilters.py
@@ -64,29 +64,10 @@ def capfirst(value):
64 64
 capfirst.is_safe=True
65 65
 capfirst = stringfilter(capfirst)
66 66
 
67  
-_base_js_escapes = (
68  
-    ('\\', r'\u005C'),
69  
-    ('\'', r'\u0027'),
70  
-    ('"', r'\u0022'),
71  
-    ('>', r'\u003E'),
72  
-    ('<', r'\u003C'),
73  
-    ('&', r'\u0026'),
74  
-    ('=', r'\u003D'),
75  
-    ('-', r'\u002D'),
76  
-    (';', r'\u003B'),
77  
-    (u'\u2028', r'\u2028'),
78  
-    (u'\u2029', r'\u2029')
79  
-)
80  
-
81  
-# Escape every ASCII character with a value less than 32.
82  
-_js_escapes = (_base_js_escapes +
83  
-               tuple([('%c' % z, '\\u%04X' % z) for z in range(32)]))
84  
-
85 67
 def escapejs(value):
86 68
     """Hex encodes characters for use in JavaScript strings."""
87  
-    for bad, good in _js_escapes:
88  
-        value = value.replace(bad, good)
89  
-    return value
  69
+    from django.utils.html import escapejs
  70
+    return escapejs(value)
90 71
 escapejs = stringfilter(escapejs)
91 72
 
92 73
 def fix_ampersands(value):
@@ -735,7 +716,6 @@ def timesince(value, arg=None):
735 716
 def timeuntil(value, arg=None):
736 717
     """Formats a date as the time until that date (i.e. "4 days, 6 hours")."""
737 718
     from django.utils.timesince import timeuntil
738  
-    from datetime import datetime
739 719
     if not value:
740 720
         return u''
741 721
     try:
25  django/utils/html.py
@@ -34,6 +34,31 @@ def escape(html):
34 34
     return mark_safe(force_unicode(html).replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;').replace('"', '&quot;').replace("'", '&#39;'))
35 35
 escape = allow_lazy(escape, unicode)
36 36
 
  37
+_base_js_escapes = (
  38
+    ('\\', r'\u005C'),
  39
+    ('\'', r'\u0027'),
  40
+    ('"', r'\u0022'),
  41
+    ('>', r'\u003E'),
  42
+    ('<', r'\u003C'),
  43
+    ('&', r'\u0026'),
  44
+    ('=', r'\u003D'),
  45
+    ('-', r'\u002D'),
  46
+    (';', r'\u003B'),
  47
+    (u'\u2028', r'\u2028'),
  48
+    (u'\u2029', r'\u2029')
  49
+)
  50
+
  51
+# Escape every ASCII character with a value less than 32.
  52
+_js_escapes = (_base_js_escapes +
  53
+               tuple([('%c' % z, '\\u%04X' % z) for z in range(32)]))
  54
+
  55
+def escapejs(value):
  56
+    """Hex encodes characters for use in JavaScript strings."""
  57
+    for bad, good in _js_escapes:
  58
+        value = mark_safe(force_unicode(value).replace(bad, good))
  59
+    return value
  60
+escapejs = allow_lazy(escapejs, unicode)
  61
+
37 62
 def conditional_escape(html):
38 63
     """
39 64
     Similar to escape(), except that it doesn't operate on pre-escaped strings.
16  tests/regressiontests/admin_views/tests.py
@@ -101,6 +101,22 @@ def testBasicAddPost(self):
101 101
         response = self.client.post('/test_admin/%s/admin_views/section/add/' % self.urlbit, post_data)
102 102
         self.assertEqual(response.status_code, 302) # redirect somewhere
103 103
 
  104
+    def testPopupAddPost(self):
  105
+        """
  106
+        Ensure http response from a popup is properly escaped.
  107
+        """
  108
+        post_data = {
  109
+            '_popup': u'1',
  110
+            'title': u'title with a new\nline',
  111
+            'content': u'some content',
  112
+            'date_0': u'2010-09-10',
  113
+            'date_1': u'14:55:39',
  114
+        }
  115
+        response = self.client.post('/test_admin/%s/admin_views/article/add/' % self.urlbit, post_data)
  116
+        self.failUnlessEqual(response.status_code, 200)
  117
+        self.assertContains(response, 'dismissAddAnotherPopup')
  118
+        self.assertContains(response, 'title with a new\u000Aline')
  119
+
104 120
     # Post data for edit inline
105 121
     inline_post_data = {
106 122
         "name": u"Test section",
12  tests/regressiontests/utils/html.py
@@ -109,3 +109,15 @@ def test_fix_ampersands(self):
109 109
         )
110 110
         for value, output in items:
111 111
             self.check_output(f, value, output)
  112
+
  113
+    def test_escapejs(self):
  114
+        f = html.escapejs
  115
+        items = (
  116
+            (u'"double quotes" and \'single quotes\'', u'\\u0022double quotes\\u0022 and \\u0027single quotes\\u0027'),
  117
+            (ur'\ : backslashes, too', u'\\u005C : backslashes, too'),
  118
+            (u'and lots of whitespace: \r\n\t\v\f\b', u'and lots of whitespace: \\u000D\\u000A\\u0009\\u000B\\u000C\\u0008'),
  119
+            (ur'<script>and this</script>', u'\\u003Cscript\\u003Eand this\\u003C/script\\u003E'),
  120
+            (u'paragraph separator:\u2029and line separator:\u2028', u'paragraph separator:\\u2029and line separator:\\u2028'),
  121
+        )
  122
+        for value, output in items:
  123
+            self.check_output(f, value, output)

0 notes on commit 3297c09

Please sign in to comment.
Something went wrong with that request. Please try again.