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