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) |