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