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