@@ -80,19 +80,77 module Redmine | |||||
80 | end |
|
80 | end | |
81 | end |
|
81 | end | |
82 |
|
82 | |||
|
83 | module LinksHelper | |||
|
84 | AUTO_LINK_RE = %r{ | |||
|
85 | ( # leading text | |||
|
86 | <\w+.*?>| # leading HTML tag, or | |||
|
87 | [^=<>!:'"/]| # leading punctuation, or | |||
|
88 | ^ # beginning of line | |||
|
89 | ) | |||
|
90 | ( | |||
|
91 | (?:https?://)| # protocol spec, or | |||
|
92 | (?:s?ftps?://)| | |||
|
93 | (?:www\.) # www.* | |||
|
94 | ) | |||
|
95 | ( | |||
|
96 | (\S+?) # url | |||
|
97 | (\/)? # slash | |||
|
98 | ) | |||
|
99 | ((?:>)?|[^\w\=\/;\(\)]*?) # post | |||
|
100 | (?=<|\s|$) | |||
|
101 | }x unless const_defined?(:AUTO_LINK_RE) | |||
|
102 | ||||
|
103 | # Destructively remplaces urls into clickable links | |||
|
104 | def auto_link!(text) | |||
|
105 | text.gsub!(AUTO_LINK_RE) do | |||
|
106 | all, leading, proto, url, post = $&, $1, $2, $3, $6 | |||
|
107 | if leading =~ /<a\s/i || leading =~ /![<>=]?/ | |||
|
108 | # don't replace URL's that are already linked | |||
|
109 | # and URL's prefixed with ! !> !< != (textile images) | |||
|
110 | all | |||
|
111 | else | |||
|
112 | # Idea below : an URL with unbalanced parethesis and | |||
|
113 | # ending by ')' is put into external parenthesis | |||
|
114 | if ( url[-1]==?) and ((url.count("(") - url.count(")")) < 0 ) ) | |||
|
115 | url=url[0..-2] # discard closing parenth from url | |||
|
116 | post = ")"+post # add closing parenth to post | |||
|
117 | end | |||
|
118 | tag = content_tag('a', proto + url, :href => "#{proto=="www."?"http://www.":proto}#{url}", :class => 'external') | |||
|
119 | %(#{leading}#{tag}#{post}) | |||
|
120 | end | |||
|
121 | end | |||
|
122 | end | |||
|
123 | ||||
|
124 | # Destructively remplaces email addresses into clickable links | |||
|
125 | def auto_mailto!(text) | |||
|
126 | text.gsub!(/([\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do | |||
|
127 | mail = $1 | |||
|
128 | if text.match(/<a\b[^>]*>(.*)(#{Regexp.escape(mail)})(.*)<\/a>/) | |||
|
129 | ||||
|
130 | else | |||
|
131 | content_tag('a', mail, :href => "mailto:#{mail}", :class => "email") | |||
|
132 | end | |||
|
133 | end | |||
|
134 | end | |||
|
135 | end | |||
|
136 | ||||
83 | # Default formatter module |
|
137 | # Default formatter module | |
84 | module NullFormatter |
|
138 | module NullFormatter | |
85 | class Formatter |
|
139 | class Formatter | |
86 | include ActionView::Helpers::TagHelper |
|
140 | include ActionView::Helpers::TagHelper | |
87 | include ActionView::Helpers::TextHelper |
|
141 | include ActionView::Helpers::TextHelper | |
88 | include ActionView::Helpers::UrlHelper |
|
142 | include ActionView::Helpers::UrlHelper | |
|
143 | include Redmine::WikiFormatting::LinksHelper | |||
89 |
|
144 | |||
90 | def initialize(text) |
|
145 | def initialize(text) | |
91 | @text = text |
|
146 | @text = text | |
92 | end |
|
147 | end | |
93 |
|
148 | |||
94 | def to_html(*args) |
|
149 | def to_html(*args) | |
95 |
|
|
150 | t = CGI::escapeHTML(@text) | |
|
151 | auto_link!(t) | |||
|
152 | auto_mailto!(t) | |||
|
153 | simple_format(t) | |||
96 | end |
|
154 | end | |
97 | end |
|
155 | end | |
98 |
|
156 |
@@ -23,6 +23,10 module Redmine | |||||
23 | module Textile |
|
23 | module Textile | |
24 | class Formatter < RedCloth3 |
|
24 | class Formatter < RedCloth3 | |
25 | include ActionView::Helpers::TagHelper |
|
25 | include ActionView::Helpers::TagHelper | |
|
26 | include Redmine::WikiFormatting::LinksHelper | |||
|
27 | ||||
|
28 | alias :inline_auto_link :auto_link! | |||
|
29 | alias :inline_auto_mailto :auto_mailto! | |||
26 |
|
30 | |||
27 | # auto_link rule after textile rules so that it doesn't break !image_url! tags |
|
31 | # auto_link rule after textile rules so that it doesn't break !image_url! tags | |
28 | RULES = [:textile, :block_markdown_rule, :inline_auto_link, :inline_auto_mailto] |
|
32 | RULES = [:textile, :block_markdown_rule, :inline_auto_link, :inline_auto_mailto] | |
@@ -124,58 +128,6 module Redmine | |||||
124 | end |
|
128 | end | |
125 | end |
|
129 | end | |
126 | end |
|
130 | end | |
127 |
|
||||
128 | AUTO_LINK_RE = %r{ |
|
|||
129 | ( # leading text |
|
|||
130 | <\w+.*?>| # leading HTML tag, or |
|
|||
131 | [^=<>!:'"/]| # leading punctuation, or |
|
|||
132 | ^ # beginning of line |
|
|||
133 | ) |
|
|||
134 | ( |
|
|||
135 | (?:https?://)| # protocol spec, or |
|
|||
136 | (?:s?ftps?://)| |
|
|||
137 | (?:www\.) # www.* |
|
|||
138 | ) |
|
|||
139 | ( |
|
|||
140 | (\S+?) # url |
|
|||
141 | (\/)? # slash |
|
|||
142 | ) |
|
|||
143 | ((?:>)?|[^\w\=\/;\(\)]*?) # post |
|
|||
144 | (?=<|\s|$) |
|
|||
145 | }x unless const_defined?(:AUTO_LINK_RE) |
|
|||
146 |
|
||||
147 | # Turns all urls into clickable links (code from Rails). |
|
|||
148 | def inline_auto_link(text) |
|
|||
149 | text.gsub!(AUTO_LINK_RE) do |
|
|||
150 | all, leading, proto, url, post = $&, $1, $2, $3, $6 |
|
|||
151 | if leading =~ /<a\s/i || leading =~ /![<>=]?/ |
|
|||
152 | # don't replace URL's that are already linked |
|
|||
153 | # and URL's prefixed with ! !> !< != (textile images) |
|
|||
154 | all |
|
|||
155 | else |
|
|||
156 | # Idea below : an URL with unbalanced parethesis and |
|
|||
157 | # ending by ')' is put into external parenthesis |
|
|||
158 | if ( url[-1]==?) and ((url.count("(") - url.count(")")) < 0 ) ) |
|
|||
159 | url=url[0..-2] # discard closing parenth from url |
|
|||
160 | post = ")"+post # add closing parenth to post |
|
|||
161 | end |
|
|||
162 | tag = content_tag('a', proto + url, :href => "#{proto=="www."?"http://www.":proto}#{url}", :class => 'external') |
|
|||
163 | %(#{leading}#{tag}#{post}) |
|
|||
164 | end |
|
|||
165 | end |
|
|||
166 | end |
|
|||
167 |
|
||||
168 | # Turns all email addresses into clickable links (code from Rails). |
|
|||
169 | def inline_auto_mailto(text) |
|
|||
170 | text.gsub!(/([\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do |
|
|||
171 | mail = $1 |
|
|||
172 | if text.match(/<a\b[^>]*>(.*)(#{Regexp.escape(mail)})(.*)<\/a>/) |
|
|||
173 |
|
||||
174 | else |
|
|||
175 | content_tag('a', mail, :href => "mailto:#{mail}", :class => "email") |
|
|||
176 | end |
|
|||
177 | end |
|
|||
178 | end |
|
|||
179 | end |
|
131 | end | |
180 | end |
|
132 | end | |
181 | end |
|
133 | end |
@@ -940,7 +940,7 RAW | |||||
940 | def test_default_formatter |
|
940 | def test_default_formatter | |
941 | with_settings :text_formatting => 'unknown' do |
|
941 | with_settings :text_formatting => 'unknown' do | |
942 | text = 'a *link*: http://www.example.net/' |
|
942 | text = 'a *link*: http://www.example.net/' | |
943 | assert_equal '<p>a *link*: <a href="http://www.example.net/">http://www.example.net/</a></p>', textilizable(text) |
|
943 | assert_equal '<p>a *link*: <a class="external" href="http://www.example.net/">http://www.example.net/</a></p>', textilizable(text) | |
944 | end |
|
944 | end | |
945 | end |
|
945 | end | |
946 |
|
946 |
@@ -36,8 +36,8 and an email address foo@example.net | |||||
36 | DIFF |
|
36 | DIFF | |
37 |
|
37 | |||
38 | expected = <<-EXPECTED |
|
38 | expected = <<-EXPECTED | |
39 | <p>This is a sample *text* with a link: <a href="http://www.redmine.org">http://www.redmine.org</a><br /> |
|
39 | <p>This is a sample *text* with a link: <a class="external" href="http://www.redmine.org">http://www.redmine.org</a><br /> | |
40 | and an email address <a href="mailto:foo@example.net">foo@example.net</a></p> |
|
40 | and an email address <a class="email" href="mailto:foo@example.net">foo@example.net</a></p> | |
41 | EXPECTED |
|
41 | EXPECTED | |
42 |
|
42 | |||
43 | assert_equal expected.gsub(%r{[\r\n\t]}, ''), Redmine::WikiFormatting::NullFormatter::Formatter.new(raw).to_html.gsub(%r{[\r\n\t]}, '') |
|
43 | assert_equal expected.gsub(%r{[\r\n\t]}, ''), Redmine::WikiFormatting::NullFormatter::Formatter.new(raw).to_html.gsub(%r{[\r\n\t]}, '') |
General Comments 0
You need to be logged in to leave comments.
Login now