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