app/django/utils/html.py
changeset 323 ff1a9aa48cfd
parent 54 03e267d67478
equal deleted inserted replaced
322:6641e941ef1e 323:ff1a9aa48cfd
    74 
    74 
    75 def urlize(text, trim_url_limit=None, nofollow=False, autoescape=False):
    75 def urlize(text, trim_url_limit=None, nofollow=False, autoescape=False):
    76     """
    76     """
    77     Converts any URLs in text into clickable links.
    77     Converts any URLs in text into clickable links.
    78 
    78 
    79     Works on http://, https://, and www. links.  Links can have trailing
    79     Works on http://, https://, www. links and links ending in .org, .net or
    80     punctuation (periods, commas, close-parens) and leading punctuation
    80     .com. Links can have trailing punctuation (periods, commas, close-parens)
    81     (opening parens) and it'll still do the right thing.
    81     and leading punctuation (opening parens) and it'll still do the right
       
    82     thing.
    82 
    83 
    83     If trim_url_limit is not None, the URLs in link text longer than this limit
    84     If trim_url_limit is not None, the URLs in link text longer than this limit
    84     will truncated to trim_url_limit-3 characters and appended with an elipsis.
    85     will truncated to trim_url_limit-3 characters and appended with an elipsis.
    85 
    86 
    86     If nofollow is True, the URLs in link text will get a rel="nofollow"
    87     If nofollow is True, the URLs in link text will get a rel="nofollow"
    87     attribute.
    88     attribute.
       
    89 
       
    90     If autoescape is True, the link text and URLs will get autoescaped.
    88     """
    91     """
    89     if autoescape:
    92     trim_url = lambda x, limit=trim_url_limit: limit is not None and (len(x) > limit and ('%s...' % x[:max(0, limit - 3)])) or x
    90         trim_url = lambda x, limit=trim_url_limit: conditional_escape(limit is not None and (len(x) > limit and ('%s...' % x[:max(0, limit - 3)])) or x)
       
    91     else:
       
    92         trim_url = lambda x, limit=trim_url_limit: limit is not None and (len(x) > limit and ('%s...' % x[:max(0, limit - 3)])) or x
       
    93     safe_input = isinstance(text, SafeData)
    93     safe_input = isinstance(text, SafeData)
    94     words = word_split_re.split(force_unicode(text))
    94     words = word_split_re.split(force_unicode(text))
    95     nofollow_attr = nofollow and ' rel="nofollow"' or ''
    95     nofollow_attr = nofollow and ' rel="nofollow"' or ''
    96     for i, word in enumerate(words):
    96     for i, word in enumerate(words):
    97         match = punctuation_re.match(word)
    97         match = None
       
    98         if '.' in word or '@' in word or ':' in word:
       
    99             match = punctuation_re.match(word)
    98         if match:
   100         if match:
    99             lead, middle, trail = match.groups()
   101             lead, middle, trail = match.groups()
   100             if safe_input:
   102             # Make URL we want to point to.
   101                 middle = mark_safe(middle)
   103             url = None
   102             if middle.startswith('www.') or ('@' not in middle and not middle.startswith('http://') and \
       
   103                     len(middle) > 0 and middle[0] in string.ascii_letters + string.digits and \
       
   104                     (middle.endswith('.org') or middle.endswith('.net') or middle.endswith('.com'))):
       
   105                 middle = 'http://%s' % middle
       
   106             if middle.startswith('http://') or middle.startswith('https://'):
   104             if middle.startswith('http://') or middle.startswith('https://'):
   107                 url = urlquote(middle, safe='/&=:;#?+*')
   105                 url = urlquote(middle, safe='/&=:;#?+*')
   108                 if autoescape and not safe_input:
   106             elif middle.startswith('www.') or ('@' not in middle and \
   109                     url = escape(url)
   107                     middle and middle[0] in string.ascii_letters + string.digits and \
   110                 trimmed_url = trim_url(middle)
   108                     (middle.endswith('.org') or middle.endswith('.net') or middle.endswith('.com'))):
   111                 middle = '<a href="%s"%s>%s</a>' % (url, nofollow_attr,
   109                 url = urlquote('http://%s' % middle, safe='/&=:;#?+*')
   112                         trimmed_url)
   110             elif '@' in middle and not ':' in middle and simple_email_re.match(middle):
   113             elif '@' in middle and not middle.startswith('www.') and \
   111                 url = 'mailto:%s' % middle
   114                       not ':' in middle and simple_email_re.match(middle):
   112                 nofollow_attr = ''
   115                 if autoescape:
   113             # Make link.
   116                     middle = conditional_escape(middle)
   114             if url:
   117                 middle = '<a href="mailto:%s">%s</a>' % (middle, middle)
   115                 trimmed = trim_url(middle)
   118             if lead + middle + trail != word:
       
   119                 if autoescape and not safe_input:
   116                 if autoescape and not safe_input:
   120                     lead, trail = escape(lead), escape(trail)
   117                     lead, trail = escape(lead), escape(trail)
       
   118                     url, trimmed = escape(url), escape(trimmed)
       
   119                 middle = '<a href="%s"%s>%s</a>' % (url, nofollow_attr, trimmed)
   121                 words[i] = mark_safe('%s%s%s' % (lead, middle, trail))
   120                 words[i] = mark_safe('%s%s%s' % (lead, middle, trail))
   122             elif autoescape and not safe_input:
   121             else:
   123                 words[i] = escape(word)
   122                 if safe_input:
       
   123                     words[i] = mark_safe(word)
       
   124                 elif autoescape:
       
   125                     words[i] = escape(word)
   124         elif safe_input:
   126         elif safe_input:
   125             words[i] = mark_safe(word)
   127             words[i] = mark_safe(word)
   126         elif autoescape:
   128         elif autoescape:
   127             words[i] = escape(word)
   129             words[i] = escape(word)
   128     return u''.join(words)
   130     return u''.join(words)