continued convertig filters
authorChristoph Hack <christoph@tux21b.org>
Sun, 13 Apr 2008 23:35:10 +0000 (01:35 +0200)
committerChristoph Hack <christoph@tux21b.org>
Sun, 13 Apr 2008 23:35:10 +0000 (01:35 +0200)
--HG--
branch : trunk

jinja2/compiler.py
jinja2/filters.py
jinja2/utils.py
tests/test_filters.py

index 4ddacd9084e994183ef77b4edb1338e066cda30a..162192de28175e5f87e086572d911e44d359f6dc 100644 (file)
@@ -981,12 +981,14 @@ class CodeGenerator(NodeVisitor):
 
     def visit_Filter(self, node, frame, initial=None):
         self.write('f_%s(' % node.name)
-        if initial is not None:
+        func = self.environment.filters.get(node.name)
+        if getattr(func, 'contextfilter', False):
+            self.write('context, ')
+        if isinstance(node.node, nodes.Filter):
+            self.visit_Filter(node.node, frame, initial)
+        elif node.node is None:
             self.write(initial)
         else:
-            func = self.environment.filters.get(node.name)
-            if getattr(func, 'contextfilter', False):
-                self.write('context, ')
             self.visit(node.node, frame)
         self.signature(node, frame)
         self.write(')')
index db0ea228674907f64ecda83c088f26cbcc16b864..300e0cd88da0c5a6bb4ecb65886d6def43a7ccc8 100644 (file)
@@ -15,8 +15,8 @@ try:
 except ImportError:
     itemgetter = lambda a: lambda b: b[a]
 from urllib import urlencode, quote
-from jinja2.utils import escape, pformat
-from jinja2.nodes import Undefined
+from jinja2.utils import escape, pformat, urlize
+from jinja2.runtime import Undefined
 
 
 
@@ -287,31 +287,6 @@ def do_random(seq):
         return env.undefined_singleton
 
 
-def do_urlencode(value):
-    """
-    urlencode a string or directory.
-
-    .. sourcecode:: jinja
-
-        {{ {'foo': 'bar', 'blub': 'blah'}|urlencode }}
-            -> foo=bar&blub=blah
-
-        {{ 'Hello World' }}
-            -> Hello%20World
-    """
-    if isinstance(value, dict):
-        tmp = {}
-        for key, value in value.iteritems():
-            # XXX env.charset?
-            key = unicode(key).encode(env.charset)
-            value = unicode(value).encode(env.charset)
-            tmp[key] = value
-        return urlencode(tmp)
-    else:
-        # XXX: env.charset?
-        return quote(unicode(value).encode(env.charset))
-
-
 def do_jsonencode(value):
     """
     JSON dump a variable. just works if simplejson is installed.
@@ -825,7 +800,6 @@ FILTERS = {
     'first':                do_first,
     'last':                 do_last,
     'random':               do_random,
-    'urlencode':            do_urlencode,
     'jsonencode':           do_jsonencode,
     'filesizeformat':       do_filesizeformat,
     'pprint':               do_pprint,
index 90f30e907f90fad1cc65143d8302acbb73b024d5..b597ed0586fef5a64692419ab6aa21dbf0446c56 100644 (file)
@@ -8,6 +8,8 @@
     :copyright: 2008 by Armin Ronacher.
     :license: BSD, see LICENSE for more details.
 """
+import re
+import string
 
 
 def escape(obj, attribute=False):
@@ -32,3 +34,60 @@ def pformat(obj, verbose=False):
     except ImportError:
         from pprint import pformat
         return pformat(obj)
+
+
+_word_split_re = re.compile(r'(\s+)')
+
+_punctuation_re = re.compile(
+    '^(?P<lead>(?:%s)*)(?P<middle>.*?)(?P<trail>(?:%s)*)$' %  (
+        '|'.join([re.escape(p) for p in ('(', '<', '&lt;')]),
+        '|'.join([re.escape(p) for p in ('.', ',', ')', '>', '\n', '&gt;')])
+    )
+)
+
+_simple_email_re = re.compile(r'^\S+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+$')
+
+
+def urlize(text, trim_url_limit=None, nofollow=False):
+    """
+    Converts any URLs in text into clickable links. Works on http://,
+    https:// and www. links. Links can have trailing punctuation (periods,
+    commas, close-parens) and leading punctuation (opening parens) and
+    it'll still do the right thing.
+
+    If trim_url_limit is not None, the URLs in link text will be limited
+    to trim_url_limit characters.
+
+    If nofollow is True, the URLs in link text will get a rel="nofollow"
+    attribute.
+    """
+    trim_url = lambda x, limit=trim_url_limit: limit is not None \
+                         and (x[:limit] + (len(x) >=limit and '...'
+                         or '')) or x
+    words = _word_split_re.split(text)
+    nofollow_attr = nofollow and ' rel="nofollow"' or ''
+    for i, word in enumerate(words):
+        match = _punctuation_re.match(word)
+        if match:
+            lead, middle, trail = match.groups()
+            if middle.startswith('www.') or (
+                '@' not in middle and
+                not middle.startswith('http://') and
+                len(middle) > 0 and
+                middle[0] in string.letters + string.digits and (
+                    middle.endswith('.org') or
+                    middle.endswith('.net') or
+                    middle.endswith('.com')
+                )):
+                middle = '<a href="http://%s"%s>%s</a>' % (middle,
+                    nofollow_attr, trim_url(middle))
+            if middle.startswith('http://') or \
+               middle.startswith('https://'):
+                middle = '<a href="%s"%s>%s</a>' % (middle,
+                    nofollow_attr, trim_url(middle))
+            if '@' in middle and not middle.startswith('www.') and \
+               not ':' in middle and _simple_email_re.match(middle):
+                middle = '<a href="mailto:%s">%s</a>' % (middle, middle)
+            if lead + middle + trail != word:
+                words[i] = lead + middle + trail
+    return u''.join(words)
index 2378d1011b5449ca82c6ac869037ddab3e9abf5a..7a7ea9f09f32cf72b6b73c952b1515ecdacd7d57 100644 (file)
@@ -49,7 +49,6 @@ TRUNCATE = '''{{ data|truncate(15, true, ">>>") }}|\
 {{ data|truncate(15, false, ">>>") }}|\
 {{ smalldata|truncate(15) }}'''
 UPPER = '''{{ "foo"|upper }}'''
-URLENCODE = '''{{ "f#b"|urlencode }}'''
 URLIZE = '''{{ "foo http://www.example.com/ bar"|urlize }}'''
 WORDCOUNT = '''{{ "foo bar baz"|wordcount }}'''
 BLOCK = '''{% filter lower|escape %}<HEHE>{% endfilter %}'''
@@ -203,7 +202,7 @@ def test_reverse(env):
 
 def test_string(env):
     tmpl = env.from_string(STRING)
-    assert tmpl.render(foo=range(10)) == str(range(10))
+    assert tmpl.render(foo=range(10)) == unicode(xrange(10))
 
 
 def test_title(env):
@@ -228,11 +227,6 @@ def test_upper(env):
     assert tmpl.render() == 'FOO'
 
 
-def test_urlencode(env):
-    tmpl = env.from_string(URLENCODE)
-    assert tmpl.render() == 'f%23b'
-
-
 def test_urlize(env):
     tmpl = env.from_string(URLIZE)
     assert tmpl.render() == 'foo <a href="http://www.example.com/">'\