##// END OF EJS Templates
Small fix to the Redmine links regexp....
Jean-Philippe Lang -
r1253:030afe742816
parent child
Show More
@@ -1,487 +1,487
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 module ApplicationHelper
18 module ApplicationHelper
19 include Redmine::WikiFormatting::Macros::Definitions
19 include Redmine::WikiFormatting::Macros::Definitions
20
20
21 def current_role
21 def current_role
22 @current_role ||= User.current.role_for_project(@project)
22 @current_role ||= User.current.role_for_project(@project)
23 end
23 end
24
24
25 # Return true if user is authorized for controller/action, otherwise false
25 # Return true if user is authorized for controller/action, otherwise false
26 def authorize_for(controller, action)
26 def authorize_for(controller, action)
27 User.current.allowed_to?({:controller => controller, :action => action}, @project)
27 User.current.allowed_to?({:controller => controller, :action => action}, @project)
28 end
28 end
29
29
30 # Display a link if user is authorized
30 # Display a link if user is authorized
31 def link_to_if_authorized(name, options = {}, html_options = nil, *parameters_for_method_reference)
31 def link_to_if_authorized(name, options = {}, html_options = nil, *parameters_for_method_reference)
32 link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for(options[:controller] || params[:controller], options[:action])
32 link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for(options[:controller] || params[:controller], options[:action])
33 end
33 end
34
34
35 # Display a link to user's account page
35 # Display a link to user's account page
36 def link_to_user(user)
36 def link_to_user(user)
37 user ? link_to(user, :controller => 'account', :action => 'show', :id => user) : 'Anonymous'
37 user ? link_to(user, :controller => 'account', :action => 'show', :id => user) : 'Anonymous'
38 end
38 end
39
39
40 def link_to_issue(issue, options={})
40 def link_to_issue(issue, options={})
41 link_to "#{issue.tracker.name} ##{issue.id}", {:controller => "issues", :action => "show", :id => issue}, options
41 link_to "#{issue.tracker.name} ##{issue.id}", {:controller => "issues", :action => "show", :id => issue}, options
42 end
42 end
43
43
44 def toggle_link(name, id, options={})
44 def toggle_link(name, id, options={})
45 onclick = "Element.toggle('#{id}'); "
45 onclick = "Element.toggle('#{id}'); "
46 onclick << (options[:focus] ? "Form.Element.focus('#{options[:focus]}'); " : "this.blur(); ")
46 onclick << (options[:focus] ? "Form.Element.focus('#{options[:focus]}'); " : "this.blur(); ")
47 onclick << "return false;"
47 onclick << "return false;"
48 link_to(name, "#", :onclick => onclick)
48 link_to(name, "#", :onclick => onclick)
49 end
49 end
50
50
51 def show_and_goto_link(name, id, options={})
51 def show_and_goto_link(name, id, options={})
52 onclick = "Element.show('#{id}'); "
52 onclick = "Element.show('#{id}'); "
53 onclick << (options[:focus] ? "Form.Element.focus('#{options[:focus]}'); " : "this.blur(); ")
53 onclick << (options[:focus] ? "Form.Element.focus('#{options[:focus]}'); " : "this.blur(); ")
54 onclick << "Element.scrollTo('#{id}'); "
54 onclick << "Element.scrollTo('#{id}'); "
55 onclick << "return false;"
55 onclick << "return false;"
56 link_to(name, "#", options.merge(:onclick => onclick))
56 link_to(name, "#", options.merge(:onclick => onclick))
57 end
57 end
58
58
59 def image_to_function(name, function, html_options = {})
59 def image_to_function(name, function, html_options = {})
60 html_options.symbolize_keys!
60 html_options.symbolize_keys!
61 tag(:input, html_options.merge({
61 tag(:input, html_options.merge({
62 :type => "image", :src => image_path(name),
62 :type => "image", :src => image_path(name),
63 :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};"
63 :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};"
64 }))
64 }))
65 end
65 end
66
66
67 def prompt_to_remote(name, text, param, url, html_options = {})
67 def prompt_to_remote(name, text, param, url, html_options = {})
68 html_options[:onclick] = "promptToRemote('#{text}', '#{param}', '#{url_for(url)}'); return false;"
68 html_options[:onclick] = "promptToRemote('#{text}', '#{param}', '#{url_for(url)}'); return false;"
69 link_to name, {}, html_options
69 link_to name, {}, html_options
70 end
70 end
71
71
72 def format_date(date)
72 def format_date(date)
73 return nil unless date
73 return nil unless date
74 # "Setting.date_format.size < 2" is a temporary fix (content of date_format setting changed)
74 # "Setting.date_format.size < 2" is a temporary fix (content of date_format setting changed)
75 @date_format ||= (Setting.date_format.blank? || Setting.date_format.size < 2 ? l(:general_fmt_date) : Setting.date_format)
75 @date_format ||= (Setting.date_format.blank? || Setting.date_format.size < 2 ? l(:general_fmt_date) : Setting.date_format)
76 date.strftime(@date_format)
76 date.strftime(@date_format)
77 end
77 end
78
78
79 def format_time(time, include_date = true)
79 def format_time(time, include_date = true)
80 return nil unless time
80 return nil unless time
81 time = time.to_time if time.is_a?(String)
81 time = time.to_time if time.is_a?(String)
82 zone = User.current.time_zone
82 zone = User.current.time_zone
83 if time.utc?
83 if time.utc?
84 local = zone ? zone.adjust(time) : time.getlocal
84 local = zone ? zone.adjust(time) : time.getlocal
85 else
85 else
86 local = zone ? zone.adjust(time.getutc) : time
86 local = zone ? zone.adjust(time.getutc) : time
87 end
87 end
88 @date_format ||= (Setting.date_format.blank? || Setting.date_format.size < 2 ? l(:general_fmt_date) : Setting.date_format)
88 @date_format ||= (Setting.date_format.blank? || Setting.date_format.size < 2 ? l(:general_fmt_date) : Setting.date_format)
89 @time_format ||= (Setting.time_format.blank? ? l(:general_fmt_time) : Setting.time_format)
89 @time_format ||= (Setting.time_format.blank? ? l(:general_fmt_time) : Setting.time_format)
90 include_date ? local.strftime("#{@date_format} #{@time_format}") : local.strftime(@time_format)
90 include_date ? local.strftime("#{@date_format} #{@time_format}") : local.strftime(@time_format)
91 end
91 end
92
92
93 def html_hours(text)
93 def html_hours(text)
94 text.gsub(%r{(\d+)\.(\d+)}, '<span class="hours hours-int">\1</span><span class="hours hours-dec">.\2</span>')
94 text.gsub(%r{(\d+)\.(\d+)}, '<span class="hours hours-int">\1</span><span class="hours hours-dec">.\2</span>')
95 end
95 end
96
96
97 def authoring(created, author)
97 def authoring(created, author)
98 time_tag = content_tag('acronym', distance_of_time_in_words(Time.now, created), :title => format_time(created))
98 time_tag = content_tag('acronym', distance_of_time_in_words(Time.now, created), :title => format_time(created))
99 l(:label_added_time_by, author || 'Anonymous', time_tag)
99 l(:label_added_time_by, author || 'Anonymous', time_tag)
100 end
100 end
101
101
102 def l_or_humanize(s)
102 def l_or_humanize(s)
103 l_has_string?("label_#{s}".to_sym) ? l("label_#{s}".to_sym) : s.to_s.humanize
103 l_has_string?("label_#{s}".to_sym) ? l("label_#{s}".to_sym) : s.to_s.humanize
104 end
104 end
105
105
106 def day_name(day)
106 def day_name(day)
107 l(:general_day_names).split(',')[day-1]
107 l(:general_day_names).split(',')[day-1]
108 end
108 end
109
109
110 def month_name(month)
110 def month_name(month)
111 l(:actionview_datehelper_select_month_names).split(',')[month-1]
111 l(:actionview_datehelper_select_month_names).split(',')[month-1]
112 end
112 end
113
113
114 def pagination_links_full(paginator, count=nil, options={})
114 def pagination_links_full(paginator, count=nil, options={})
115 page_param = options.delete(:page_param) || :page
115 page_param = options.delete(:page_param) || :page
116 url_param = params.dup
116 url_param = params.dup
117 # don't reuse params if filters are present
117 # don't reuse params if filters are present
118 url_param.clear if url_param.has_key?(:set_filter)
118 url_param.clear if url_param.has_key?(:set_filter)
119
119
120 html = ''
120 html = ''
121 html << link_to_remote(('&#171; ' + l(:label_previous)),
121 html << link_to_remote(('&#171; ' + l(:label_previous)),
122 {:update => 'content',
122 {:update => 'content',
123 :url => url_param.merge(page_param => paginator.current.previous),
123 :url => url_param.merge(page_param => paginator.current.previous),
124 :complete => 'window.scrollTo(0,0)'},
124 :complete => 'window.scrollTo(0,0)'},
125 {:href => url_for(:params => url_param.merge(page_param => paginator.current.previous))}) + ' ' if paginator.current.previous
125 {:href => url_for(:params => url_param.merge(page_param => paginator.current.previous))}) + ' ' if paginator.current.previous
126
126
127 html << (pagination_links_each(paginator, options) do |n|
127 html << (pagination_links_each(paginator, options) do |n|
128 link_to_remote(n.to_s,
128 link_to_remote(n.to_s,
129 {:url => {:params => url_param.merge(page_param => n)},
129 {:url => {:params => url_param.merge(page_param => n)},
130 :update => 'content',
130 :update => 'content',
131 :complete => 'window.scrollTo(0,0)'},
131 :complete => 'window.scrollTo(0,0)'},
132 {:href => url_for(:params => url_param.merge(page_param => n))})
132 {:href => url_for(:params => url_param.merge(page_param => n))})
133 end || '')
133 end || '')
134
134
135 html << ' ' + link_to_remote((l(:label_next) + ' &#187;'),
135 html << ' ' + link_to_remote((l(:label_next) + ' &#187;'),
136 {:update => 'content',
136 {:update => 'content',
137 :url => url_param.merge(page_param => paginator.current.next),
137 :url => url_param.merge(page_param => paginator.current.next),
138 :complete => 'window.scrollTo(0,0)'},
138 :complete => 'window.scrollTo(0,0)'},
139 {:href => url_for(:params => url_param.merge(page_param => paginator.current.next))}) if paginator.current.next
139 {:href => url_for(:params => url_param.merge(page_param => paginator.current.next))}) if paginator.current.next
140
140
141 unless count.nil?
141 unless count.nil?
142 html << [" (#{paginator.current.first_item}-#{paginator.current.last_item}/#{count})", per_page_links(paginator.items_per_page)].compact.join(' | ')
142 html << [" (#{paginator.current.first_item}-#{paginator.current.last_item}/#{count})", per_page_links(paginator.items_per_page)].compact.join(' | ')
143 end
143 end
144
144
145 html
145 html
146 end
146 end
147
147
148 def per_page_links(selected=nil)
148 def per_page_links(selected=nil)
149 url_param = params.dup
149 url_param = params.dup
150 url_param.clear if url_param.has_key?(:set_filter)
150 url_param.clear if url_param.has_key?(:set_filter)
151
151
152 links = Setting.per_page_options_array.collect do |n|
152 links = Setting.per_page_options_array.collect do |n|
153 n == selected ? n : link_to_remote(n, {:update => "content", :url => params.dup.merge(:per_page => n)},
153 n == selected ? n : link_to_remote(n, {:update => "content", :url => params.dup.merge(:per_page => n)},
154 {:href => url_for(url_param.merge(:per_page => n))})
154 {:href => url_for(url_param.merge(:per_page => n))})
155 end
155 end
156 links.size > 1 ? l(:label_display_per_page, links.join(', ')) : nil
156 links.size > 1 ? l(:label_display_per_page, links.join(', ')) : nil
157 end
157 end
158
158
159 def html_title(*args)
159 def html_title(*args)
160 if args.empty?
160 if args.empty?
161 title = []
161 title = []
162 title << @project.name if @project
162 title << @project.name if @project
163 title += @html_title if @html_title
163 title += @html_title if @html_title
164 title << Setting.app_title
164 title << Setting.app_title
165 title.compact.join(' - ')
165 title.compact.join(' - ')
166 else
166 else
167 @html_title ||= []
167 @html_title ||= []
168 @html_title += args
168 @html_title += args
169 end
169 end
170 end
170 end
171
171
172 def accesskey(s)
172 def accesskey(s)
173 Redmine::AccessKeys.key_for s
173 Redmine::AccessKeys.key_for s
174 end
174 end
175
175
176 # Formats text according to system settings.
176 # Formats text according to system settings.
177 # 2 ways to call this method:
177 # 2 ways to call this method:
178 # * with a String: textilizable(text, options)
178 # * with a String: textilizable(text, options)
179 # * with an object and one of its attribute: textilizable(issue, :description, options)
179 # * with an object and one of its attribute: textilizable(issue, :description, options)
180 def textilizable(*args)
180 def textilizable(*args)
181 options = args.last.is_a?(Hash) ? args.pop : {}
181 options = args.last.is_a?(Hash) ? args.pop : {}
182 case args.size
182 case args.size
183 when 1
183 when 1
184 obj = nil
184 obj = nil
185 text = args.shift
185 text = args.shift
186 when 2
186 when 2
187 obj = args.shift
187 obj = args.shift
188 text = obj.send(args.shift).to_s
188 text = obj.send(args.shift).to_s
189 else
189 else
190 raise ArgumentError, 'invalid arguments to textilizable'
190 raise ArgumentError, 'invalid arguments to textilizable'
191 end
191 end
192 return '' if text.blank?
192 return '' if text.blank?
193
193
194 only_path = options.delete(:only_path) == false ? false : true
194 only_path = options.delete(:only_path) == false ? false : true
195
195
196 # when using an image link, try to use an attachment, if possible
196 # when using an image link, try to use an attachment, if possible
197 attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil)
197 attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil)
198
198
199 if attachments
199 if attachments
200 text = text.gsub(/!((\<|\=|\>)?(\([^\)]+\))?(\[[^\]]+\])?(\{[^\}]+\})?)(\S+\.(gif|jpg|jpeg|png))!/) do |m|
200 text = text.gsub(/!((\<|\=|\>)?(\([^\)]+\))?(\[[^\]]+\])?(\{[^\}]+\})?)(\S+\.(gif|jpg|jpeg|png))!/) do |m|
201 style = $1
201 style = $1
202 filename = $6
202 filename = $6
203 rf = Regexp.new(filename, Regexp::IGNORECASE)
203 rf = Regexp.new(filename, Regexp::IGNORECASE)
204 # search for the picture in attachments
204 # search for the picture in attachments
205 if found = attachments.detect { |att| att.filename =~ rf }
205 if found = attachments.detect { |att| att.filename =~ rf }
206 image_url = url_for :only_path => only_path, :controller => 'attachments', :action => 'download', :id => found.id
206 image_url = url_for :only_path => only_path, :controller => 'attachments', :action => 'download', :id => found.id
207 "!#{style}#{image_url}!"
207 "!#{style}#{image_url}!"
208 else
208 else
209 "!#{style}#{filename}!"
209 "!#{style}#{filename}!"
210 end
210 end
211 end
211 end
212 end
212 end
213
213
214 text = (Setting.text_formatting == 'textile') ?
214 text = (Setting.text_formatting == 'textile') ?
215 Redmine::WikiFormatting.to_html(text) { |macro, args| exec_macro(macro, obj, args) } :
215 Redmine::WikiFormatting.to_html(text) { |macro, args| exec_macro(macro, obj, args) } :
216 simple_format(auto_link(h(text)))
216 simple_format(auto_link(h(text)))
217
217
218 # different methods for formatting wiki links
218 # different methods for formatting wiki links
219 case options[:wiki_links]
219 case options[:wiki_links]
220 when :local
220 when :local
221 # used for local links to html files
221 # used for local links to html files
222 format_wiki_link = Proc.new {|project, title| "#{title}.html" }
222 format_wiki_link = Proc.new {|project, title| "#{title}.html" }
223 when :anchor
223 when :anchor
224 # used for single-file wiki export
224 # used for single-file wiki export
225 format_wiki_link = Proc.new {|project, title| "##{title}" }
225 format_wiki_link = Proc.new {|project, title| "##{title}" }
226 else
226 else
227 format_wiki_link = Proc.new {|project, title| url_for(:only_path => only_path, :controller => 'wiki', :action => 'index', :id => project, :page => title) }
227 format_wiki_link = Proc.new {|project, title| url_for(:only_path => only_path, :controller => 'wiki', :action => 'index', :id => project, :page => title) }
228 end
228 end
229
229
230 project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil)
230 project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil)
231
231
232 # Wiki links
232 # Wiki links
233 #
233 #
234 # Examples:
234 # Examples:
235 # [[mypage]]
235 # [[mypage]]
236 # [[mypage|mytext]]
236 # [[mypage|mytext]]
237 # wiki links can refer other project wikis, using project name or identifier:
237 # wiki links can refer other project wikis, using project name or identifier:
238 # [[project:]] -> wiki starting page
238 # [[project:]] -> wiki starting page
239 # [[project:|mytext]]
239 # [[project:|mytext]]
240 # [[project:mypage]]
240 # [[project:mypage]]
241 # [[project:mypage|mytext]]
241 # [[project:mypage|mytext]]
242 text = text.gsub(/(!)?(\[\[([^\]\|]+)(\|([^\]\|]+))?\]\])/) do |m|
242 text = text.gsub(/(!)?(\[\[([^\]\|]+)(\|([^\]\|]+))?\]\])/) do |m|
243 link_project = project
243 link_project = project
244 esc, all, page, title = $1, $2, $3, $5
244 esc, all, page, title = $1, $2, $3, $5
245 if esc.nil?
245 if esc.nil?
246 if page =~ /^([^\:]+)\:(.*)$/
246 if page =~ /^([^\:]+)\:(.*)$/
247 link_project = Project.find_by_name($1) || Project.find_by_identifier($1)
247 link_project = Project.find_by_name($1) || Project.find_by_identifier($1)
248 page = $2
248 page = $2
249 title ||= $1 if page.blank?
249 title ||= $1 if page.blank?
250 end
250 end
251
251
252 if link_project && link_project.wiki
252 if link_project && link_project.wiki
253 # check if page exists
253 # check if page exists
254 wiki_page = link_project.wiki.find_page(page)
254 wiki_page = link_project.wiki.find_page(page)
255 link_to((title || page), format_wiki_link.call(link_project, Wiki.titleize(page)),
255 link_to((title || page), format_wiki_link.call(link_project, Wiki.titleize(page)),
256 :class => ('wiki-page' + (wiki_page ? '' : ' new')))
256 :class => ('wiki-page' + (wiki_page ? '' : ' new')))
257 else
257 else
258 # project or wiki doesn't exist
258 # project or wiki doesn't exist
259 title || page
259 title || page
260 end
260 end
261 else
261 else
262 all
262 all
263 end
263 end
264 end
264 end
265
265
266 # Redmine links
266 # Redmine links
267 #
267 #
268 # Examples:
268 # Examples:
269 # Issues:
269 # Issues:
270 # #52 -> Link to issue #52
270 # #52 -> Link to issue #52
271 # Changesets:
271 # Changesets:
272 # r52 -> Link to revision 52
272 # r52 -> Link to revision 52
273 # commit:a85130f -> Link to scmid starting with a85130f
273 # commit:a85130f -> Link to scmid starting with a85130f
274 # Documents:
274 # Documents:
275 # document#17 -> Link to document with id 17
275 # document#17 -> Link to document with id 17
276 # document:Greetings -> Link to the document with title "Greetings"
276 # document:Greetings -> Link to the document with title "Greetings"
277 # document:"Some document" -> Link to the document with title "Some document"
277 # document:"Some document" -> Link to the document with title "Some document"
278 # Versions:
278 # Versions:
279 # version#3 -> Link to version with id 3
279 # version#3 -> Link to version with id 3
280 # version:1.0.0 -> Link to version named "1.0.0"
280 # version:1.0.0 -> Link to version named "1.0.0"
281 # version:"1.0 beta 2" -> Link to version named "1.0 beta 2"
281 # version:"1.0 beta 2" -> Link to version named "1.0 beta 2"
282 # Attachments:
282 # Attachments:
283 # attachment:file.zip -> Link to the attachment of the current object named file.zip
283 # attachment:file.zip -> Link to the attachment of the current object named file.zip
284 # Source files:
284 # Source files:
285 # source:some/file -> Link to the file located at /some/file in the project's repository
285 # source:some/file -> Link to the file located at /some/file in the project's repository
286 # source:some/file@52 -> Link to the file's revision 52
286 # source:some/file@52 -> Link to the file's revision 52
287 # source:some/file#L120 -> Link to line 120 of the file
287 # source:some/file#L120 -> Link to line 120 of the file
288 # source:some/file@52#L120 -> Link to line 120 of the file's revision 52
288 # source:some/file@52#L120 -> Link to line 120 of the file's revision 52
289 # export:some/file -> Force the download of the file
289 # export:some/file -> Force the download of the file
290 text = text.gsub(%r{([\s\(,-^])(!)?(attachment|document|version|commit|source|export)?((#|r)(\d+)|(:)([^"][^\s<>]+|"[^"]+"))(?=[[:punct:]]|\s|<|$)}) do |m|
290 text = text.gsub(%r{([\s\(,-^])(!)?(attachment|document|version|commit|source|export)?((#|r)(\d+)|(:)([^"\s<>][^\s<>]*|"[^"]+"))(?=[[:punct:]]|\s|<|$)}) do |m|
291 leading, esc, prefix, sep, oid = $1, $2, $3, $5 || $7, $6 || $8
291 leading, esc, prefix, sep, oid = $1, $2, $3, $5 || $7, $6 || $8
292 link = nil
292 link = nil
293 if esc.nil?
293 if esc.nil?
294 if prefix.nil? && sep == 'r'
294 if prefix.nil? && sep == 'r'
295 if project && (changeset = project.changesets.find_by_revision(oid))
295 if project && (changeset = project.changesets.find_by_revision(oid))
296 link = link_to("r#{oid}", {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => oid},
296 link = link_to("r#{oid}", {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => oid},
297 :class => 'changeset',
297 :class => 'changeset',
298 :title => truncate(changeset.comments, 100))
298 :title => truncate(changeset.comments, 100))
299 end
299 end
300 elsif sep == '#'
300 elsif sep == '#'
301 oid = oid.to_i
301 oid = oid.to_i
302 case prefix
302 case prefix
303 when nil
303 when nil
304 if issue = Issue.find_by_id(oid, :include => [:project, :status], :conditions => Project.visible_by(User.current))
304 if issue = Issue.find_by_id(oid, :include => [:project, :status], :conditions => Project.visible_by(User.current))
305 link = link_to("##{oid}", {:only_path => only_path, :controller => 'issues', :action => 'show', :id => oid},
305 link = link_to("##{oid}", {:only_path => only_path, :controller => 'issues', :action => 'show', :id => oid},
306 :class => (issue.closed? ? 'issue closed' : 'issue'),
306 :class => (issue.closed? ? 'issue closed' : 'issue'),
307 :title => "#{truncate(issue.subject, 100)} (#{issue.status.name})")
307 :title => "#{truncate(issue.subject, 100)} (#{issue.status.name})")
308 link = content_tag('del', link) if issue.closed?
308 link = content_tag('del', link) if issue.closed?
309 end
309 end
310 when 'document'
310 when 'document'
311 if document = Document.find_by_id(oid, :include => [:project], :conditions => Project.visible_by(User.current))
311 if document = Document.find_by_id(oid, :include => [:project], :conditions => Project.visible_by(User.current))
312 link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},
312 link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},
313 :class => 'document'
313 :class => 'document'
314 end
314 end
315 when 'version'
315 when 'version'
316 if version = Version.find_by_id(oid, :include => [:project], :conditions => Project.visible_by(User.current))
316 if version = Version.find_by_id(oid, :include => [:project], :conditions => Project.visible_by(User.current))
317 link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
317 link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
318 :class => 'version'
318 :class => 'version'
319 end
319 end
320 end
320 end
321 elsif sep == ':'
321 elsif sep == ':'
322 # removes the double quotes if any
322 # removes the double quotes if any
323 name = oid.gsub(%r{^"(.*)"$}, "\\1")
323 name = oid.gsub(%r{^"(.*)"$}, "\\1")
324 case prefix
324 case prefix
325 when 'document'
325 when 'document'
326 if project && document = project.documents.find_by_title(name)
326 if project && document = project.documents.find_by_title(name)
327 link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},
327 link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},
328 :class => 'document'
328 :class => 'document'
329 end
329 end
330 when 'version'
330 when 'version'
331 if project && version = project.versions.find_by_name(name)
331 if project && version = project.versions.find_by_name(name)
332 link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
332 link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
333 :class => 'version'
333 :class => 'version'
334 end
334 end
335 when 'commit'
335 when 'commit'
336 if project && (changeset = project.changesets.find(:first, :conditions => ["scmid LIKE ?", "#{name}%"]))
336 if project && (changeset = project.changesets.find(:first, :conditions => ["scmid LIKE ?", "#{name}%"]))
337 link = link_to h("#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.revision}, :class => 'changeset', :title => truncate(changeset.comments, 100)
337 link = link_to h("#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.revision}, :class => 'changeset', :title => truncate(changeset.comments, 100)
338 end
338 end
339 when 'source', 'export'
339 when 'source', 'export'
340 if project && project.repository
340 if project && project.repository
341 name =~ %r{^[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?$}
341 name =~ %r{^[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?$}
342 path, rev, anchor = $1, $3, $5
342 path, rev, anchor = $1, $3, $5
343 link = link_to h("#{prefix}:#{name}"), {:controller => 'repositories', :action => 'entry', :id => project, :path => path,
343 link = link_to h("#{prefix}:#{name}"), {:controller => 'repositories', :action => 'entry', :id => project, :path => path,
344 :rev => rev,
344 :rev => rev,
345 :anchor => anchor,
345 :anchor => anchor,
346 :format => (prefix == 'export' ? 'raw' : nil)},
346 :format => (prefix == 'export' ? 'raw' : nil)},
347 :class => (prefix == 'export' ? 'source download' : 'source')
347 :class => (prefix == 'export' ? 'source download' : 'source')
348 end
348 end
349 when 'attachment'
349 when 'attachment'
350 if attachments && attachment = attachments.detect {|a| a.filename == name }
350 if attachments && attachment = attachments.detect {|a| a.filename == name }
351 link = link_to h(attachment.filename), {:only_path => only_path, :controller => 'attachments', :action => 'download', :id => attachment},
351 link = link_to h(attachment.filename), {:only_path => only_path, :controller => 'attachments', :action => 'download', :id => attachment},
352 :class => 'attachment'
352 :class => 'attachment'
353 end
353 end
354 end
354 end
355 end
355 end
356 end
356 end
357 leading + (link || "#{prefix}#{sep}#{oid}")
357 leading + (link || "#{prefix}#{sep}#{oid}")
358 end
358 end
359
359
360 text
360 text
361 end
361 end
362
362
363 # Same as Rails' simple_format helper without using paragraphs
363 # Same as Rails' simple_format helper without using paragraphs
364 def simple_format_without_paragraph(text)
364 def simple_format_without_paragraph(text)
365 text.to_s.
365 text.to_s.
366 gsub(/\r\n?/, "\n"). # \r\n and \r -> \n
366 gsub(/\r\n?/, "\n"). # \r\n and \r -> \n
367 gsub(/\n\n+/, "<br /><br />"). # 2+ newline -> 2 br
367 gsub(/\n\n+/, "<br /><br />"). # 2+ newline -> 2 br
368 gsub(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br
368 gsub(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br
369 end
369 end
370
370
371 def error_messages_for(object_name, options = {})
371 def error_messages_for(object_name, options = {})
372 options = options.symbolize_keys
372 options = options.symbolize_keys
373 object = instance_variable_get("@#{object_name}")
373 object = instance_variable_get("@#{object_name}")
374 if object && !object.errors.empty?
374 if object && !object.errors.empty?
375 # build full_messages here with controller current language
375 # build full_messages here with controller current language
376 full_messages = []
376 full_messages = []
377 object.errors.each do |attr, msg|
377 object.errors.each do |attr, msg|
378 next if msg.nil?
378 next if msg.nil?
379 msg = msg.first if msg.is_a? Array
379 msg = msg.first if msg.is_a? Array
380 if attr == "base"
380 if attr == "base"
381 full_messages << l(msg)
381 full_messages << l(msg)
382 else
382 else
383 full_messages << "&#171; " + (l_has_string?("field_" + attr) ? l("field_" + attr) : object.class.human_attribute_name(attr)) + " &#187; " + l(msg) unless attr == "custom_values"
383 full_messages << "&#171; " + (l_has_string?("field_" + attr) ? l("field_" + attr) : object.class.human_attribute_name(attr)) + " &#187; " + l(msg) unless attr == "custom_values"
384 end
384 end
385 end
385 end
386 # retrieve custom values error messages
386 # retrieve custom values error messages
387 if object.errors[:custom_values]
387 if object.errors[:custom_values]
388 object.custom_values.each do |v|
388 object.custom_values.each do |v|
389 v.errors.each do |attr, msg|
389 v.errors.each do |attr, msg|
390 next if msg.nil?
390 next if msg.nil?
391 msg = msg.first if msg.is_a? Array
391 msg = msg.first if msg.is_a? Array
392 full_messages << "&#171; " + v.custom_field.name + " &#187; " + l(msg)
392 full_messages << "&#171; " + v.custom_field.name + " &#187; " + l(msg)
393 end
393 end
394 end
394 end
395 end
395 end
396 content_tag("div",
396 content_tag("div",
397 content_tag(
397 content_tag(
398 options[:header_tag] || "span", lwr(:gui_validation_error, full_messages.length) + ":"
398 options[:header_tag] || "span", lwr(:gui_validation_error, full_messages.length) + ":"
399 ) +
399 ) +
400 content_tag("ul", full_messages.collect { |msg| content_tag("li", msg) }),
400 content_tag("ul", full_messages.collect { |msg| content_tag("li", msg) }),
401 "id" => options[:id] || "errorExplanation", "class" => options[:class] || "errorExplanation"
401 "id" => options[:id] || "errorExplanation", "class" => options[:class] || "errorExplanation"
402 )
402 )
403 else
403 else
404 ""
404 ""
405 end
405 end
406 end
406 end
407
407
408 def lang_options_for_select(blank=true)
408 def lang_options_for_select(blank=true)
409 (blank ? [["(auto)", ""]] : []) +
409 (blank ? [["(auto)", ""]] : []) +
410 GLoc.valid_languages.collect{|lang| [ ll(lang.to_s, :general_lang_name), lang.to_s]}.sort{|x,y| x.last <=> y.last }
410 GLoc.valid_languages.collect{|lang| [ ll(lang.to_s, :general_lang_name), lang.to_s]}.sort{|x,y| x.last <=> y.last }
411 end
411 end
412
412
413 def label_tag_for(name, option_tags = nil, options = {})
413 def label_tag_for(name, option_tags = nil, options = {})
414 label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "")
414 label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "")
415 content_tag("label", label_text)
415 content_tag("label", label_text)
416 end
416 end
417
417
418 def labelled_tabular_form_for(name, object, options, &proc)
418 def labelled_tabular_form_for(name, object, options, &proc)
419 options[:html] ||= {}
419 options[:html] ||= {}
420 options[:html][:class] = 'tabular' unless options[:html].has_key?(:class)
420 options[:html][:class] = 'tabular' unless options[:html].has_key?(:class)
421 form_for(name, object, options.merge({ :builder => TabularFormBuilder, :lang => current_language}), &proc)
421 form_for(name, object, options.merge({ :builder => TabularFormBuilder, :lang => current_language}), &proc)
422 end
422 end
423
423
424 def check_all_links(form_name)
424 def check_all_links(form_name)
425 link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") +
425 link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") +
426 " | " +
426 " | " +
427 link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)")
427 link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)")
428 end
428 end
429
429
430 def progress_bar(pcts, options={})
430 def progress_bar(pcts, options={})
431 pcts = [pcts, pcts] unless pcts.is_a?(Array)
431 pcts = [pcts, pcts] unless pcts.is_a?(Array)
432 pcts[1] = pcts[1] - pcts[0]
432 pcts[1] = pcts[1] - pcts[0]
433 pcts << (100 - pcts[1] - pcts[0])
433 pcts << (100 - pcts[1] - pcts[0])
434 width = options[:width] || '100px;'
434 width = options[:width] || '100px;'
435 legend = options[:legend] || ''
435 legend = options[:legend] || ''
436 content_tag('table',
436 content_tag('table',
437 content_tag('tr',
437 content_tag('tr',
438 (pcts[0] > 0 ? content_tag('td', '', :width => "#{pcts[0].floor}%;", :class => 'closed') : '') +
438 (pcts[0] > 0 ? content_tag('td', '', :width => "#{pcts[0].floor}%;", :class => 'closed') : '') +
439 (pcts[1] > 0 ? content_tag('td', '', :width => "#{pcts[1].floor}%;", :class => 'done') : '') +
439 (pcts[1] > 0 ? content_tag('td', '', :width => "#{pcts[1].floor}%;", :class => 'done') : '') +
440 (pcts[2] > 0 ? content_tag('td', '', :width => "#{pcts[2].floor}%;", :class => 'todo') : '')
440 (pcts[2] > 0 ? content_tag('td', '', :width => "#{pcts[2].floor}%;", :class => 'todo') : '')
441 ), :class => 'progress', :style => "width: #{width};") +
441 ), :class => 'progress', :style => "width: #{width};") +
442 content_tag('p', legend, :class => 'pourcent')
442 content_tag('p', legend, :class => 'pourcent')
443 end
443 end
444
444
445 def context_menu_link(name, url, options={})
445 def context_menu_link(name, url, options={})
446 options[:class] ||= ''
446 options[:class] ||= ''
447 if options.delete(:selected)
447 if options.delete(:selected)
448 options[:class] << ' icon-checked disabled'
448 options[:class] << ' icon-checked disabled'
449 options[:disabled] = true
449 options[:disabled] = true
450 end
450 end
451 if options.delete(:disabled)
451 if options.delete(:disabled)
452 options.delete(:method)
452 options.delete(:method)
453 options.delete(:confirm)
453 options.delete(:confirm)
454 options.delete(:onclick)
454 options.delete(:onclick)
455 options[:class] << ' disabled'
455 options[:class] << ' disabled'
456 url = '#'
456 url = '#'
457 end
457 end
458 link_to name, url, options
458 link_to name, url, options
459 end
459 end
460
460
461 def calendar_for(field_id)
461 def calendar_for(field_id)
462 image_tag("calendar.png", {:id => "#{field_id}_trigger",:class => "calendar-trigger"}) +
462 image_tag("calendar.png", {:id => "#{field_id}_trigger",:class => "calendar-trigger"}) +
463 javascript_tag("Calendar.setup({inputField : '#{field_id}', ifFormat : '%Y-%m-%d', button : '#{field_id}_trigger' });")
463 javascript_tag("Calendar.setup({inputField : '#{field_id}', ifFormat : '%Y-%m-%d', button : '#{field_id}_trigger' });")
464 end
464 end
465
465
466 def wikitoolbar_for(field_id)
466 def wikitoolbar_for(field_id)
467 return '' unless Setting.text_formatting == 'textile'
467 return '' unless Setting.text_formatting == 'textile'
468
468
469 help_link = l(:setting_text_formatting) + ': ' +
469 help_link = l(:setting_text_formatting) + ': ' +
470 link_to(l(:label_help), compute_public_path('wiki_syntax', 'help', 'html'),
470 link_to(l(:label_help), compute_public_path('wiki_syntax', 'help', 'html'),
471 :onclick => "window.open(\"#{ compute_public_path('wiki_syntax', 'help', 'html') }\", \"\", \"resizable=yes, location=no, width=300, height=640, menubar=no, status=no, scrollbars=yes\"); return false;")
471 :onclick => "window.open(\"#{ compute_public_path('wiki_syntax', 'help', 'html') }\", \"\", \"resizable=yes, location=no, width=300, height=640, menubar=no, status=no, scrollbars=yes\"); return false;")
472
472
473 javascript_include_tag('jstoolbar/jstoolbar') +
473 javascript_include_tag('jstoolbar/jstoolbar') +
474 javascript_include_tag("jstoolbar/lang/jstoolbar-#{current_language}") +
474 javascript_include_tag("jstoolbar/lang/jstoolbar-#{current_language}") +
475 javascript_tag("var toolbar = new jsToolBar($('#{field_id}')); toolbar.setHelpLink('#{help_link}'); toolbar.draw();")
475 javascript_tag("var toolbar = new jsToolBar($('#{field_id}')); toolbar.setHelpLink('#{help_link}'); toolbar.draw();")
476 end
476 end
477
477
478 def content_for(name, content = nil, &block)
478 def content_for(name, content = nil, &block)
479 @has_content ||= {}
479 @has_content ||= {}
480 @has_content[name] = true
480 @has_content[name] = true
481 super(name, content, &block)
481 super(name, content, &block)
482 end
482 end
483
483
484 def has_content?(name)
484 def has_content?(name)
485 (@has_content && @has_content[name]) || false
485 (@has_content && @has_content[name]) || false
486 end
486 end
487 end
487 end
@@ -1,168 +1,170
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.dirname(__FILE__) + '/../../test_helper'
18 require File.dirname(__FILE__) + '/../../test_helper'
19
19
20 class ApplicationHelperTest < HelperTestCase
20 class ApplicationHelperTest < HelperTestCase
21 include ApplicationHelper
21 include ApplicationHelper
22 include ActionView::Helpers::TextHelper
22 include ActionView::Helpers::TextHelper
23 fixtures :projects, :repositories, :changesets, :trackers, :issue_statuses, :issues, :documents, :versions, :wikis, :wiki_pages, :wiki_contents
23 fixtures :projects, :repositories, :changesets, :trackers, :issue_statuses, :issues, :documents, :versions, :wikis, :wiki_pages, :wiki_contents
24
24
25 def setup
25 def setup
26 super
26 super
27 end
27 end
28
28
29 def test_auto_links
29 def test_auto_links
30 to_test = {
30 to_test = {
31 'http://foo.bar' => '<a class="external" href="http://foo.bar">http://foo.bar</a>',
31 'http://foo.bar' => '<a class="external" href="http://foo.bar">http://foo.bar</a>',
32 'http://foo.bar/~user' => '<a class="external" href="http://foo.bar/~user">http://foo.bar/~user</a>',
32 'http://foo.bar/~user' => '<a class="external" href="http://foo.bar/~user">http://foo.bar/~user</a>',
33 'http://foo.bar.' => '<a class="external" href="http://foo.bar">http://foo.bar</a>.',
33 'http://foo.bar.' => '<a class="external" href="http://foo.bar">http://foo.bar</a>.',
34 'http://foo.bar/foo.bar#foo.bar.' => '<a class="external" href="http://foo.bar/foo.bar#foo.bar">http://foo.bar/foo.bar#foo.bar</a>.',
34 'http://foo.bar/foo.bar#foo.bar.' => '<a class="external" href="http://foo.bar/foo.bar#foo.bar">http://foo.bar/foo.bar#foo.bar</a>.',
35 'www.foo.bar' => '<a class="external" href="http://www.foo.bar">www.foo.bar</a>',
35 'www.foo.bar' => '<a class="external" href="http://www.foo.bar">www.foo.bar</a>',
36 'http://foo.bar/page?p=1&t=z&s=' => '<a class="external" href="http://foo.bar/page?p=1&#38;t=z&#38;s=">http://foo.bar/page?p=1&#38;t=z&#38;s=</a>',
36 'http://foo.bar/page?p=1&t=z&s=' => '<a class="external" href="http://foo.bar/page?p=1&#38;t=z&#38;s=">http://foo.bar/page?p=1&#38;t=z&#38;s=</a>',
37 'http://foo.bar/page#125' => '<a class="external" href="http://foo.bar/page#125">http://foo.bar/page#125</a>'
37 'http://foo.bar/page#125' => '<a class="external" href="http://foo.bar/page#125">http://foo.bar/page#125</a>'
38 }
38 }
39 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
39 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
40 end
40 end
41
41
42 def test_auto_mailto
42 def test_auto_mailto
43 assert_equal '<p><a href="mailto:test@foo.bar" class="email">test@foo.bar</a></p>',
43 assert_equal '<p><a href="mailto:test@foo.bar" class="email">test@foo.bar</a></p>',
44 textilizable('test@foo.bar')
44 textilizable('test@foo.bar')
45 end
45 end
46
46
47 def test_inline_images
47 def test_inline_images
48 to_test = {
48 to_test = {
49 '!http://foo.bar/image.jpg!' => '<img src="http://foo.bar/image.jpg" alt="" />',
49 '!http://foo.bar/image.jpg!' => '<img src="http://foo.bar/image.jpg" alt="" />',
50 'floating !>http://foo.bar/image.jpg!' => 'floating <div style="float:right"><img src="http://foo.bar/image.jpg" alt="" /></div>',
50 'floating !>http://foo.bar/image.jpg!' => 'floating <div style="float:right"><img src="http://foo.bar/image.jpg" alt="" /></div>',
51 'with class !(some-class)http://foo.bar/image.jpg!' => 'with class <img src="http://foo.bar/image.jpg" class="some-class" alt="" />',
51 'with class !(some-class)http://foo.bar/image.jpg!' => 'with class <img src="http://foo.bar/image.jpg" class="some-class" alt="" />',
52 'with style !{width:100px;height100px}http://foo.bar/image.jpg!' => 'with style <img src="http://foo.bar/image.jpg" style="width:100px;height100px;" alt="" />',
52 'with style !{width:100px;height100px}http://foo.bar/image.jpg!' => 'with style <img src="http://foo.bar/image.jpg" style="width:100px;height100px;" alt="" />',
53 }
53 }
54 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
54 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
55 end
55 end
56
56
57 def test_textile_external_links
57 def test_textile_external_links
58 to_test = {
58 to_test = {
59 'This is a "link":http://foo.bar' => 'This is a <a href="http://foo.bar" class="external">link</a>',
59 'This is a "link":http://foo.bar' => 'This is a <a href="http://foo.bar" class="external">link</a>',
60 'This is an intern "link":/foo/bar' => 'This is an intern <a href="/foo/bar">link</a>',
60 'This is an intern "link":/foo/bar' => 'This is an intern <a href="/foo/bar">link</a>',
61 '"link (Link title)":http://foo.bar' => '<a href="http://foo.bar" title="Link title" class="external">link</a>'
61 '"link (Link title)":http://foo.bar' => '<a href="http://foo.bar" title="Link title" class="external">link</a>'
62 }
62 }
63 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
63 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
64 end
64 end
65
65
66 def test_redmine_links
66 def test_redmine_links
67 issue_link = link_to('#3', {:controller => 'issues', :action => 'show', :id => 3},
67 issue_link = link_to('#3', {:controller => 'issues', :action => 'show', :id => 3},
68 :class => 'issue', :title => 'Error 281 when updating a recipe (New)')
68 :class => 'issue', :title => 'Error 281 when updating a recipe (New)')
69
69
70 changeset_link = link_to('r1', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 1},
70 changeset_link = link_to('r1', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 1},
71 :class => 'changeset', :title => 'My very first commit')
71 :class => 'changeset', :title => 'My very first commit')
72
72
73 document_link = link_to('Test document', {:controller => 'documents', :action => 'show', :id => 1},
73 document_link = link_to('Test document', {:controller => 'documents', :action => 'show', :id => 1},
74 :class => 'document')
74 :class => 'document')
75
75
76 version_link = link_to('1.0', {:controller => 'versions', :action => 'show', :id => 2},
76 version_link = link_to('1.0', {:controller => 'versions', :action => 'show', :id => 2},
77 :class => 'version')
77 :class => 'version')
78
78
79 source_url = {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => 'some/file'}
79 source_url = {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => 'some/file'}
80
80
81 to_test = {
81 to_test = {
82 # tickets
82 # tickets
83 '#3, #3 and #3.' => "#{issue_link}, #{issue_link} and #{issue_link}.",
83 '#3, #3 and #3.' => "#{issue_link}, #{issue_link} and #{issue_link}.",
84 # changesets
84 # changesets
85 'r1' => changeset_link,
85 'r1' => changeset_link,
86 # documents
86 # documents
87 'document#1' => document_link,
87 'document#1' => document_link,
88 'document:"Test document"' => document_link,
88 'document:"Test document"' => document_link,
89 # versions
89 # versions
90 'version#2' => version_link,
90 'version#2' => version_link,
91 'version:1.0' => version_link,
91 'version:1.0' => version_link,
92 'version:"1.0"' => version_link,
92 'version:"1.0"' => version_link,
93 # source
93 # source
94 'source:/some/file' => link_to('source:/some/file', source_url, :class => 'source'),
94 'source:/some/file' => link_to('source:/some/file', source_url, :class => 'source'),
95 'source:/some/file@52' => link_to('source:/some/file@52', source_url.merge(:rev => 52), :class => 'source'),
95 'source:/some/file@52' => link_to('source:/some/file@52', source_url.merge(:rev => 52), :class => 'source'),
96 'source:/some/file#L110' => link_to('source:/some/file#L110', source_url.merge(:anchor => 'L110'), :class => 'source'),
96 'source:/some/file#L110' => link_to('source:/some/file#L110', source_url.merge(:anchor => 'L110'), :class => 'source'),
97 'source:/some/file@52#L110' => link_to('source:/some/file@52#L110', source_url.merge(:rev => 52, :anchor => 'L110'), :class => 'source'),
97 'source:/some/file@52#L110' => link_to('source:/some/file@52#L110', source_url.merge(:rev => 52, :anchor => 'L110'), :class => 'source'),
98 'export:/some/file' => link_to('export:/some/file', source_url.merge(:format => 'raw'), :class => 'source download'),
98 'export:/some/file' => link_to('export:/some/file', source_url.merge(:format => 'raw'), :class => 'source download'),
99 # escaping
99 # escaping
100 '!#3.' => '#3.',
100 '!#3.' => '#3.',
101 '!r1' => 'r1',
101 '!r1' => 'r1',
102 '!document#1' => 'document#1',
102 '!document#1' => 'document#1',
103 '!document:"Test document"' => 'document:"Test document"',
103 '!document:"Test document"' => 'document:"Test document"',
104 '!version#2' => 'version#2',
104 '!version#2' => 'version#2',
105 '!version:1.0' => 'version:1.0',
105 '!version:1.0' => 'version:1.0',
106 '!version:"1.0"' => 'version:"1.0"',
106 '!version:"1.0"' => 'version:"1.0"',
107 '!source:/some/file' => 'source:/some/file',
107 '!source:/some/file' => 'source:/some/file',
108 # invalid expressions
109 'source:' => 'source:'
108 }
110 }
109 @project = Project.find(1)
111 @project = Project.find(1)
110 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
112 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
111 end
113 end
112
114
113 def test_wiki_links
115 def test_wiki_links
114 to_test = {
116 to_test = {
115 '[[CookBook documentation]]' => '<a href="/wiki/ecookbook/CookBook_documentation" class="wiki-page">CookBook documentation</a>',
117 '[[CookBook documentation]]' => '<a href="/wiki/ecookbook/CookBook_documentation" class="wiki-page">CookBook documentation</a>',
116 '[[Another page|Page]]' => '<a href="/wiki/ecookbook/Another_page" class="wiki-page">Page</a>',
118 '[[Another page|Page]]' => '<a href="/wiki/ecookbook/Another_page" class="wiki-page">Page</a>',
117 # page that doesn't exist
119 # page that doesn't exist
118 '[[Unknown page]]' => '<a href="/wiki/ecookbook/Unknown_page" class="wiki-page new">Unknown page</a>',
120 '[[Unknown page]]' => '<a href="/wiki/ecookbook/Unknown_page" class="wiki-page new">Unknown page</a>',
119 '[[Unknown page|404]]' => '<a href="/wiki/ecookbook/Unknown_page" class="wiki-page new">404</a>',
121 '[[Unknown page|404]]' => '<a href="/wiki/ecookbook/Unknown_page" class="wiki-page new">404</a>',
120 # link to another project wiki
122 # link to another project wiki
121 '[[onlinestore:]]' => '<a href="/wiki/onlinestore/" class="wiki-page">onlinestore</a>',
123 '[[onlinestore:]]' => '<a href="/wiki/onlinestore/" class="wiki-page">onlinestore</a>',
122 '[[onlinestore:|Wiki]]' => '<a href="/wiki/onlinestore/" class="wiki-page">Wiki</a>',
124 '[[onlinestore:|Wiki]]' => '<a href="/wiki/onlinestore/" class="wiki-page">Wiki</a>',
123 '[[onlinestore:Start page]]' => '<a href="/wiki/onlinestore/Start_page" class="wiki-page">Start page</a>',
125 '[[onlinestore:Start page]]' => '<a href="/wiki/onlinestore/Start_page" class="wiki-page">Start page</a>',
124 '[[onlinestore:Start page|Text]]' => '<a href="/wiki/onlinestore/Start_page" class="wiki-page">Text</a>',
126 '[[onlinestore:Start page|Text]]' => '<a href="/wiki/onlinestore/Start_page" class="wiki-page">Text</a>',
125 '[[onlinestore:Unknown page]]' => '<a href="/wiki/onlinestore/Unknown_page" class="wiki-page new">Unknown page</a>',
127 '[[onlinestore:Unknown page]]' => '<a href="/wiki/onlinestore/Unknown_page" class="wiki-page new">Unknown page</a>',
126 # escaping
128 # escaping
127 '![[Another page|Page]]' => '[[Another page|Page]]',
129 '![[Another page|Page]]' => '[[Another page|Page]]',
128 }
130 }
129 @project = Project.find(1)
131 @project = Project.find(1)
130 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
132 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
131 end
133 end
132
134
133 def test_macro_hello_world
135 def test_macro_hello_world
134 text = "{{hello_world}}"
136 text = "{{hello_world}}"
135 assert textilizable(text).match(/Hello world!/)
137 assert textilizable(text).match(/Hello world!/)
136 # escaping
138 # escaping
137 text = "!{{hello_world}}"
139 text = "!{{hello_world}}"
138 assert_equal '<p>{{hello_world}}</p>', textilizable(text)
140 assert_equal '<p>{{hello_world}}</p>', textilizable(text)
139 end
141 end
140
142
141 def test_date_format_default
143 def test_date_format_default
142 today = Date.today
144 today = Date.today
143 Setting.date_format = ''
145 Setting.date_format = ''
144 assert_equal l_date(today), format_date(today)
146 assert_equal l_date(today), format_date(today)
145 end
147 end
146
148
147 def test_date_format
149 def test_date_format
148 today = Date.today
150 today = Date.today
149 Setting.date_format = '%d %m %Y'
151 Setting.date_format = '%d %m %Y'
150 assert_equal today.strftime('%d %m %Y'), format_date(today)
152 assert_equal today.strftime('%d %m %Y'), format_date(today)
151 end
153 end
152
154
153 def test_time_format_default
155 def test_time_format_default
154 now = Time.now
156 now = Time.now
155 Setting.date_format = ''
157 Setting.date_format = ''
156 Setting.time_format = ''
158 Setting.time_format = ''
157 assert_equal l_datetime(now), format_time(now)
159 assert_equal l_datetime(now), format_time(now)
158 assert_equal l_time(now), format_time(now, false)
160 assert_equal l_time(now), format_time(now, false)
159 end
161 end
160
162
161 def test_time_format
163 def test_time_format
162 now = Time.now
164 now = Time.now
163 Setting.date_format = '%d %m %Y'
165 Setting.date_format = '%d %m %Y'
164 Setting.time_format = '%H %M'
166 Setting.time_format = '%H %M'
165 assert_equal now.strftime('%d %m %Y %H %M'), format_time(now)
167 assert_equal now.strftime('%d %m %Y %H %M'), format_time(now)
166 assert_equal now.strftime('%H %M'), format_time(now, false)
168 assert_equal now.strftime('%H %M'), format_time(now, false)
167 end
169 end
168 end
170 end
General Comments 0
You need to be logged in to leave comments. Login now