##// END OF EJS Templates
Clean up ticket auto links....
Jean-Philippe Lang -
r2927:bc37fcee74cf
parent child
Show More
@@ -1,700 +1,699
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 'coderay'
18 require 'coderay'
19 require 'coderay/helpers/file_type'
19 require 'coderay/helpers/file_type'
20 require 'forwardable'
20 require 'forwardable'
21 require 'cgi'
21 require 'cgi'
22
22
23 module ApplicationHelper
23 module ApplicationHelper
24 include Redmine::WikiFormatting::Macros::Definitions
24 include Redmine::WikiFormatting::Macros::Definitions
25 include Redmine::I18n
25 include Redmine::I18n
26 include GravatarHelper::PublicMethods
26 include GravatarHelper::PublicMethods
27
27
28 extend Forwardable
28 extend Forwardable
29 def_delegators :wiki_helper, :wikitoolbar_for, :heads_for_wiki_formatter
29 def_delegators :wiki_helper, :wikitoolbar_for, :heads_for_wiki_formatter
30
30
31 # Return true if user is authorized for controller/action, otherwise false
31 # Return true if user is authorized for controller/action, otherwise false
32 def authorize_for(controller, action)
32 def authorize_for(controller, action)
33 User.current.allowed_to?({:controller => controller, :action => action}, @project)
33 User.current.allowed_to?({:controller => controller, :action => action}, @project)
34 end
34 end
35
35
36 # Display a link if user is authorized
36 # Display a link if user is authorized
37 def link_to_if_authorized(name, options = {}, html_options = nil, *parameters_for_method_reference)
37 def link_to_if_authorized(name, options = {}, html_options = nil, *parameters_for_method_reference)
38 link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for(options[:controller] || params[:controller], options[:action])
38 link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for(options[:controller] || params[:controller], options[:action])
39 end
39 end
40
40
41 # Display a link to remote if user is authorized
41 # Display a link to remote if user is authorized
42 def link_to_remote_if_authorized(name, options = {}, html_options = nil)
42 def link_to_remote_if_authorized(name, options = {}, html_options = nil)
43 url = options[:url] || {}
43 url = options[:url] || {}
44 link_to_remote(name, options, html_options) if authorize_for(url[:controller] || params[:controller], url[:action])
44 link_to_remote(name, options, html_options) if authorize_for(url[:controller] || params[:controller], url[:action])
45 end
45 end
46
46
47 # Displays a link to user's account page if active
47 # Displays a link to user's account page if active
48 def link_to_user(user, options={})
48 def link_to_user(user, options={})
49 if user.is_a?(User)
49 if user.is_a?(User)
50 name = h(user.name(options[:format]))
50 name = h(user.name(options[:format]))
51 if user.active?
51 if user.active?
52 link_to name, :controller => 'users', :action => 'show', :id => user
52 link_to name, :controller => 'users', :action => 'show', :id => user
53 else
53 else
54 name
54 name
55 end
55 end
56 else
56 else
57 h(user.to_s)
57 h(user.to_s)
58 end
58 end
59 end
59 end
60
60
61 # Displays a link to +issue+ with its subject.
61 # Displays a link to +issue+ with its subject.
62 # Examples:
62 # Examples:
63 #
63 #
64 # link_to_issue(issue) # => Defect #6: This is the subject
64 # link_to_issue(issue) # => Defect #6: This is the subject
65 # link_to_issue(issue, :truncate => 6) # => Defect #6: This i...
65 # link_to_issue(issue, :truncate => 6) # => Defect #6: This i...
66 # link_to_issue(issue, :subject => false) # => Defect #6
66 # link_to_issue(issue, :subject => false) # => Defect #6
67 #
67 #
68 def link_to_issue(issue, options={})
68 def link_to_issue(issue, options={})
69 title = nil
69 title = nil
70 subject = nil
70 subject = nil
71 if options[:subject] == false
71 if options[:subject] == false
72 title = truncate(issue.subject, :length => 60)
72 title = truncate(issue.subject, :length => 60)
73 else
73 else
74 subject = issue.subject
74 subject = issue.subject
75 if options[:truncate]
75 if options[:truncate]
76 subject = truncate(subject, :length => options[:truncate])
76 subject = truncate(subject, :length => options[:truncate])
77 end
77 end
78 end
78 end
79 s = link_to "#{issue.tracker} ##{issue.id}", {:controller => "issues", :action => "show", :id => issue},
79 s = link_to "#{issue.tracker} ##{issue.id}", {:controller => "issues", :action => "show", :id => issue},
80 :class => issue.css_classes,
80 :class => issue.css_classes,
81 :title => title
81 :title => title
82 s << ": #{h subject}" if subject
82 s << ": #{h subject}" if subject
83 s
83 s
84 end
84 end
85
85
86 # Generates a link to an attachment.
86 # Generates a link to an attachment.
87 # Options:
87 # Options:
88 # * :text - Link text (default to attachment filename)
88 # * :text - Link text (default to attachment filename)
89 # * :download - Force download (default: false)
89 # * :download - Force download (default: false)
90 def link_to_attachment(attachment, options={})
90 def link_to_attachment(attachment, options={})
91 text = options.delete(:text) || attachment.filename
91 text = options.delete(:text) || attachment.filename
92 action = options.delete(:download) ? 'download' : 'show'
92 action = options.delete(:download) ? 'download' : 'show'
93
93
94 link_to(h(text), {:controller => 'attachments', :action => action, :id => attachment, :filename => attachment.filename }, options)
94 link_to(h(text), {:controller => 'attachments', :action => action, :id => attachment, :filename => attachment.filename }, options)
95 end
95 end
96
96
97 def toggle_link(name, id, options={})
97 def toggle_link(name, id, options={})
98 onclick = "Element.toggle('#{id}'); "
98 onclick = "Element.toggle('#{id}'); "
99 onclick << (options[:focus] ? "Form.Element.focus('#{options[:focus]}'); " : "this.blur(); ")
99 onclick << (options[:focus] ? "Form.Element.focus('#{options[:focus]}'); " : "this.blur(); ")
100 onclick << "return false;"
100 onclick << "return false;"
101 link_to(name, "#", :onclick => onclick)
101 link_to(name, "#", :onclick => onclick)
102 end
102 end
103
103
104 def image_to_function(name, function, html_options = {})
104 def image_to_function(name, function, html_options = {})
105 html_options.symbolize_keys!
105 html_options.symbolize_keys!
106 tag(:input, html_options.merge({
106 tag(:input, html_options.merge({
107 :type => "image", :src => image_path(name),
107 :type => "image", :src => image_path(name),
108 :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};"
108 :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};"
109 }))
109 }))
110 end
110 end
111
111
112 def prompt_to_remote(name, text, param, url, html_options = {})
112 def prompt_to_remote(name, text, param, url, html_options = {})
113 html_options[:onclick] = "promptToRemote('#{text}', '#{param}', '#{url_for(url)}'); return false;"
113 html_options[:onclick] = "promptToRemote('#{text}', '#{param}', '#{url_for(url)}'); return false;"
114 link_to name, {}, html_options
114 link_to name, {}, html_options
115 end
115 end
116
116
117 def format_activity_title(text)
117 def format_activity_title(text)
118 h(truncate_single_line(text, :length => 100))
118 h(truncate_single_line(text, :length => 100))
119 end
119 end
120
120
121 def format_activity_day(date)
121 def format_activity_day(date)
122 date == Date.today ? l(:label_today).titleize : format_date(date)
122 date == Date.today ? l(:label_today).titleize : format_date(date)
123 end
123 end
124
124
125 def format_activity_description(text)
125 def format_activity_description(text)
126 h(truncate(text.to_s, :length => 120).gsub(%r{[\r\n]*<(pre|code)>.*$}m, '...')).gsub(/[\r\n]+/, "<br />")
126 h(truncate(text.to_s, :length => 120).gsub(%r{[\r\n]*<(pre|code)>.*$}m, '...')).gsub(/[\r\n]+/, "<br />")
127 end
127 end
128
128
129 def due_date_distance_in_words(date)
129 def due_date_distance_in_words(date)
130 if date
130 if date
131 l((date < Date.today ? :label_roadmap_overdue : :label_roadmap_due_in), distance_of_date_in_words(Date.today, date))
131 l((date < Date.today ? :label_roadmap_overdue : :label_roadmap_due_in), distance_of_date_in_words(Date.today, date))
132 end
132 end
133 end
133 end
134
134
135 def render_page_hierarchy(pages, node=nil)
135 def render_page_hierarchy(pages, node=nil)
136 content = ''
136 content = ''
137 if pages[node]
137 if pages[node]
138 content << "<ul class=\"pages-hierarchy\">\n"
138 content << "<ul class=\"pages-hierarchy\">\n"
139 pages[node].each do |page|
139 pages[node].each do |page|
140 content << "<li>"
140 content << "<li>"
141 content << link_to(h(page.pretty_title), {:controller => 'wiki', :action => 'index', :id => page.project, :page => page.title},
141 content << link_to(h(page.pretty_title), {:controller => 'wiki', :action => 'index', :id => page.project, :page => page.title},
142 :title => (page.respond_to?(:updated_on) ? l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on)) : nil))
142 :title => (page.respond_to?(:updated_on) ? l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on)) : nil))
143 content << "\n" + render_page_hierarchy(pages, page.id) if pages[page.id]
143 content << "\n" + render_page_hierarchy(pages, page.id) if pages[page.id]
144 content << "</li>\n"
144 content << "</li>\n"
145 end
145 end
146 content << "</ul>\n"
146 content << "</ul>\n"
147 end
147 end
148 content
148 content
149 end
149 end
150
150
151 # Renders flash messages
151 # Renders flash messages
152 def render_flash_messages
152 def render_flash_messages
153 s = ''
153 s = ''
154 flash.each do |k,v|
154 flash.each do |k,v|
155 s << content_tag('div', v, :class => "flash #{k}")
155 s << content_tag('div', v, :class => "flash #{k}")
156 end
156 end
157 s
157 s
158 end
158 end
159
159
160 # Renders tabs and their content
160 # Renders tabs and their content
161 def render_tabs(tabs)
161 def render_tabs(tabs)
162 if tabs.any?
162 if tabs.any?
163 render :partial => 'common/tabs', :locals => {:tabs => tabs}
163 render :partial => 'common/tabs', :locals => {:tabs => tabs}
164 else
164 else
165 content_tag 'p', l(:label_no_data), :class => "nodata"
165 content_tag 'p', l(:label_no_data), :class => "nodata"
166 end
166 end
167 end
167 end
168
168
169 # Renders the project quick-jump box
169 # Renders the project quick-jump box
170 def render_project_jump_box
170 def render_project_jump_box
171 # Retrieve them now to avoid a COUNT query
171 # Retrieve them now to avoid a COUNT query
172 projects = User.current.projects.all
172 projects = User.current.projects.all
173 if projects.any?
173 if projects.any?
174 s = '<select onchange="if (this.value != \'\') { window.location = this.value; }">' +
174 s = '<select onchange="if (this.value != \'\') { window.location = this.value; }">' +
175 "<option value=''>#{ l(:label_jump_to_a_project) }</option>" +
175 "<option value=''>#{ l(:label_jump_to_a_project) }</option>" +
176 '<option value="" disabled="disabled">---</option>'
176 '<option value="" disabled="disabled">---</option>'
177 s << project_tree_options_for_select(projects, :selected => @project) do |p|
177 s << project_tree_options_for_select(projects, :selected => @project) do |p|
178 { :value => url_for(:controller => 'projects', :action => 'show', :id => p, :jump => current_menu_item) }
178 { :value => url_for(:controller => 'projects', :action => 'show', :id => p, :jump => current_menu_item) }
179 end
179 end
180 s << '</select>'
180 s << '</select>'
181 s
181 s
182 end
182 end
183 end
183 end
184
184
185 def project_tree_options_for_select(projects, options = {})
185 def project_tree_options_for_select(projects, options = {})
186 s = ''
186 s = ''
187 project_tree(projects) do |project, level|
187 project_tree(projects) do |project, level|
188 name_prefix = (level > 0 ? ('&nbsp;' * 2 * level + '&#187; ') : '')
188 name_prefix = (level > 0 ? ('&nbsp;' * 2 * level + '&#187; ') : '')
189 tag_options = {:value => project.id, :selected => ((project == options[:selected]) ? 'selected' : nil)}
189 tag_options = {:value => project.id, :selected => ((project == options[:selected]) ? 'selected' : nil)}
190 tag_options.merge!(yield(project)) if block_given?
190 tag_options.merge!(yield(project)) if block_given?
191 s << content_tag('option', name_prefix + h(project), tag_options)
191 s << content_tag('option', name_prefix + h(project), tag_options)
192 end
192 end
193 s
193 s
194 end
194 end
195
195
196 # Yields the given block for each project with its level in the tree
196 # Yields the given block for each project with its level in the tree
197 def project_tree(projects, &block)
197 def project_tree(projects, &block)
198 ancestors = []
198 ancestors = []
199 projects.sort_by(&:lft).each do |project|
199 projects.sort_by(&:lft).each do |project|
200 while (ancestors.any? && !project.is_descendant_of?(ancestors.last))
200 while (ancestors.any? && !project.is_descendant_of?(ancestors.last))
201 ancestors.pop
201 ancestors.pop
202 end
202 end
203 yield project, ancestors.size
203 yield project, ancestors.size
204 ancestors << project
204 ancestors << project
205 end
205 end
206 end
206 end
207
207
208 def project_nested_ul(projects, &block)
208 def project_nested_ul(projects, &block)
209 s = ''
209 s = ''
210 if projects.any?
210 if projects.any?
211 ancestors = []
211 ancestors = []
212 projects.sort_by(&:lft).each do |project|
212 projects.sort_by(&:lft).each do |project|
213 if (ancestors.empty? || project.is_descendant_of?(ancestors.last))
213 if (ancestors.empty? || project.is_descendant_of?(ancestors.last))
214 s << "<ul>\n"
214 s << "<ul>\n"
215 else
215 else
216 ancestors.pop
216 ancestors.pop
217 s << "</li>"
217 s << "</li>"
218 while (ancestors.any? && !project.is_descendant_of?(ancestors.last))
218 while (ancestors.any? && !project.is_descendant_of?(ancestors.last))
219 ancestors.pop
219 ancestors.pop
220 s << "</ul></li>\n"
220 s << "</ul></li>\n"
221 end
221 end
222 end
222 end
223 s << "<li>"
223 s << "<li>"
224 s << yield(project).to_s
224 s << yield(project).to_s
225 ancestors << project
225 ancestors << project
226 end
226 end
227 s << ("</li></ul>\n" * ancestors.size)
227 s << ("</li></ul>\n" * ancestors.size)
228 end
228 end
229 s
229 s
230 end
230 end
231
231
232 def principals_check_box_tags(name, principals)
232 def principals_check_box_tags(name, principals)
233 s = ''
233 s = ''
234 principals.sort.each do |principal|
234 principals.sort.each do |principal|
235 s << "<label>#{ check_box_tag name, principal.id, false } #{h principal}</label>\n"
235 s << "<label>#{ check_box_tag name, principal.id, false } #{h principal}</label>\n"
236 end
236 end
237 s
237 s
238 end
238 end
239
239
240 # Truncates and returns the string as a single line
240 # Truncates and returns the string as a single line
241 def truncate_single_line(string, *args)
241 def truncate_single_line(string, *args)
242 truncate(string.to_s, *args).gsub(%r{[\r\n]+}m, ' ')
242 truncate(string.to_s, *args).gsub(%r{[\r\n]+}m, ' ')
243 end
243 end
244
244
245 def html_hours(text)
245 def html_hours(text)
246 text.gsub(%r{(\d+)\.(\d+)}, '<span class="hours hours-int">\1</span><span class="hours hours-dec">.\2</span>')
246 text.gsub(%r{(\d+)\.(\d+)}, '<span class="hours hours-int">\1</span><span class="hours hours-dec">.\2</span>')
247 end
247 end
248
248
249 def authoring(created, author, options={})
249 def authoring(created, author, options={})
250 l(options[:label] || :label_added_time_by, :author => link_to_user(author), :age => time_tag(created))
250 l(options[:label] || :label_added_time_by, :author => link_to_user(author), :age => time_tag(created))
251 end
251 end
252
252
253 def time_tag(time)
253 def time_tag(time)
254 text = distance_of_time_in_words(Time.now, time)
254 text = distance_of_time_in_words(Time.now, time)
255 if @project
255 if @project
256 link_to(text, {:controller => 'projects', :action => 'activity', :id => @project, :from => time.to_date}, :title => format_time(time))
256 link_to(text, {:controller => 'projects', :action => 'activity', :id => @project, :from => time.to_date}, :title => format_time(time))
257 else
257 else
258 content_tag('acronym', text, :title => format_time(time))
258 content_tag('acronym', text, :title => format_time(time))
259 end
259 end
260 end
260 end
261
261
262 def syntax_highlight(name, content)
262 def syntax_highlight(name, content)
263 type = CodeRay::FileType[name]
263 type = CodeRay::FileType[name]
264 type ? CodeRay.scan(content, type).html : h(content)
264 type ? CodeRay.scan(content, type).html : h(content)
265 end
265 end
266
266
267 def to_path_param(path)
267 def to_path_param(path)
268 path.to_s.split(%r{[/\\]}).select {|p| !p.blank?}
268 path.to_s.split(%r{[/\\]}).select {|p| !p.blank?}
269 end
269 end
270
270
271 def pagination_links_full(paginator, count=nil, options={})
271 def pagination_links_full(paginator, count=nil, options={})
272 page_param = options.delete(:page_param) || :page
272 page_param = options.delete(:page_param) || :page
273 url_param = params.dup
273 url_param = params.dup
274 # don't reuse query params if filters are present
274 # don't reuse query params if filters are present
275 url_param.merge!(:fields => nil, :values => nil, :operators => nil) if url_param.delete(:set_filter)
275 url_param.merge!(:fields => nil, :values => nil, :operators => nil) if url_param.delete(:set_filter)
276
276
277 html = ''
277 html = ''
278 if paginator.current.previous
278 if paginator.current.previous
279 html << link_to_remote_content_update('&#171; ' + l(:label_previous), url_param.merge(page_param => paginator.current.previous)) + ' '
279 html << link_to_remote_content_update('&#171; ' + l(:label_previous), url_param.merge(page_param => paginator.current.previous)) + ' '
280 end
280 end
281
281
282 html << (pagination_links_each(paginator, options) do |n|
282 html << (pagination_links_each(paginator, options) do |n|
283 link_to_remote_content_update(n.to_s, url_param.merge(page_param => n))
283 link_to_remote_content_update(n.to_s, url_param.merge(page_param => n))
284 end || '')
284 end || '')
285
285
286 if paginator.current.next
286 if paginator.current.next
287 html << ' ' + link_to_remote_content_update((l(:label_next) + ' &#187;'), url_param.merge(page_param => paginator.current.next))
287 html << ' ' + link_to_remote_content_update((l(:label_next) + ' &#187;'), url_param.merge(page_param => paginator.current.next))
288 end
288 end
289
289
290 unless count.nil?
290 unless count.nil?
291 html << [
291 html << [
292 " (#{paginator.current.first_item}-#{paginator.current.last_item}/#{count})",
292 " (#{paginator.current.first_item}-#{paginator.current.last_item}/#{count})",
293 per_page_links(paginator.items_per_page)
293 per_page_links(paginator.items_per_page)
294 ].compact.join(' | ')
294 ].compact.join(' | ')
295 end
295 end
296
296
297 html
297 html
298 end
298 end
299
299
300 def per_page_links(selected=nil)
300 def per_page_links(selected=nil)
301 url_param = params.dup
301 url_param = params.dup
302 url_param.clear if url_param.has_key?(:set_filter)
302 url_param.clear if url_param.has_key?(:set_filter)
303
303
304 links = Setting.per_page_options_array.collect do |n|
304 links = Setting.per_page_options_array.collect do |n|
305 n == selected ? n : link_to_remote(n, {:update => "content",
305 n == selected ? n : link_to_remote(n, {:update => "content",
306 :url => params.dup.merge(:per_page => n),
306 :url => params.dup.merge(:per_page => n),
307 :method => :get},
307 :method => :get},
308 {:href => url_for(url_param.merge(:per_page => n))})
308 {:href => url_for(url_param.merge(:per_page => n))})
309 end
309 end
310 links.size > 1 ? l(:label_display_per_page, links.join(', ')) : nil
310 links.size > 1 ? l(:label_display_per_page, links.join(', ')) : nil
311 end
311 end
312
312
313 def reorder_links(name, url)
313 def reorder_links(name, url)
314 link_to(image_tag('2uparrow.png', :alt => l(:label_sort_highest)), url.merge({"#{name}[move_to]" => 'highest'}), :method => :post, :title => l(:label_sort_highest)) +
314 link_to(image_tag('2uparrow.png', :alt => l(:label_sort_highest)), url.merge({"#{name}[move_to]" => 'highest'}), :method => :post, :title => l(:label_sort_highest)) +
315 link_to(image_tag('1uparrow.png', :alt => l(:label_sort_higher)), url.merge({"#{name}[move_to]" => 'higher'}), :method => :post, :title => l(:label_sort_higher)) +
315 link_to(image_tag('1uparrow.png', :alt => l(:label_sort_higher)), url.merge({"#{name}[move_to]" => 'higher'}), :method => :post, :title => l(:label_sort_higher)) +
316 link_to(image_tag('1downarrow.png', :alt => l(:label_sort_lower)), url.merge({"#{name}[move_to]" => 'lower'}), :method => :post, :title => l(:label_sort_lower)) +
316 link_to(image_tag('1downarrow.png', :alt => l(:label_sort_lower)), url.merge({"#{name}[move_to]" => 'lower'}), :method => :post, :title => l(:label_sort_lower)) +
317 link_to(image_tag('2downarrow.png', :alt => l(:label_sort_lowest)), url.merge({"#{name}[move_to]" => 'lowest'}), :method => :post, :title => l(:label_sort_lowest))
317 link_to(image_tag('2downarrow.png', :alt => l(:label_sort_lowest)), url.merge({"#{name}[move_to]" => 'lowest'}), :method => :post, :title => l(:label_sort_lowest))
318 end
318 end
319
319
320 def breadcrumb(*args)
320 def breadcrumb(*args)
321 elements = args.flatten
321 elements = args.flatten
322 elements.any? ? content_tag('p', args.join(' &#187; ') + ' &#187; ', :class => 'breadcrumb') : nil
322 elements.any? ? content_tag('p', args.join(' &#187; ') + ' &#187; ', :class => 'breadcrumb') : nil
323 end
323 end
324
324
325 def other_formats_links(&block)
325 def other_formats_links(&block)
326 concat('<p class="other-formats">' + l(:label_export_to))
326 concat('<p class="other-formats">' + l(:label_export_to))
327 yield Redmine::Views::OtherFormatsBuilder.new(self)
327 yield Redmine::Views::OtherFormatsBuilder.new(self)
328 concat('</p>')
328 concat('</p>')
329 end
329 end
330
330
331 def page_header_title
331 def page_header_title
332 if @project.nil? || @project.new_record?
332 if @project.nil? || @project.new_record?
333 h(Setting.app_title)
333 h(Setting.app_title)
334 else
334 else
335 b = []
335 b = []
336 ancestors = (@project.root? ? [] : @project.ancestors.visible)
336 ancestors = (@project.root? ? [] : @project.ancestors.visible)
337 if ancestors.any?
337 if ancestors.any?
338 root = ancestors.shift
338 root = ancestors.shift
339 b << link_to(h(root), {:controller => 'projects', :action => 'show', :id => root, :jump => current_menu_item}, :class => 'root')
339 b << link_to(h(root), {:controller => 'projects', :action => 'show', :id => root, :jump => current_menu_item}, :class => 'root')
340 if ancestors.size > 2
340 if ancestors.size > 2
341 b << '&#8230;'
341 b << '&#8230;'
342 ancestors = ancestors[-2, 2]
342 ancestors = ancestors[-2, 2]
343 end
343 end
344 b += ancestors.collect {|p| link_to(h(p), {:controller => 'projects', :action => 'show', :id => p, :jump => current_menu_item}, :class => 'ancestor') }
344 b += ancestors.collect {|p| link_to(h(p), {:controller => 'projects', :action => 'show', :id => p, :jump => current_menu_item}, :class => 'ancestor') }
345 end
345 end
346 b << h(@project)
346 b << h(@project)
347 b.join(' &#187; ')
347 b.join(' &#187; ')
348 end
348 end
349 end
349 end
350
350
351 def html_title(*args)
351 def html_title(*args)
352 if args.empty?
352 if args.empty?
353 title = []
353 title = []
354 title << @project.name if @project
354 title << @project.name if @project
355 title += @html_title if @html_title
355 title += @html_title if @html_title
356 title << Setting.app_title
356 title << Setting.app_title
357 title.select {|t| !t.blank? }.join(' - ')
357 title.select {|t| !t.blank? }.join(' - ')
358 else
358 else
359 @html_title ||= []
359 @html_title ||= []
360 @html_title += args
360 @html_title += args
361 end
361 end
362 end
362 end
363
363
364 def accesskey(s)
364 def accesskey(s)
365 Redmine::AccessKeys.key_for s
365 Redmine::AccessKeys.key_for s
366 end
366 end
367
367
368 # Formats text according to system settings.
368 # Formats text according to system settings.
369 # 2 ways to call this method:
369 # 2 ways to call this method:
370 # * with a String: textilizable(text, options)
370 # * with a String: textilizable(text, options)
371 # * with an object and one of its attribute: textilizable(issue, :description, options)
371 # * with an object and one of its attribute: textilizable(issue, :description, options)
372 def textilizable(*args)
372 def textilizable(*args)
373 options = args.last.is_a?(Hash) ? args.pop : {}
373 options = args.last.is_a?(Hash) ? args.pop : {}
374 case args.size
374 case args.size
375 when 1
375 when 1
376 obj = options[:object]
376 obj = options[:object]
377 text = args.shift
377 text = args.shift
378 when 2
378 when 2
379 obj = args.shift
379 obj = args.shift
380 text = obj.send(args.shift).to_s
380 text = obj.send(args.shift).to_s
381 else
381 else
382 raise ArgumentError, 'invalid arguments to textilizable'
382 raise ArgumentError, 'invalid arguments to textilizable'
383 end
383 end
384 return '' if text.blank?
384 return '' if text.blank?
385
385
386 only_path = options.delete(:only_path) == false ? false : true
386 only_path = options.delete(:only_path) == false ? false : true
387
387
388 # when using an image link, try to use an attachment, if possible
388 # when using an image link, try to use an attachment, if possible
389 attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil)
389 attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil)
390
390
391 if attachments
391 if attachments
392 attachments = attachments.sort_by(&:created_on).reverse
392 attachments = attachments.sort_by(&:created_on).reverse
393 text = text.gsub(/!((\<|\=|\>)?(\([^\)]+\))?(\[[^\]]+\])?(\{[^\}]+\})?)(\S+\.(bmp|gif|jpg|jpeg|png))!/i) do |m|
393 text = text.gsub(/!((\<|\=|\>)?(\([^\)]+\))?(\[[^\]]+\])?(\{[^\}]+\})?)(\S+\.(bmp|gif|jpg|jpeg|png))!/i) do |m|
394 style = $1
394 style = $1
395 filename = $6.downcase
395 filename = $6.downcase
396 # search for the picture in attachments
396 # search for the picture in attachments
397 if found = attachments.detect { |att| att.filename.downcase == filename }
397 if found = attachments.detect { |att| att.filename.downcase == filename }
398 image_url = url_for :only_path => only_path, :controller => 'attachments', :action => 'download', :id => found
398 image_url = url_for :only_path => only_path, :controller => 'attachments', :action => 'download', :id => found
399 desc = found.description.to_s.gsub(/^([^\(\)]*).*$/, "\\1")
399 desc = found.description.to_s.gsub(/^([^\(\)]*).*$/, "\\1")
400 alt = desc.blank? ? nil : "(#{desc})"
400 alt = desc.blank? ? nil : "(#{desc})"
401 "!#{style}#{image_url}#{alt}!"
401 "!#{style}#{image_url}#{alt}!"
402 else
402 else
403 m
403 m
404 end
404 end
405 end
405 end
406 end
406 end
407
407
408 text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text) { |macro, args| exec_macro(macro, obj, args) }
408 text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text) { |macro, args| exec_macro(macro, obj, args) }
409
409
410 # different methods for formatting wiki links
410 # different methods for formatting wiki links
411 case options[:wiki_links]
411 case options[:wiki_links]
412 when :local
412 when :local
413 # used for local links to html files
413 # used for local links to html files
414 format_wiki_link = Proc.new {|project, title, anchor| "#{title}.html" }
414 format_wiki_link = Proc.new {|project, title, anchor| "#{title}.html" }
415 when :anchor
415 when :anchor
416 # used for single-file wiki export
416 # used for single-file wiki export
417 format_wiki_link = Proc.new {|project, title, anchor| "##{title}" }
417 format_wiki_link = Proc.new {|project, title, anchor| "##{title}" }
418 else
418 else
419 format_wiki_link = Proc.new {|project, title, anchor| url_for(:only_path => only_path, :controller => 'wiki', :action => 'index', :id => project, :page => title, :anchor => anchor) }
419 format_wiki_link = Proc.new {|project, title, anchor| url_for(:only_path => only_path, :controller => 'wiki', :action => 'index', :id => project, :page => title, :anchor => anchor) }
420 end
420 end
421
421
422 project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil)
422 project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil)
423
423
424 # Wiki links
424 # Wiki links
425 #
425 #
426 # Examples:
426 # Examples:
427 # [[mypage]]
427 # [[mypage]]
428 # [[mypage|mytext]]
428 # [[mypage|mytext]]
429 # wiki links can refer other project wikis, using project name or identifier:
429 # wiki links can refer other project wikis, using project name or identifier:
430 # [[project:]] -> wiki starting page
430 # [[project:]] -> wiki starting page
431 # [[project:|mytext]]
431 # [[project:|mytext]]
432 # [[project:mypage]]
432 # [[project:mypage]]
433 # [[project:mypage|mytext]]
433 # [[project:mypage|mytext]]
434 text = text.gsub(/(!)?(\[\[([^\]\n\|]+)(\|([^\]\n\|]+))?\]\])/) do |m|
434 text = text.gsub(/(!)?(\[\[([^\]\n\|]+)(\|([^\]\n\|]+))?\]\])/) do |m|
435 link_project = project
435 link_project = project
436 esc, all, page, title = $1, $2, $3, $5
436 esc, all, page, title = $1, $2, $3, $5
437 if esc.nil?
437 if esc.nil?
438 if page =~ /^([^\:]+)\:(.*)$/
438 if page =~ /^([^\:]+)\:(.*)$/
439 link_project = Project.find_by_name($1) || Project.find_by_identifier($1)
439 link_project = Project.find_by_name($1) || Project.find_by_identifier($1)
440 page = $2
440 page = $2
441 title ||= $1 if page.blank?
441 title ||= $1 if page.blank?
442 end
442 end
443
443
444 if link_project && link_project.wiki
444 if link_project && link_project.wiki
445 # extract anchor
445 # extract anchor
446 anchor = nil
446 anchor = nil
447 if page =~ /^(.+?)\#(.+)$/
447 if page =~ /^(.+?)\#(.+)$/
448 page, anchor = $1, $2
448 page, anchor = $1, $2
449 end
449 end
450 # check if page exists
450 # check if page exists
451 wiki_page = link_project.wiki.find_page(page)
451 wiki_page = link_project.wiki.find_page(page)
452 link_to((title || page), format_wiki_link.call(link_project, Wiki.titleize(page), anchor),
452 link_to((title || page), format_wiki_link.call(link_project, Wiki.titleize(page), anchor),
453 :class => ('wiki-page' + (wiki_page ? '' : ' new')))
453 :class => ('wiki-page' + (wiki_page ? '' : ' new')))
454 else
454 else
455 # project or wiki doesn't exist
455 # project or wiki doesn't exist
456 all
456 all
457 end
457 end
458 else
458 else
459 all
459 all
460 end
460 end
461 end
461 end
462
462
463 # Redmine links
463 # Redmine links
464 #
464 #
465 # Examples:
465 # Examples:
466 # Issues:
466 # Issues:
467 # #52 -> Link to issue #52
467 # #52 -> Link to issue #52
468 # Changesets:
468 # Changesets:
469 # r52 -> Link to revision 52
469 # r52 -> Link to revision 52
470 # commit:a85130f -> Link to scmid starting with a85130f
470 # commit:a85130f -> Link to scmid starting with a85130f
471 # Documents:
471 # Documents:
472 # document#17 -> Link to document with id 17
472 # document#17 -> Link to document with id 17
473 # document:Greetings -> Link to the document with title "Greetings"
473 # document:Greetings -> Link to the document with title "Greetings"
474 # document:"Some document" -> Link to the document with title "Some document"
474 # document:"Some document" -> Link to the document with title "Some document"
475 # Versions:
475 # Versions:
476 # version#3 -> Link to version with id 3
476 # version#3 -> Link to version with id 3
477 # version:1.0.0 -> Link to version named "1.0.0"
477 # version:1.0.0 -> Link to version named "1.0.0"
478 # version:"1.0 beta 2" -> Link to version named "1.0 beta 2"
478 # version:"1.0 beta 2" -> Link to version named "1.0 beta 2"
479 # Attachments:
479 # Attachments:
480 # attachment:file.zip -> Link to the attachment of the current object named file.zip
480 # attachment:file.zip -> Link to the attachment of the current object named file.zip
481 # Source files:
481 # Source files:
482 # source:some/file -> Link to the file located at /some/file in the project's repository
482 # source:some/file -> Link to the file located at /some/file in the project's repository
483 # source:some/file@52 -> Link to the file's revision 52
483 # source:some/file@52 -> Link to the file's revision 52
484 # source:some/file#L120 -> Link to line 120 of the file
484 # source:some/file#L120 -> Link to line 120 of the file
485 # source:some/file@52#L120 -> Link to line 120 of the file's revision 52
485 # source:some/file@52#L120 -> Link to line 120 of the file's revision 52
486 # export:some/file -> Force the download of the file
486 # export:some/file -> Force the download of the file
487 # Forum messages:
487 # Forum messages:
488 # message#1218 -> Link to message with id 1218
488 # message#1218 -> Link to message with id 1218
489 text = text.gsub(%r{([\s\(,\-\>]|^)(!)?(attachment|document|version|commit|source|export|message)?((#|r)(\d+)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]]\W)|,|\s|<|$)}) do |m|
489 text = text.gsub(%r{([\s\(,\-\>]|^)(!)?(attachment|document|version|commit|source|export|message)?((#|r)(\d+)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]]\W)|,|\s|<|$)}) do |m|
490 leading, esc, prefix, sep, oid = $1, $2, $3, $5 || $7, $6 || $8
490 leading, esc, prefix, sep, oid = $1, $2, $3, $5 || $7, $6 || $8
491 link = nil
491 link = nil
492 if esc.nil?
492 if esc.nil?
493 if prefix.nil? && sep == 'r'
493 if prefix.nil? && sep == 'r'
494 if project && (changeset = project.changesets.find_by_revision(oid))
494 if project && (changeset = project.changesets.find_by_revision(oid))
495 link = link_to("r#{oid}", {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => oid},
495 link = link_to("r#{oid}", {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => oid},
496 :class => 'changeset',
496 :class => 'changeset',
497 :title => truncate_single_line(changeset.comments, :length => 100))
497 :title => truncate_single_line(changeset.comments, :length => 100))
498 end
498 end
499 elsif sep == '#'
499 elsif sep == '#'
500 oid = oid.to_i
500 oid = oid.to_i
501 case prefix
501 case prefix
502 when nil
502 when nil
503 if issue = Issue.visible.find_by_id(oid, :include => :status)
503 if issue = Issue.visible.find_by_id(oid, :include => :status)
504 link = link_to("##{oid}", {:only_path => only_path, :controller => 'issues', :action => 'show', :id => oid},
504 link = link_to("##{oid}", {:only_path => only_path, :controller => 'issues', :action => 'show', :id => oid},
505 :class => (issue.closed? ? 'issue closed' : 'issue'),
505 :class => issue.css_classes,
506 :title => "#{truncate(issue.subject, :length => 100)} (#{issue.status.name})")
506 :title => "#{truncate(issue.subject, :length => 100)} (#{issue.status.name})")
507 link = content_tag('del', link) if issue.closed?
508 end
507 end
509 when 'document'
508 when 'document'
510 if document = Document.find_by_id(oid, :include => [:project], :conditions => Project.visible_by(User.current))
509 if document = Document.find_by_id(oid, :include => [:project], :conditions => Project.visible_by(User.current))
511 link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},
510 link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},
512 :class => 'document'
511 :class => 'document'
513 end
512 end
514 when 'version'
513 when 'version'
515 if version = Version.find_by_id(oid, :include => [:project], :conditions => Project.visible_by(User.current))
514 if version = Version.find_by_id(oid, :include => [:project], :conditions => Project.visible_by(User.current))
516 link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
515 link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
517 :class => 'version'
516 :class => 'version'
518 end
517 end
519 when 'message'
518 when 'message'
520 if message = Message.find_by_id(oid, :include => [:parent, {:board => :project}], :conditions => Project.visible_by(User.current))
519 if message = Message.find_by_id(oid, :include => [:parent, {:board => :project}], :conditions => Project.visible_by(User.current))
521 link = link_to h(truncate(message.subject, :length => 60)), {:only_path => only_path,
520 link = link_to h(truncate(message.subject, :length => 60)), {:only_path => only_path,
522 :controller => 'messages',
521 :controller => 'messages',
523 :action => 'show',
522 :action => 'show',
524 :board_id => message.board,
523 :board_id => message.board,
525 :id => message.root,
524 :id => message.root,
526 :anchor => (message.parent ? "message-#{message.id}" : nil)},
525 :anchor => (message.parent ? "message-#{message.id}" : nil)},
527 :class => 'message'
526 :class => 'message'
528 end
527 end
529 end
528 end
530 elsif sep == ':'
529 elsif sep == ':'
531 # removes the double quotes if any
530 # removes the double quotes if any
532 name = oid.gsub(%r{^"(.*)"$}, "\\1")
531 name = oid.gsub(%r{^"(.*)"$}, "\\1")
533 case prefix
532 case prefix
534 when 'document'
533 when 'document'
535 if project && document = project.documents.find_by_title(name)
534 if project && document = project.documents.find_by_title(name)
536 link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},
535 link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},
537 :class => 'document'
536 :class => 'document'
538 end
537 end
539 when 'version'
538 when 'version'
540 if project && version = project.versions.find_by_name(name)
539 if project && version = project.versions.find_by_name(name)
541 link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
540 link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
542 :class => 'version'
541 :class => 'version'
543 end
542 end
544 when 'commit'
543 when 'commit'
545 if project && (changeset = project.changesets.find(:first, :conditions => ["scmid LIKE ?", "#{name}%"]))
544 if project && (changeset = project.changesets.find(:first, :conditions => ["scmid LIKE ?", "#{name}%"]))
546 link = link_to h("#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.revision},
545 link = link_to h("#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.revision},
547 :class => 'changeset',
546 :class => 'changeset',
548 :title => truncate_single_line(changeset.comments, :length => 100)
547 :title => truncate_single_line(changeset.comments, :length => 100)
549 end
548 end
550 when 'source', 'export'
549 when 'source', 'export'
551 if project && project.repository
550 if project && project.repository
552 name =~ %r{^[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?$}
551 name =~ %r{^[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?$}
553 path, rev, anchor = $1, $3, $5
552 path, rev, anchor = $1, $3, $5
554 link = link_to h("#{prefix}:#{name}"), {:controller => 'repositories', :action => 'entry', :id => project,
553 link = link_to h("#{prefix}:#{name}"), {:controller => 'repositories', :action => 'entry', :id => project,
555 :path => to_path_param(path),
554 :path => to_path_param(path),
556 :rev => rev,
555 :rev => rev,
557 :anchor => anchor,
556 :anchor => anchor,
558 :format => (prefix == 'export' ? 'raw' : nil)},
557 :format => (prefix == 'export' ? 'raw' : nil)},
559 :class => (prefix == 'export' ? 'source download' : 'source')
558 :class => (prefix == 'export' ? 'source download' : 'source')
560 end
559 end
561 when 'attachment'
560 when 'attachment'
562 if attachments && attachment = attachments.detect {|a| a.filename == name }
561 if attachments && attachment = attachments.detect {|a| a.filename == name }
563 link = link_to h(attachment.filename), {:only_path => only_path, :controller => 'attachments', :action => 'download', :id => attachment},
562 link = link_to h(attachment.filename), {:only_path => only_path, :controller => 'attachments', :action => 'download', :id => attachment},
564 :class => 'attachment'
563 :class => 'attachment'
565 end
564 end
566 end
565 end
567 end
566 end
568 end
567 end
569 leading + (link || "#{prefix}#{sep}#{oid}")
568 leading + (link || "#{prefix}#{sep}#{oid}")
570 end
569 end
571
570
572 text
571 text
573 end
572 end
574
573
575 # Same as Rails' simple_format helper without using paragraphs
574 # Same as Rails' simple_format helper without using paragraphs
576 def simple_format_without_paragraph(text)
575 def simple_format_without_paragraph(text)
577 text.to_s.
576 text.to_s.
578 gsub(/\r\n?/, "\n"). # \r\n and \r -> \n
577 gsub(/\r\n?/, "\n"). # \r\n and \r -> \n
579 gsub(/\n\n+/, "<br /><br />"). # 2+ newline -> 2 br
578 gsub(/\n\n+/, "<br /><br />"). # 2+ newline -> 2 br
580 gsub(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br
579 gsub(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br
581 end
580 end
582
581
583 def lang_options_for_select(blank=true)
582 def lang_options_for_select(blank=true)
584 (blank ? [["(auto)", ""]] : []) +
583 (blank ? [["(auto)", ""]] : []) +
585 valid_languages.collect{|lang| [ ll(lang.to_s, :general_lang_name), lang.to_s]}.sort{|x,y| x.last <=> y.last }
584 valid_languages.collect{|lang| [ ll(lang.to_s, :general_lang_name), lang.to_s]}.sort{|x,y| x.last <=> y.last }
586 end
585 end
587
586
588 def label_tag_for(name, option_tags = nil, options = {})
587 def label_tag_for(name, option_tags = nil, options = {})
589 label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "")
588 label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "")
590 content_tag("label", label_text)
589 content_tag("label", label_text)
591 end
590 end
592
591
593 def labelled_tabular_form_for(name, object, options, &proc)
592 def labelled_tabular_form_for(name, object, options, &proc)
594 options[:html] ||= {}
593 options[:html] ||= {}
595 options[:html][:class] = 'tabular' unless options[:html].has_key?(:class)
594 options[:html][:class] = 'tabular' unless options[:html].has_key?(:class)
596 form_for(name, object, options.merge({ :builder => TabularFormBuilder, :lang => current_language}), &proc)
595 form_for(name, object, options.merge({ :builder => TabularFormBuilder, :lang => current_language}), &proc)
597 end
596 end
598
597
599 def back_url_hidden_field_tag
598 def back_url_hidden_field_tag
600 back_url = params[:back_url] || request.env['HTTP_REFERER']
599 back_url = params[:back_url] || request.env['HTTP_REFERER']
601 back_url = CGI.unescape(back_url.to_s)
600 back_url = CGI.unescape(back_url.to_s)
602 hidden_field_tag('back_url', CGI.escape(back_url)) unless back_url.blank?
601 hidden_field_tag('back_url', CGI.escape(back_url)) unless back_url.blank?
603 end
602 end
604
603
605 def check_all_links(form_name)
604 def check_all_links(form_name)
606 link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") +
605 link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") +
607 " | " +
606 " | " +
608 link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)")
607 link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)")
609 end
608 end
610
609
611 def progress_bar(pcts, options={})
610 def progress_bar(pcts, options={})
612 pcts = [pcts, pcts] unless pcts.is_a?(Array)
611 pcts = [pcts, pcts] unless pcts.is_a?(Array)
613 pcts[1] = pcts[1] - pcts[0]
612 pcts[1] = pcts[1] - pcts[0]
614 pcts << (100 - pcts[1] - pcts[0])
613 pcts << (100 - pcts[1] - pcts[0])
615 width = options[:width] || '100px;'
614 width = options[:width] || '100px;'
616 legend = options[:legend] || ''
615 legend = options[:legend] || ''
617 content_tag('table',
616 content_tag('table',
618 content_tag('tr',
617 content_tag('tr',
619 (pcts[0] > 0 ? content_tag('td', '', :style => "width: #{pcts[0].floor}%;", :class => 'closed') : '') +
618 (pcts[0] > 0 ? content_tag('td', '', :style => "width: #{pcts[0].floor}%;", :class => 'closed') : '') +
620 (pcts[1] > 0 ? content_tag('td', '', :style => "width: #{pcts[1].floor}%;", :class => 'done') : '') +
619 (pcts[1] > 0 ? content_tag('td', '', :style => "width: #{pcts[1].floor}%;", :class => 'done') : '') +
621 (pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2].floor}%;", :class => 'todo') : '')
620 (pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2].floor}%;", :class => 'todo') : '')
622 ), :class => 'progress', :style => "width: #{width};") +
621 ), :class => 'progress', :style => "width: #{width};") +
623 content_tag('p', legend, :class => 'pourcent')
622 content_tag('p', legend, :class => 'pourcent')
624 end
623 end
625
624
626 def context_menu_link(name, url, options={})
625 def context_menu_link(name, url, options={})
627 options[:class] ||= ''
626 options[:class] ||= ''
628 if options.delete(:selected)
627 if options.delete(:selected)
629 options[:class] << ' icon-checked disabled'
628 options[:class] << ' icon-checked disabled'
630 options[:disabled] = true
629 options[:disabled] = true
631 end
630 end
632 if options.delete(:disabled)
631 if options.delete(:disabled)
633 options.delete(:method)
632 options.delete(:method)
634 options.delete(:confirm)
633 options.delete(:confirm)
635 options.delete(:onclick)
634 options.delete(:onclick)
636 options[:class] << ' disabled'
635 options[:class] << ' disabled'
637 url = '#'
636 url = '#'
638 end
637 end
639 link_to name, url, options
638 link_to name, url, options
640 end
639 end
641
640
642 def calendar_for(field_id)
641 def calendar_for(field_id)
643 include_calendar_headers_tags
642 include_calendar_headers_tags
644 image_tag("calendar.png", {:id => "#{field_id}_trigger",:class => "calendar-trigger"}) +
643 image_tag("calendar.png", {:id => "#{field_id}_trigger",:class => "calendar-trigger"}) +
645 javascript_tag("Calendar.setup({inputField : '#{field_id}', ifFormat : '%Y-%m-%d', button : '#{field_id}_trigger' });")
644 javascript_tag("Calendar.setup({inputField : '#{field_id}', ifFormat : '%Y-%m-%d', button : '#{field_id}_trigger' });")
646 end
645 end
647
646
648 def include_calendar_headers_tags
647 def include_calendar_headers_tags
649 unless @calendar_headers_tags_included
648 unless @calendar_headers_tags_included
650 @calendar_headers_tags_included = true
649 @calendar_headers_tags_included = true
651 content_for :header_tags do
650 content_for :header_tags do
652 javascript_include_tag('calendar/calendar') +
651 javascript_include_tag('calendar/calendar') +
653 javascript_include_tag("calendar/lang/calendar-#{current_language.to_s.downcase}.js") +
652 javascript_include_tag("calendar/lang/calendar-#{current_language.to_s.downcase}.js") +
654 javascript_include_tag('calendar/calendar-setup') +
653 javascript_include_tag('calendar/calendar-setup') +
655 stylesheet_link_tag('calendar')
654 stylesheet_link_tag('calendar')
656 end
655 end
657 end
656 end
658 end
657 end
659
658
660 def content_for(name, content = nil, &block)
659 def content_for(name, content = nil, &block)
661 @has_content ||= {}
660 @has_content ||= {}
662 @has_content[name] = true
661 @has_content[name] = true
663 super(name, content, &block)
662 super(name, content, &block)
664 end
663 end
665
664
666 def has_content?(name)
665 def has_content?(name)
667 (@has_content && @has_content[name]) || false
666 (@has_content && @has_content[name]) || false
668 end
667 end
669
668
670 # Returns the avatar image tag for the given +user+ if avatars are enabled
669 # Returns the avatar image tag for the given +user+ if avatars are enabled
671 # +user+ can be a User or a string that will be scanned for an email address (eg. 'joe <joe@foo.bar>')
670 # +user+ can be a User or a string that will be scanned for an email address (eg. 'joe <joe@foo.bar>')
672 def avatar(user, options = { })
671 def avatar(user, options = { })
673 if Setting.gravatar_enabled?
672 if Setting.gravatar_enabled?
674 options.merge!({:ssl => Setting.protocol == 'https'})
673 options.merge!({:ssl => Setting.protocol == 'https'})
675 email = nil
674 email = nil
676 if user.respond_to?(:mail)
675 if user.respond_to?(:mail)
677 email = user.mail
676 email = user.mail
678 elsif user.to_s =~ %r{<(.+?)>}
677 elsif user.to_s =~ %r{<(.+?)>}
679 email = $1
678 email = $1
680 end
679 end
681 return gravatar(email.to_s.downcase, options) unless email.blank? rescue nil
680 return gravatar(email.to_s.downcase, options) unless email.blank? rescue nil
682 end
681 end
683 end
682 end
684
683
685 private
684 private
686
685
687 def wiki_helper
686 def wiki_helper
688 helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting)
687 helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting)
689 extend helper
688 extend helper
690 return self
689 return self
691 end
690 end
692
691
693 def link_to_remote_content_update(text, url_params)
692 def link_to_remote_content_update(text, url_params)
694 link_to_remote(text,
693 link_to_remote(text,
695 {:url => url_params, :method => :get, :update => 'content', :complete => 'window.scrollTo(0,0)'},
694 {:url => url_params, :method => :get, :update => 'content', :complete => 'window.scrollTo(0,0)'},
696 {:href => url_for(:params => url_params)}
695 {:href => url_for(:params => url_params)}
697 )
696 )
698 end
697 end
699
698
700 end
699 end
General Comments 0
You need to be logged in to leave comments. Login now