20 |
20 |
|
21 |
21 |
module Redmine
|
22 |
22 |
module WikiFormatting
|
23 |
|
|
24 |
|
private
|
25 |
|
|
|
23 |
|
|
24 |
private
|
|
25 |
|
26 |
26 |
class TextileFormatter < RedCloth
|
27 |
27 |
|
28 |
28 |
# auto_link rule after textile rules so that it doesn't break !image_url! tags
|
... | ... | |
39 |
39 |
@macros_runner = block
|
40 |
40 |
super(*RULES).to_s
|
41 |
41 |
end
|
42 |
|
|
43 |
|
private
|
44 |
|
|
|
42 |
|
|
43 |
private
|
|
44 |
|
45 |
45 |
# Patch for RedCloth. Fixed in RedCloth r128 but _why hasn't released it yet.
|
46 |
46 |
# <a href="http://code.whytheluckystiff.net/redcloth/changeset/128">http://code.whytheluckystiff.net/redcloth/changeset/128</a>
|
47 |
47 |
def hard_break( text )
|
... | ... | |
71 |
71 |
content = "<a name=\"#{@toc.length}\" class=\"wiki-page\"></a>" + content
|
72 |
72 |
textile_p(tag, atts, cite, content)
|
73 |
73 |
end
|
74 |
|
|
|
74 |
|
75 |
75 |
alias :textile_h1 :textile_p_withtoc
|
76 |
76 |
alias :textile_h2 :textile_p_withtoc
|
77 |
77 |
alias :textile_h3 :textile_p_withtoc
|
... | ... | |
121 |
121 |
end
|
122 |
122 |
end
|
123 |
123 |
|
|
124 |
|
|
125 |
|
124 |
126 |
AUTO_LINK_RE = %r{
|
125 |
|
( # leading text
|
126 |
|
<\w+.*?>| # leading HTML tag, or
|
127 |
|
[^=<>!:'"/]| # leading punctuation, or
|
128 |
|
^ # beginning of line
|
129 |
|
)
|
130 |
|
(
|
131 |
|
(?:https?://)| # protocol spec, or
|
132 |
|
(?:ftp://)|
|
133 |
|
(?:www\.) # www.*
|
134 |
|
)
|
135 |
|
(
|
136 |
|
(\S+?) # url
|
137 |
|
(\/)? # slash
|
138 |
|
)
|
139 |
|
([^\w\=\/;]*?) # post
|
140 |
|
(?=<|\s|$)
|
141 |
|
}x unless const_defined?(:AUTO_LINK_RE)
|
|
127 |
( # leading text
|
|
128 |
<\w+.*?>| # leading HTML tag, or
|
|
129 |
[^=!:'"/]| # leading punctuation, or
|
|
130 |
^ # beginning of line
|
|
131 |
)
|
|
132 |
(
|
|
133 |
(?:https?://)| # protocol spec, or
|
|
134 |
(?:www\.)|
|
|
135 |
(?:ftp://) # www.*
|
|
136 |
)
|
|
137 |
(
|
|
138 |
(?:[-_.\w]+(?::[^@\s]+)?@)? # username:password@
|
|
139 |
[-\w]+ # subdomain or domain
|
|
140 |
(?:\.[-\w]+)* # remaining subdomains or domain
|
|
141 |
(?::\d+)? # port
|
|
142 |
(?:/(?:(?:[~\w\+@%=\(\)-]|(?:[,.;:'][^\s$]))+)?)* # path
|
|
143 |
(?:\?[\w\+@%&=.;-]+)? # query string
|
|
144 |
(?:\#[\w\-_:.]*[\w])? # trailing anchor
|
|
145 |
)
|
|
146 |
([[:punct:]]|<|$|) # trailing text
|
|
147 |
}x unless const_defined?(:AUTO_LINK_RE)
|
|
148 |
|
142 |
149 |
|
143 |
|
# Turns all urls into clickable links (code from Rails).
|
|
150 |
|
|
151 |
|
|
152 |
|
|
153 |
# Turns all urls into clickable links.
|
144 |
154 |
def inline_auto_link(text)
|
145 |
155 |
text.gsub!(AUTO_LINK_RE) do
|
146 |
|
all, leading, proto, url, post = $&, $1, $2, $3, $6
|
147 |
|
if leading =~ /<a\s/i || leading =~ /![<>=]?/
|
|
156 |
all, a, b, c, d = $&, $1, $2, $3, $4
|
|
157 |
if a =~ /<a\s/i || a =~ /![<>=]?/
|
148 |
158 |
# don't replace URL's that are already linked
|
149 |
|
# and URL's prefixed with ! !> !< != (textile images)
|
150 |
159 |
all
|
151 |
|
else
|
152 |
|
%(#{leading}<a class="external" href="#{proto=="www."?"http://www.":proto}#{url}">#{proto + url}</a>#{post})
|
|
160 |
else
|
|
161 |
text = b + c
|
|
162 |
%(#{a}<a class="external" href="#{b=="www."?"http://www.":b}#{c}">#{text}</a>#{d})
|
153 |
163 |
end
|
154 |
164 |
end
|
155 |
165 |
end
|
156 |
166 |
|
|
167 |
|
157 |
168 |
# Turns all email addresses into clickable links (code from Rails).
|
158 |
169 |
def inline_auto_mailto(text)
|
159 |
170 |
text.gsub!(/([\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do
|
... | ... | |
167 |
178 |
end
|
168 |
179 |
end
|
169 |
180 |
|
170 |
|
public
|
171 |
|
|
|
181 |
public
|
|
182 |
|
172 |
183 |
def self.to_html(text, options = {}, &block)
|
173 |
184 |
TextileFormatter.new(text).to_html(&block)
|
174 |
185 |
end
|