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