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