##// END OF EJS Templates
Adds noindex,noarchive robots meta tag on form pages (#7582)....
Jean-Philippe Lang -
r5323:ffd0a9c72c24
parent child
Show More
@@ -1,937 +1,941
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 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 #
35 #
36 # @param [String] name Anchor text (passed to link_to)
36 # @param [String] name Anchor text (passed to link_to)
37 # @param [Hash] options Hash params. This will checked by authorize_for to see if the user is authorized
37 # @param [Hash] options Hash params. This will checked by authorize_for to see if the user is authorized
38 # @param [optional, Hash] html_options Options passed to link_to
38 # @param [optional, Hash] html_options Options passed to link_to
39 # @param [optional, Hash] parameters_for_method_reference Extra parameters for link_to
39 # @param [optional, Hash] parameters_for_method_reference Extra parameters for link_to
40 def link_to_if_authorized(name, options = {}, html_options = nil, *parameters_for_method_reference)
40 def link_to_if_authorized(name, options = {}, html_options = nil, *parameters_for_method_reference)
41 link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for(options[:controller] || params[:controller], options[:action])
41 link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for(options[:controller] || params[:controller], options[:action])
42 end
42 end
43
43
44 # Display a link to remote if user is authorized
44 # Display a link to remote if user is authorized
45 def link_to_remote_if_authorized(name, options = {}, html_options = nil)
45 def link_to_remote_if_authorized(name, options = {}, html_options = nil)
46 url = options[:url] || {}
46 url = options[:url] || {}
47 link_to_remote(name, options, html_options) if authorize_for(url[:controller] || params[:controller], url[:action])
47 link_to_remote(name, options, html_options) if authorize_for(url[:controller] || params[:controller], url[:action])
48 end
48 end
49
49
50 # Displays a link to user's account page if active
50 # Displays a link to user's account page if active
51 def link_to_user(user, options={})
51 def link_to_user(user, options={})
52 if user.is_a?(User)
52 if user.is_a?(User)
53 name = h(user.name(options[:format]))
53 name = h(user.name(options[:format]))
54 if user.active?
54 if user.active?
55 link_to name, :controller => 'users', :action => 'show', :id => user
55 link_to name, :controller => 'users', :action => 'show', :id => user
56 else
56 else
57 name
57 name
58 end
58 end
59 else
59 else
60 h(user.to_s)
60 h(user.to_s)
61 end
61 end
62 end
62 end
63
63
64 # Displays a link to +issue+ with its subject.
64 # Displays a link to +issue+ with its subject.
65 # Examples:
65 # Examples:
66 #
66 #
67 # link_to_issue(issue) # => Defect #6: This is the subject
67 # link_to_issue(issue) # => Defect #6: This is the subject
68 # link_to_issue(issue, :truncate => 6) # => Defect #6: This i...
68 # link_to_issue(issue, :truncate => 6) # => Defect #6: This i...
69 # link_to_issue(issue, :subject => false) # => Defect #6
69 # link_to_issue(issue, :subject => false) # => Defect #6
70 # link_to_issue(issue, :project => true) # => Foo - Defect #6
70 # link_to_issue(issue, :project => true) # => Foo - Defect #6
71 #
71 #
72 def link_to_issue(issue, options={})
72 def link_to_issue(issue, options={})
73 title = nil
73 title = nil
74 subject = nil
74 subject = nil
75 if options[:subject] == false
75 if options[:subject] == false
76 title = truncate(issue.subject, :length => 60)
76 title = truncate(issue.subject, :length => 60)
77 else
77 else
78 subject = issue.subject
78 subject = issue.subject
79 if options[:truncate]
79 if options[:truncate]
80 subject = truncate(subject, :length => options[:truncate])
80 subject = truncate(subject, :length => options[:truncate])
81 end
81 end
82 end
82 end
83 s = link_to "#{issue.tracker} ##{issue.id}", {:controller => "issues", :action => "show", :id => issue},
83 s = link_to "#{issue.tracker} ##{issue.id}", {:controller => "issues", :action => "show", :id => issue},
84 :class => issue.css_classes,
84 :class => issue.css_classes,
85 :title => title
85 :title => title
86 s << ": #{h subject}" if subject
86 s << ": #{h subject}" if subject
87 s = "#{h issue.project} - " + s if options[:project]
87 s = "#{h issue.project} - " + s if options[:project]
88 s
88 s
89 end
89 end
90
90
91 # Generates a link to an attachment.
91 # Generates a link to an attachment.
92 # Options:
92 # Options:
93 # * :text - Link text (default to attachment filename)
93 # * :text - Link text (default to attachment filename)
94 # * :download - Force download (default: false)
94 # * :download - Force download (default: false)
95 def link_to_attachment(attachment, options={})
95 def link_to_attachment(attachment, options={})
96 text = options.delete(:text) || attachment.filename
96 text = options.delete(:text) || attachment.filename
97 action = options.delete(:download) ? 'download' : 'show'
97 action = options.delete(:download) ? 'download' : 'show'
98
98
99 link_to(h(text), {:controller => 'attachments', :action => action, :id => attachment, :filename => attachment.filename }, options)
99 link_to(h(text), {:controller => 'attachments', :action => action, :id => attachment, :filename => attachment.filename }, options)
100 end
100 end
101
101
102 # Generates a link to a SCM revision
102 # Generates a link to a SCM revision
103 # Options:
103 # Options:
104 # * :text - Link text (default to the formatted revision)
104 # * :text - Link text (default to the formatted revision)
105 def link_to_revision(revision, project, options={})
105 def link_to_revision(revision, project, options={})
106 text = options.delete(:text) || format_revision(revision)
106 text = options.delete(:text) || format_revision(revision)
107 rev = revision.respond_to?(:identifier) ? revision.identifier : revision
107 rev = revision.respond_to?(:identifier) ? revision.identifier : revision
108
108
109 link_to(text, {:controller => 'repositories', :action => 'revision', :id => project, :rev => rev},
109 link_to(text, {:controller => 'repositories', :action => 'revision', :id => project, :rev => rev},
110 :title => l(:label_revision_id, format_revision(revision)))
110 :title => l(:label_revision_id, format_revision(revision)))
111 end
111 end
112
112
113 # Generates a link to a message
113 # Generates a link to a message
114 def link_to_message(message, options={}, html_options = nil)
114 def link_to_message(message, options={}, html_options = nil)
115 link_to(
115 link_to(
116 h(truncate(message.subject, :length => 60)),
116 h(truncate(message.subject, :length => 60)),
117 { :controller => 'messages', :action => 'show',
117 { :controller => 'messages', :action => 'show',
118 :board_id => message.board_id,
118 :board_id => message.board_id,
119 :id => message.root,
119 :id => message.root,
120 :r => (message.parent_id && message.id),
120 :r => (message.parent_id && message.id),
121 :anchor => (message.parent_id ? "message-#{message.id}" : nil)
121 :anchor => (message.parent_id ? "message-#{message.id}" : nil)
122 }.merge(options),
122 }.merge(options),
123 html_options
123 html_options
124 )
124 )
125 end
125 end
126
126
127 # Generates a link to a project if active
127 # Generates a link to a project if active
128 # Examples:
128 # Examples:
129 #
129 #
130 # link_to_project(project) # => link to the specified project overview
130 # link_to_project(project) # => link to the specified project overview
131 # link_to_project(project, :action=>'settings') # => link to project settings
131 # link_to_project(project, :action=>'settings') # => link to project settings
132 # link_to_project(project, {:only_path => false}, :class => "project") # => 3rd arg adds html options
132 # link_to_project(project, {:only_path => false}, :class => "project") # => 3rd arg adds html options
133 # link_to_project(project, {}, :class => "project") # => html options with default url (project overview)
133 # link_to_project(project, {}, :class => "project") # => html options with default url (project overview)
134 #
134 #
135 def link_to_project(project, options={}, html_options = nil)
135 def link_to_project(project, options={}, html_options = nil)
136 if project.active?
136 if project.active?
137 url = {:controller => 'projects', :action => 'show', :id => project}.merge(options)
137 url = {:controller => 'projects', :action => 'show', :id => project}.merge(options)
138 link_to(h(project), url, html_options)
138 link_to(h(project), url, html_options)
139 else
139 else
140 h(project)
140 h(project)
141 end
141 end
142 end
142 end
143
143
144 def toggle_link(name, id, options={})
144 def toggle_link(name, id, options={})
145 onclick = "Element.toggle('#{id}'); "
145 onclick = "Element.toggle('#{id}'); "
146 onclick << (options[:focus] ? "Form.Element.focus('#{options[:focus]}'); " : "this.blur(); ")
146 onclick << (options[:focus] ? "Form.Element.focus('#{options[:focus]}'); " : "this.blur(); ")
147 onclick << "return false;"
147 onclick << "return false;"
148 link_to(name, "#", :onclick => onclick)
148 link_to(name, "#", :onclick => onclick)
149 end
149 end
150
150
151 def image_to_function(name, function, html_options = {})
151 def image_to_function(name, function, html_options = {})
152 html_options.symbolize_keys!
152 html_options.symbolize_keys!
153 tag(:input, html_options.merge({
153 tag(:input, html_options.merge({
154 :type => "image", :src => image_path(name),
154 :type => "image", :src => image_path(name),
155 :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};"
155 :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};"
156 }))
156 }))
157 end
157 end
158
158
159 def prompt_to_remote(name, text, param, url, html_options = {})
159 def prompt_to_remote(name, text, param, url, html_options = {})
160 html_options[:onclick] = "promptToRemote('#{text}', '#{param}', '#{url_for(url)}'); return false;"
160 html_options[:onclick] = "promptToRemote('#{text}', '#{param}', '#{url_for(url)}'); return false;"
161 link_to name, {}, html_options
161 link_to name, {}, html_options
162 end
162 end
163
163
164 def format_activity_title(text)
164 def format_activity_title(text)
165 h(truncate_single_line(text, :length => 100))
165 h(truncate_single_line(text, :length => 100))
166 end
166 end
167
167
168 def format_activity_day(date)
168 def format_activity_day(date)
169 date == Date.today ? l(:label_today).titleize : format_date(date)
169 date == Date.today ? l(:label_today).titleize : format_date(date)
170 end
170 end
171
171
172 def format_activity_description(text)
172 def format_activity_description(text)
173 h(truncate(text.to_s, :length => 120).gsub(%r{[\r\n]*<(pre|code)>.*$}m, '...')).gsub(/[\r\n]+/, "<br />")
173 h(truncate(text.to_s, :length => 120).gsub(%r{[\r\n]*<(pre|code)>.*$}m, '...')).gsub(/[\r\n]+/, "<br />")
174 end
174 end
175
175
176 def format_version_name(version)
176 def format_version_name(version)
177 if version.project == @project
177 if version.project == @project
178 h(version)
178 h(version)
179 else
179 else
180 h("#{version.project} - #{version}")
180 h("#{version.project} - #{version}")
181 end
181 end
182 end
182 end
183
183
184 def due_date_distance_in_words(date)
184 def due_date_distance_in_words(date)
185 if date
185 if date
186 l((date < Date.today ? :label_roadmap_overdue : :label_roadmap_due_in), distance_of_date_in_words(Date.today, date))
186 l((date < Date.today ? :label_roadmap_overdue : :label_roadmap_due_in), distance_of_date_in_words(Date.today, date))
187 end
187 end
188 end
188 end
189
189
190 def render_page_hierarchy(pages, node=nil, options={})
190 def render_page_hierarchy(pages, node=nil, options={})
191 content = ''
191 content = ''
192 if pages[node]
192 if pages[node]
193 content << "<ul class=\"pages-hierarchy\">\n"
193 content << "<ul class=\"pages-hierarchy\">\n"
194 pages[node].each do |page|
194 pages[node].each do |page|
195 content << "<li>"
195 content << "<li>"
196 content << link_to(h(page.pretty_title), {:controller => 'wiki', :action => 'show', :project_id => page.project, :id => page.title},
196 content << link_to(h(page.pretty_title), {:controller => 'wiki', :action => 'show', :project_id => page.project, :id => page.title},
197 :title => (options[:timestamp] && page.updated_on ? l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on)) : nil))
197 :title => (options[:timestamp] && page.updated_on ? l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on)) : nil))
198 content << "\n" + render_page_hierarchy(pages, page.id, options) if pages[page.id]
198 content << "\n" + render_page_hierarchy(pages, page.id, options) if pages[page.id]
199 content << "</li>\n"
199 content << "</li>\n"
200 end
200 end
201 content << "</ul>\n"
201 content << "</ul>\n"
202 end
202 end
203 content
203 content
204 end
204 end
205
205
206 # Renders flash messages
206 # Renders flash messages
207 def render_flash_messages
207 def render_flash_messages
208 s = ''
208 s = ''
209 flash.each do |k,v|
209 flash.each do |k,v|
210 s << content_tag('div', v, :class => "flash #{k}")
210 s << content_tag('div', v, :class => "flash #{k}")
211 end
211 end
212 s
212 s
213 end
213 end
214
214
215 # Renders tabs and their content
215 # Renders tabs and their content
216 def render_tabs(tabs)
216 def render_tabs(tabs)
217 if tabs.any?
217 if tabs.any?
218 render :partial => 'common/tabs', :locals => {:tabs => tabs}
218 render :partial => 'common/tabs', :locals => {:tabs => tabs}
219 else
219 else
220 content_tag 'p', l(:label_no_data), :class => "nodata"
220 content_tag 'p', l(:label_no_data), :class => "nodata"
221 end
221 end
222 end
222 end
223
223
224 # Renders the project quick-jump box
224 # Renders the project quick-jump box
225 def render_project_jump_box
225 def render_project_jump_box
226 projects = User.current.memberships.collect(&:project).compact.uniq
226 projects = User.current.memberships.collect(&:project).compact.uniq
227 if projects.any?
227 if projects.any?
228 s = '<select onchange="if (this.value != \'\') { window.location = this.value; }">' +
228 s = '<select onchange="if (this.value != \'\') { window.location = this.value; }">' +
229 "<option value=''>#{ l(:label_jump_to_a_project) }</option>" +
229 "<option value=''>#{ l(:label_jump_to_a_project) }</option>" +
230 '<option value="" disabled="disabled">---</option>'
230 '<option value="" disabled="disabled">---</option>'
231 s << project_tree_options_for_select(projects, :selected => @project) do |p|
231 s << project_tree_options_for_select(projects, :selected => @project) do |p|
232 { :value => url_for(:controller => 'projects', :action => 'show', :id => p, :jump => current_menu_item) }
232 { :value => url_for(:controller => 'projects', :action => 'show', :id => p, :jump => current_menu_item) }
233 end
233 end
234 s << '</select>'
234 s << '</select>'
235 s
235 s
236 end
236 end
237 end
237 end
238
238
239 def project_tree_options_for_select(projects, options = {})
239 def project_tree_options_for_select(projects, options = {})
240 s = ''
240 s = ''
241 project_tree(projects) do |project, level|
241 project_tree(projects) do |project, level|
242 name_prefix = (level > 0 ? ('&nbsp;' * 2 * level + '&#187; ') : '')
242 name_prefix = (level > 0 ? ('&nbsp;' * 2 * level + '&#187; ') : '')
243 tag_options = {:value => project.id}
243 tag_options = {:value => project.id}
244 if project == options[:selected] || (options[:selected].respond_to?(:include?) && options[:selected].include?(project))
244 if project == options[:selected] || (options[:selected].respond_to?(:include?) && options[:selected].include?(project))
245 tag_options[:selected] = 'selected'
245 tag_options[:selected] = 'selected'
246 else
246 else
247 tag_options[:selected] = nil
247 tag_options[:selected] = nil
248 end
248 end
249 tag_options.merge!(yield(project)) if block_given?
249 tag_options.merge!(yield(project)) if block_given?
250 s << content_tag('option', name_prefix + h(project), tag_options)
250 s << content_tag('option', name_prefix + h(project), tag_options)
251 end
251 end
252 s
252 s
253 end
253 end
254
254
255 # Yields the given block for each project with its level in the tree
255 # Yields the given block for each project with its level in the tree
256 #
256 #
257 # Wrapper for Project#project_tree
257 # Wrapper for Project#project_tree
258 def project_tree(projects, &block)
258 def project_tree(projects, &block)
259 Project.project_tree(projects, &block)
259 Project.project_tree(projects, &block)
260 end
260 end
261
261
262 def project_nested_ul(projects, &block)
262 def project_nested_ul(projects, &block)
263 s = ''
263 s = ''
264 if projects.any?
264 if projects.any?
265 ancestors = []
265 ancestors = []
266 projects.sort_by(&:lft).each do |project|
266 projects.sort_by(&:lft).each do |project|
267 if (ancestors.empty? || project.is_descendant_of?(ancestors.last))
267 if (ancestors.empty? || project.is_descendant_of?(ancestors.last))
268 s << "<ul>\n"
268 s << "<ul>\n"
269 else
269 else
270 ancestors.pop
270 ancestors.pop
271 s << "</li>"
271 s << "</li>"
272 while (ancestors.any? && !project.is_descendant_of?(ancestors.last))
272 while (ancestors.any? && !project.is_descendant_of?(ancestors.last))
273 ancestors.pop
273 ancestors.pop
274 s << "</ul></li>\n"
274 s << "</ul></li>\n"
275 end
275 end
276 end
276 end
277 s << "<li>"
277 s << "<li>"
278 s << yield(project).to_s
278 s << yield(project).to_s
279 ancestors << project
279 ancestors << project
280 end
280 end
281 s << ("</li></ul>\n" * ancestors.size)
281 s << ("</li></ul>\n" * ancestors.size)
282 end
282 end
283 s
283 s
284 end
284 end
285
285
286 def principals_check_box_tags(name, principals)
286 def principals_check_box_tags(name, principals)
287 s = ''
287 s = ''
288 principals.sort.each do |principal|
288 principals.sort.each do |principal|
289 s << "<label>#{ check_box_tag name, principal.id, false } #{h principal}</label>\n"
289 s << "<label>#{ check_box_tag name, principal.id, false } #{h principal}</label>\n"
290 end
290 end
291 s
291 s
292 end
292 end
293
293
294 # Truncates and returns the string as a single line
294 # Truncates and returns the string as a single line
295 def truncate_single_line(string, *args)
295 def truncate_single_line(string, *args)
296 truncate(string.to_s, *args).gsub(%r{[\r\n]+}m, ' ')
296 truncate(string.to_s, *args).gsub(%r{[\r\n]+}m, ' ')
297 end
297 end
298
298
299 # Truncates at line break after 250 characters or options[:length]
299 # Truncates at line break after 250 characters or options[:length]
300 def truncate_lines(string, options={})
300 def truncate_lines(string, options={})
301 length = options[:length] || 250
301 length = options[:length] || 250
302 if string.to_s =~ /\A(.{#{length}}.*?)$/m
302 if string.to_s =~ /\A(.{#{length}}.*?)$/m
303 "#{$1}..."
303 "#{$1}..."
304 else
304 else
305 string
305 string
306 end
306 end
307 end
307 end
308
308
309 def html_hours(text)
309 def html_hours(text)
310 text.gsub(%r{(\d+)\.(\d+)}, '<span class="hours hours-int">\1</span><span class="hours hours-dec">.\2</span>')
310 text.gsub(%r{(\d+)\.(\d+)}, '<span class="hours hours-int">\1</span><span class="hours hours-dec">.\2</span>')
311 end
311 end
312
312
313 def authoring(created, author, options={})
313 def authoring(created, author, options={})
314 l(options[:label] || :label_added_time_by, :author => link_to_user(author), :age => time_tag(created))
314 l(options[:label] || :label_added_time_by, :author => link_to_user(author), :age => time_tag(created))
315 end
315 end
316
316
317 def time_tag(time)
317 def time_tag(time)
318 text = distance_of_time_in_words(Time.now, time)
318 text = distance_of_time_in_words(Time.now, time)
319 if @project
319 if @project
320 link_to(text, {:controller => 'activities', :action => 'index', :id => @project, :from => time.to_date}, :title => format_time(time))
320 link_to(text, {:controller => 'activities', :action => 'index', :id => @project, :from => time.to_date}, :title => format_time(time))
321 else
321 else
322 content_tag('acronym', text, :title => format_time(time))
322 content_tag('acronym', text, :title => format_time(time))
323 end
323 end
324 end
324 end
325
325
326 def syntax_highlight(name, content)
326 def syntax_highlight(name, content)
327 Redmine::SyntaxHighlighting.highlight_by_filename(content, name)
327 Redmine::SyntaxHighlighting.highlight_by_filename(content, name)
328 end
328 end
329
329
330 def to_path_param(path)
330 def to_path_param(path)
331 path.to_s.split(%r{[/\\]}).select {|p| !p.blank?}
331 path.to_s.split(%r{[/\\]}).select {|p| !p.blank?}
332 end
332 end
333
333
334 def pagination_links_full(paginator, count=nil, options={})
334 def pagination_links_full(paginator, count=nil, options={})
335 page_param = options.delete(:page_param) || :page
335 page_param = options.delete(:page_param) || :page
336 per_page_links = options.delete(:per_page_links)
336 per_page_links = options.delete(:per_page_links)
337 url_param = params.dup
337 url_param = params.dup
338
338
339 html = ''
339 html = ''
340 if paginator.current.previous
340 if paginator.current.previous
341 html << link_to_content_update('&#171; ' + l(:label_previous), url_param.merge(page_param => paginator.current.previous)) + ' '
341 html << link_to_content_update('&#171; ' + l(:label_previous), url_param.merge(page_param => paginator.current.previous)) + ' '
342 end
342 end
343
343
344 html << (pagination_links_each(paginator, options) do |n|
344 html << (pagination_links_each(paginator, options) do |n|
345 link_to_content_update(n.to_s, url_param.merge(page_param => n))
345 link_to_content_update(n.to_s, url_param.merge(page_param => n))
346 end || '')
346 end || '')
347
347
348 if paginator.current.next
348 if paginator.current.next
349 html << ' ' + link_to_content_update((l(:label_next) + ' &#187;'), url_param.merge(page_param => paginator.current.next))
349 html << ' ' + link_to_content_update((l(:label_next) + ' &#187;'), url_param.merge(page_param => paginator.current.next))
350 end
350 end
351
351
352 unless count.nil?
352 unless count.nil?
353 html << " (#{paginator.current.first_item}-#{paginator.current.last_item}/#{count})"
353 html << " (#{paginator.current.first_item}-#{paginator.current.last_item}/#{count})"
354 if per_page_links != false && links = per_page_links(paginator.items_per_page)
354 if per_page_links != false && links = per_page_links(paginator.items_per_page)
355 html << " | #{links}"
355 html << " | #{links}"
356 end
356 end
357 end
357 end
358
358
359 html
359 html
360 end
360 end
361
361
362 def per_page_links(selected=nil)
362 def per_page_links(selected=nil)
363 links = Setting.per_page_options_array.collect do |n|
363 links = Setting.per_page_options_array.collect do |n|
364 n == selected ? n : link_to_content_update(n, params.merge(:per_page => n))
364 n == selected ? n : link_to_content_update(n, params.merge(:per_page => n))
365 end
365 end
366 links.size > 1 ? l(:label_display_per_page, links.join(', ')) : nil
366 links.size > 1 ? l(:label_display_per_page, links.join(', ')) : nil
367 end
367 end
368
368
369 def reorder_links(name, url)
369 def reorder_links(name, url)
370 link_to(image_tag('2uparrow.png', :alt => l(:label_sort_highest)), url.merge({"#{name}[move_to]" => 'highest'}), :method => :post, :title => l(:label_sort_highest)) +
370 link_to(image_tag('2uparrow.png', :alt => l(:label_sort_highest)), url.merge({"#{name}[move_to]" => 'highest'}), :method => :post, :title => l(:label_sort_highest)) +
371 link_to(image_tag('1uparrow.png', :alt => l(:label_sort_higher)), url.merge({"#{name}[move_to]" => 'higher'}), :method => :post, :title => l(:label_sort_higher)) +
371 link_to(image_tag('1uparrow.png', :alt => l(:label_sort_higher)), url.merge({"#{name}[move_to]" => 'higher'}), :method => :post, :title => l(:label_sort_higher)) +
372 link_to(image_tag('1downarrow.png', :alt => l(:label_sort_lower)), url.merge({"#{name}[move_to]" => 'lower'}), :method => :post, :title => l(:label_sort_lower)) +
372 link_to(image_tag('1downarrow.png', :alt => l(:label_sort_lower)), url.merge({"#{name}[move_to]" => 'lower'}), :method => :post, :title => l(:label_sort_lower)) +
373 link_to(image_tag('2downarrow.png', :alt => l(:label_sort_lowest)), url.merge({"#{name}[move_to]" => 'lowest'}), :method => :post, :title => l(:label_sort_lowest))
373 link_to(image_tag('2downarrow.png', :alt => l(:label_sort_lowest)), url.merge({"#{name}[move_to]" => 'lowest'}), :method => :post, :title => l(:label_sort_lowest))
374 end
374 end
375
375
376 def breadcrumb(*args)
376 def breadcrumb(*args)
377 elements = args.flatten
377 elements = args.flatten
378 elements.any? ? content_tag('p', args.join(' &#187; ') + ' &#187; ', :class => 'breadcrumb') : nil
378 elements.any? ? content_tag('p', args.join(' &#187; ') + ' &#187; ', :class => 'breadcrumb') : nil
379 end
379 end
380
380
381 def other_formats_links(&block)
381 def other_formats_links(&block)
382 concat('<p class="other-formats">' + l(:label_export_to))
382 concat('<p class="other-formats">' + l(:label_export_to))
383 yield Redmine::Views::OtherFormatsBuilder.new(self)
383 yield Redmine::Views::OtherFormatsBuilder.new(self)
384 concat('</p>')
384 concat('</p>')
385 end
385 end
386
386
387 def page_header_title
387 def page_header_title
388 if @project.nil? || @project.new_record?
388 if @project.nil? || @project.new_record?
389 h(Setting.app_title)
389 h(Setting.app_title)
390 else
390 else
391 b = []
391 b = []
392 ancestors = (@project.root? ? [] : @project.ancestors.visible)
392 ancestors = (@project.root? ? [] : @project.ancestors.visible)
393 if ancestors.any?
393 if ancestors.any?
394 root = ancestors.shift
394 root = ancestors.shift
395 b << link_to_project(root, {:jump => current_menu_item}, :class => 'root')
395 b << link_to_project(root, {:jump => current_menu_item}, :class => 'root')
396 if ancestors.size > 2
396 if ancestors.size > 2
397 b << '&#8230;'
397 b << '&#8230;'
398 ancestors = ancestors[-2, 2]
398 ancestors = ancestors[-2, 2]
399 end
399 end
400 b += ancestors.collect {|p| link_to_project(p, {:jump => current_menu_item}, :class => 'ancestor') }
400 b += ancestors.collect {|p| link_to_project(p, {:jump => current_menu_item}, :class => 'ancestor') }
401 end
401 end
402 b << h(@project)
402 b << h(@project)
403 b.join(' &#187; ')
403 b.join(' &#187; ')
404 end
404 end
405 end
405 end
406
406
407 def html_title(*args)
407 def html_title(*args)
408 if args.empty?
408 if args.empty?
409 title = []
409 title = []
410 title << @project.name if @project
410 title << @project.name if @project
411 title += @html_title if @html_title
411 title += @html_title if @html_title
412 title << Setting.app_title
412 title << Setting.app_title
413 title.select {|t| !t.blank? }.join(' - ')
413 title.select {|t| !t.blank? }.join(' - ')
414 else
414 else
415 @html_title ||= []
415 @html_title ||= []
416 @html_title += args
416 @html_title += args
417 end
417 end
418 end
418 end
419
419
420 # Returns the theme, controller name, and action as css classes for the
420 # Returns the theme, controller name, and action as css classes for the
421 # HTML body.
421 # HTML body.
422 def body_css_classes
422 def body_css_classes
423 css = []
423 css = []
424 if theme = Redmine::Themes.theme(Setting.ui_theme)
424 if theme = Redmine::Themes.theme(Setting.ui_theme)
425 css << 'theme-' + theme.name
425 css << 'theme-' + theme.name
426 end
426 end
427
427
428 css << 'controller-' + params[:controller]
428 css << 'controller-' + params[:controller]
429 css << 'action-' + params[:action]
429 css << 'action-' + params[:action]
430 css.join(' ')
430 css.join(' ')
431 end
431 end
432
432
433 def accesskey(s)
433 def accesskey(s)
434 Redmine::AccessKeys.key_for s
434 Redmine::AccessKeys.key_for s
435 end
435 end
436
436
437 # Formats text according to system settings.
437 # Formats text according to system settings.
438 # 2 ways to call this method:
438 # 2 ways to call this method:
439 # * with a String: textilizable(text, options)
439 # * with a String: textilizable(text, options)
440 # * with an object and one of its attribute: textilizable(issue, :description, options)
440 # * with an object and one of its attribute: textilizable(issue, :description, options)
441 def textilizable(*args)
441 def textilizable(*args)
442 options = args.last.is_a?(Hash) ? args.pop : {}
442 options = args.last.is_a?(Hash) ? args.pop : {}
443 case args.size
443 case args.size
444 when 1
444 when 1
445 obj = options[:object]
445 obj = options[:object]
446 text = args.shift
446 text = args.shift
447 when 2
447 when 2
448 obj = args.shift
448 obj = args.shift
449 attr = args.shift
449 attr = args.shift
450 text = obj.send(attr).to_s
450 text = obj.send(attr).to_s
451 else
451 else
452 raise ArgumentError, 'invalid arguments to textilizable'
452 raise ArgumentError, 'invalid arguments to textilizable'
453 end
453 end
454 return '' if text.blank?
454 return '' if text.blank?
455 project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil)
455 project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil)
456 only_path = options.delete(:only_path) == false ? false : true
456 only_path = options.delete(:only_path) == false ? false : true
457
457
458 text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text, :object => obj, :attribute => attr) { |macro, args| exec_macro(macro, obj, args) }
458 text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text, :object => obj, :attribute => attr) { |macro, args| exec_macro(macro, obj, args) }
459
459
460 @parsed_headings = []
460 @parsed_headings = []
461 text = parse_non_pre_blocks(text) do |text|
461 text = parse_non_pre_blocks(text) do |text|
462 [:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links, :parse_headings].each do |method_name|
462 [:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links, :parse_headings].each do |method_name|
463 send method_name, text, project, obj, attr, only_path, options
463 send method_name, text, project, obj, attr, only_path, options
464 end
464 end
465 end
465 end
466
466
467 if @parsed_headings.any?
467 if @parsed_headings.any?
468 replace_toc(text, @parsed_headings)
468 replace_toc(text, @parsed_headings)
469 end
469 end
470
470
471 text
471 text
472 end
472 end
473
473
474 def parse_non_pre_blocks(text)
474 def parse_non_pre_blocks(text)
475 s = StringScanner.new(text)
475 s = StringScanner.new(text)
476 tags = []
476 tags = []
477 parsed = ''
477 parsed = ''
478 while !s.eos?
478 while !s.eos?
479 s.scan(/(.*?)(<(\/)?(pre|code)(.*?)>|\z)/im)
479 s.scan(/(.*?)(<(\/)?(pre|code)(.*?)>|\z)/im)
480 text, full_tag, closing, tag = s[1], s[2], s[3], s[4]
480 text, full_tag, closing, tag = s[1], s[2], s[3], s[4]
481 if tags.empty?
481 if tags.empty?
482 yield text
482 yield text
483 end
483 end
484 parsed << text
484 parsed << text
485 if tag
485 if tag
486 if closing
486 if closing
487 if tags.last == tag.downcase
487 if tags.last == tag.downcase
488 tags.pop
488 tags.pop
489 end
489 end
490 else
490 else
491 tags << tag.downcase
491 tags << tag.downcase
492 end
492 end
493 parsed << full_tag
493 parsed << full_tag
494 end
494 end
495 end
495 end
496 # Close any non closing tags
496 # Close any non closing tags
497 while tag = tags.pop
497 while tag = tags.pop
498 parsed << "</#{tag}>"
498 parsed << "</#{tag}>"
499 end
499 end
500 parsed
500 parsed
501 end
501 end
502
502
503 def parse_inline_attachments(text, project, obj, attr, only_path, options)
503 def parse_inline_attachments(text, project, obj, attr, only_path, options)
504 # when using an image link, try to use an attachment, if possible
504 # when using an image link, try to use an attachment, if possible
505 if options[:attachments] || (obj && obj.respond_to?(:attachments))
505 if options[:attachments] || (obj && obj.respond_to?(:attachments))
506 attachments = nil
506 attachments = nil
507 text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m|
507 text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m|
508 filename, ext, alt, alttext = $1.downcase, $2, $3, $4
508 filename, ext, alt, alttext = $1.downcase, $2, $3, $4
509 attachments ||= (options[:attachments] || obj.attachments).sort_by(&:created_on).reverse
509 attachments ||= (options[:attachments] || obj.attachments).sort_by(&:created_on).reverse
510 # search for the picture in attachments
510 # search for the picture in attachments
511 if found = attachments.detect { |att| att.filename.downcase == filename }
511 if found = attachments.detect { |att| att.filename.downcase == filename }
512 image_url = url_for :only_path => only_path, :controller => 'attachments', :action => 'download', :id => found
512 image_url = url_for :only_path => only_path, :controller => 'attachments', :action => 'download', :id => found
513 desc = found.description.to_s.gsub('"', '')
513 desc = found.description.to_s.gsub('"', '')
514 if !desc.blank? && alttext.blank?
514 if !desc.blank? && alttext.blank?
515 alt = " title=\"#{desc}\" alt=\"#{desc}\""
515 alt = " title=\"#{desc}\" alt=\"#{desc}\""
516 end
516 end
517 "src=\"#{image_url}\"#{alt}"
517 "src=\"#{image_url}\"#{alt}"
518 else
518 else
519 m
519 m
520 end
520 end
521 end
521 end
522 end
522 end
523 end
523 end
524
524
525 # Wiki links
525 # Wiki links
526 #
526 #
527 # Examples:
527 # Examples:
528 # [[mypage]]
528 # [[mypage]]
529 # [[mypage|mytext]]
529 # [[mypage|mytext]]
530 # wiki links can refer other project wikis, using project name or identifier:
530 # wiki links can refer other project wikis, using project name or identifier:
531 # [[project:]] -> wiki starting page
531 # [[project:]] -> wiki starting page
532 # [[project:|mytext]]
532 # [[project:|mytext]]
533 # [[project:mypage]]
533 # [[project:mypage]]
534 # [[project:mypage|mytext]]
534 # [[project:mypage|mytext]]
535 def parse_wiki_links(text, project, obj, attr, only_path, options)
535 def parse_wiki_links(text, project, obj, attr, only_path, options)
536 text.gsub!(/(!)?(\[\[([^\]\n\|]+)(\|([^\]\n\|]+))?\]\])/) do |m|
536 text.gsub!(/(!)?(\[\[([^\]\n\|]+)(\|([^\]\n\|]+))?\]\])/) do |m|
537 link_project = project
537 link_project = project
538 esc, all, page, title = $1, $2, $3, $5
538 esc, all, page, title = $1, $2, $3, $5
539 if esc.nil?
539 if esc.nil?
540 if page =~ /^([^\:]+)\:(.*)$/
540 if page =~ /^([^\:]+)\:(.*)$/
541 link_project = Project.find_by_identifier($1) || Project.find_by_name($1)
541 link_project = Project.find_by_identifier($1) || Project.find_by_name($1)
542 page = $2
542 page = $2
543 title ||= $1 if page.blank?
543 title ||= $1 if page.blank?
544 end
544 end
545
545
546 if link_project && link_project.wiki
546 if link_project && link_project.wiki
547 # extract anchor
547 # extract anchor
548 anchor = nil
548 anchor = nil
549 if page =~ /^(.+?)\#(.+)$/
549 if page =~ /^(.+?)\#(.+)$/
550 page, anchor = $1, $2
550 page, anchor = $1, $2
551 end
551 end
552 # check if page exists
552 # check if page exists
553 wiki_page = link_project.wiki.find_page(page)
553 wiki_page = link_project.wiki.find_page(page)
554 url = case options[:wiki_links]
554 url = case options[:wiki_links]
555 when :local; "#{title}.html"
555 when :local; "#{title}.html"
556 when :anchor; "##{title}" # used for single-file wiki export
556 when :anchor; "##{title}" # used for single-file wiki export
557 else
557 else
558 wiki_page_id = page.present? ? Wiki.titleize(page) : nil
558 wiki_page_id = page.present? ? Wiki.titleize(page) : nil
559 url_for(:only_path => only_path, :controller => 'wiki', :action => 'show', :project_id => link_project, :id => wiki_page_id, :anchor => anchor)
559 url_for(:only_path => only_path, :controller => 'wiki', :action => 'show', :project_id => link_project, :id => wiki_page_id, :anchor => anchor)
560 end
560 end
561 link_to((title || page), url, :class => ('wiki-page' + (wiki_page ? '' : ' new')))
561 link_to((title || page), url, :class => ('wiki-page' + (wiki_page ? '' : ' new')))
562 else
562 else
563 # project or wiki doesn't exist
563 # project or wiki doesn't exist
564 all
564 all
565 end
565 end
566 else
566 else
567 all
567 all
568 end
568 end
569 end
569 end
570 end
570 end
571
571
572 # Redmine links
572 # Redmine links
573 #
573 #
574 # Examples:
574 # Examples:
575 # Issues:
575 # Issues:
576 # #52 -> Link to issue #52
576 # #52 -> Link to issue #52
577 # Changesets:
577 # Changesets:
578 # r52 -> Link to revision 52
578 # r52 -> Link to revision 52
579 # commit:a85130f -> Link to scmid starting with a85130f
579 # commit:a85130f -> Link to scmid starting with a85130f
580 # Documents:
580 # Documents:
581 # document#17 -> Link to document with id 17
581 # document#17 -> Link to document with id 17
582 # document:Greetings -> Link to the document with title "Greetings"
582 # document:Greetings -> Link to the document with title "Greetings"
583 # document:"Some document" -> Link to the document with title "Some document"
583 # document:"Some document" -> Link to the document with title "Some document"
584 # Versions:
584 # Versions:
585 # version#3 -> Link to version with id 3
585 # version#3 -> Link to version with id 3
586 # version:1.0.0 -> Link to version named "1.0.0"
586 # version:1.0.0 -> Link to version named "1.0.0"
587 # version:"1.0 beta 2" -> Link to version named "1.0 beta 2"
587 # version:"1.0 beta 2" -> Link to version named "1.0 beta 2"
588 # Attachments:
588 # Attachments:
589 # attachment:file.zip -> Link to the attachment of the current object named file.zip
589 # attachment:file.zip -> Link to the attachment of the current object named file.zip
590 # Source files:
590 # Source files:
591 # source:some/file -> Link to the file located at /some/file in the project's repository
591 # source:some/file -> Link to the file located at /some/file in the project's repository
592 # source:some/file@52 -> Link to the file's revision 52
592 # source:some/file@52 -> Link to the file's revision 52
593 # source:some/file#L120 -> Link to line 120 of the file
593 # source:some/file#L120 -> Link to line 120 of the file
594 # source:some/file@52#L120 -> Link to line 120 of the file's revision 52
594 # source:some/file@52#L120 -> Link to line 120 of the file's revision 52
595 # export:some/file -> Force the download of the file
595 # export:some/file -> Force the download of the file
596 # Forum messages:
596 # Forum messages:
597 # message#1218 -> Link to message with id 1218
597 # message#1218 -> Link to message with id 1218
598 #
598 #
599 # Links can refer other objects from other projects, using project identifier:
599 # Links can refer other objects from other projects, using project identifier:
600 # identifier:r52
600 # identifier:r52
601 # identifier:document:"Some document"
601 # identifier:document:"Some document"
602 # identifier:version:1.0.0
602 # identifier:version:1.0.0
603 # identifier:source:some/file
603 # identifier:source:some/file
604 def parse_redmine_links(text, project, obj, attr, only_path, options)
604 def parse_redmine_links(text, project, obj, attr, only_path, options)
605 text.gsub!(%r{([\s\(,\-\[\>]|^)(!)?(([a-z0-9\-]+):)?(attachment|document|version|commit|source|export|message|project)?((#|r)(\d+)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]]\W)|,|\s|\]|<|$)}) do |m|
605 text.gsub!(%r{([\s\(,\-\[\>]|^)(!)?(([a-z0-9\-]+):)?(attachment|document|version|commit|source|export|message|project)?((#|r)(\d+)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]]\W)|,|\s|\]|<|$)}) do |m|
606 leading, esc, project_prefix, project_identifier, prefix, sep, identifier = $1, $2, $3, $4, $5, $7 || $9, $8 || $10
606 leading, esc, project_prefix, project_identifier, prefix, sep, identifier = $1, $2, $3, $4, $5, $7 || $9, $8 || $10
607 link = nil
607 link = nil
608 if project_identifier
608 if project_identifier
609 project = Project.visible.find_by_identifier(project_identifier)
609 project = Project.visible.find_by_identifier(project_identifier)
610 end
610 end
611 if esc.nil?
611 if esc.nil?
612 if prefix.nil? && sep == 'r'
612 if prefix.nil? && sep == 'r'
613 # project.changesets.visible raises an SQL error because of a double join on repositories
613 # project.changesets.visible raises an SQL error because of a double join on repositories
614 if project && project.repository && (changeset = Changeset.visible.find_by_repository_id_and_revision(project.repository.id, identifier))
614 if project && project.repository && (changeset = Changeset.visible.find_by_repository_id_and_revision(project.repository.id, identifier))
615 link = link_to("#{project_prefix}r#{identifier}", {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.revision},
615 link = link_to("#{project_prefix}r#{identifier}", {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.revision},
616 :class => 'changeset',
616 :class => 'changeset',
617 :title => truncate_single_line(changeset.comments, :length => 100))
617 :title => truncate_single_line(changeset.comments, :length => 100))
618 end
618 end
619 elsif sep == '#'
619 elsif sep == '#'
620 oid = identifier.to_i
620 oid = identifier.to_i
621 case prefix
621 case prefix
622 when nil
622 when nil
623 if issue = Issue.visible.find_by_id(oid, :include => :status)
623 if issue = Issue.visible.find_by_id(oid, :include => :status)
624 link = link_to("##{oid}", {:only_path => only_path, :controller => 'issues', :action => 'show', :id => oid},
624 link = link_to("##{oid}", {:only_path => only_path, :controller => 'issues', :action => 'show', :id => oid},
625 :class => issue.css_classes,
625 :class => issue.css_classes,
626 :title => "#{truncate(issue.subject, :length => 100)} (#{issue.status.name})")
626 :title => "#{truncate(issue.subject, :length => 100)} (#{issue.status.name})")
627 end
627 end
628 when 'document'
628 when 'document'
629 if document = Document.visible.find_by_id(oid)
629 if document = Document.visible.find_by_id(oid)
630 link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},
630 link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},
631 :class => 'document'
631 :class => 'document'
632 end
632 end
633 when 'version'
633 when 'version'
634 if version = Version.visible.find_by_id(oid)
634 if version = Version.visible.find_by_id(oid)
635 link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
635 link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
636 :class => 'version'
636 :class => 'version'
637 end
637 end
638 when 'message'
638 when 'message'
639 if message = Message.visible.find_by_id(oid, :include => :parent)
639 if message = Message.visible.find_by_id(oid, :include => :parent)
640 link = link_to_message(message, {:only_path => only_path}, :class => 'message')
640 link = link_to_message(message, {:only_path => only_path}, :class => 'message')
641 end
641 end
642 when 'project'
642 when 'project'
643 if p = Project.visible.find_by_id(oid)
643 if p = Project.visible.find_by_id(oid)
644 link = link_to_project(p, {:only_path => only_path}, :class => 'project')
644 link = link_to_project(p, {:only_path => only_path}, :class => 'project')
645 end
645 end
646 end
646 end
647 elsif sep == ':'
647 elsif sep == ':'
648 # removes the double quotes if any
648 # removes the double quotes if any
649 name = identifier.gsub(%r{^"(.*)"$}, "\\1")
649 name = identifier.gsub(%r{^"(.*)"$}, "\\1")
650 case prefix
650 case prefix
651 when 'document'
651 when 'document'
652 if project && document = project.documents.visible.find_by_title(name)
652 if project && document = project.documents.visible.find_by_title(name)
653 link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},
653 link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},
654 :class => 'document'
654 :class => 'document'
655 end
655 end
656 when 'version'
656 when 'version'
657 if project && version = project.versions.visible.find_by_name(name)
657 if project && version = project.versions.visible.find_by_name(name)
658 link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
658 link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
659 :class => 'version'
659 :class => 'version'
660 end
660 end
661 when 'commit'
661 when 'commit'
662 if project && project.repository && (changeset = Changeset.visible.find(:first, :conditions => ["repository_id = ? AND scmid LIKE ?", project.repository.id, "#{name}%"]))
662 if project && project.repository && (changeset = Changeset.visible.find(:first, :conditions => ["repository_id = ? AND scmid LIKE ?", project.repository.id, "#{name}%"]))
663 link = link_to h("#{project_prefix}#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.identifier},
663 link = link_to h("#{project_prefix}#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.identifier},
664 :class => 'changeset',
664 :class => 'changeset',
665 :title => truncate_single_line(changeset.comments, :length => 100)
665 :title => truncate_single_line(changeset.comments, :length => 100)
666 end
666 end
667 when 'source', 'export'
667 when 'source', 'export'
668 if project && project.repository && User.current.allowed_to?(:browse_repository, project)
668 if project && project.repository && User.current.allowed_to?(:browse_repository, project)
669 name =~ %r{^[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?$}
669 name =~ %r{^[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?$}
670 path, rev, anchor = $1, $3, $5
670 path, rev, anchor = $1, $3, $5
671 link = link_to h("#{project_prefix}#{prefix}:#{name}"), {:controller => 'repositories', :action => 'entry', :id => project,
671 link = link_to h("#{project_prefix}#{prefix}:#{name}"), {:controller => 'repositories', :action => 'entry', :id => project,
672 :path => to_path_param(path),
672 :path => to_path_param(path),
673 :rev => rev,
673 :rev => rev,
674 :anchor => anchor,
674 :anchor => anchor,
675 :format => (prefix == 'export' ? 'raw' : nil)},
675 :format => (prefix == 'export' ? 'raw' : nil)},
676 :class => (prefix == 'export' ? 'source download' : 'source')
676 :class => (prefix == 'export' ? 'source download' : 'source')
677 end
677 end
678 when 'attachment'
678 when 'attachment'
679 attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil)
679 attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil)
680 if attachments && attachment = attachments.detect {|a| a.filename == name }
680 if attachments && attachment = attachments.detect {|a| a.filename == name }
681 link = link_to h(attachment.filename), {:only_path => only_path, :controller => 'attachments', :action => 'download', :id => attachment},
681 link = link_to h(attachment.filename), {:only_path => only_path, :controller => 'attachments', :action => 'download', :id => attachment},
682 :class => 'attachment'
682 :class => 'attachment'
683 end
683 end
684 when 'project'
684 when 'project'
685 if p = Project.visible.find(:first, :conditions => ["identifier = :s OR LOWER(name) = :s", {:s => name.downcase}])
685 if p = Project.visible.find(:first, :conditions => ["identifier = :s OR LOWER(name) = :s", {:s => name.downcase}])
686 link = link_to_project(p, {:only_path => only_path}, :class => 'project')
686 link = link_to_project(p, {:only_path => only_path}, :class => 'project')
687 end
687 end
688 end
688 end
689 end
689 end
690 end
690 end
691 leading + (link || "#{project_prefix}#{prefix}#{sep}#{identifier}")
691 leading + (link || "#{project_prefix}#{prefix}#{sep}#{identifier}")
692 end
692 end
693 end
693 end
694
694
695 HEADING_RE = /<h(1|2|3|4)( [^>]+)?>(.+?)<\/h(1|2|3|4)>/i unless const_defined?(:HEADING_RE)
695 HEADING_RE = /<h(1|2|3|4)( [^>]+)?>(.+?)<\/h(1|2|3|4)>/i unless const_defined?(:HEADING_RE)
696
696
697 # Headings and TOC
697 # Headings and TOC
698 # Adds ids and links to headings unless options[:headings] is set to false
698 # Adds ids and links to headings unless options[:headings] is set to false
699 def parse_headings(text, project, obj, attr, only_path, options)
699 def parse_headings(text, project, obj, attr, only_path, options)
700 return if options[:headings] == false
700 return if options[:headings] == false
701
701
702 text.gsub!(HEADING_RE) do
702 text.gsub!(HEADING_RE) do
703 level, attrs, content = $1.to_i, $2, $3
703 level, attrs, content = $1.to_i, $2, $3
704 item = strip_tags(content).strip
704 item = strip_tags(content).strip
705 anchor = item.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
705 anchor = item.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
706 @parsed_headings << [level, anchor, item]
706 @parsed_headings << [level, anchor, item]
707 "<a name=\"#{anchor}\"></a>\n<h#{level} #{attrs}>#{content}<a href=\"##{anchor}\" class=\"wiki-anchor\">&para;</a></h#{level}>"
707 "<a name=\"#{anchor}\"></a>\n<h#{level} #{attrs}>#{content}<a href=\"##{anchor}\" class=\"wiki-anchor\">&para;</a></h#{level}>"
708 end
708 end
709 end
709 end
710
710
711 TOC_RE = /<p>\{\{([<>]?)toc\}\}<\/p>/i unless const_defined?(:TOC_RE)
711 TOC_RE = /<p>\{\{([<>]?)toc\}\}<\/p>/i unless const_defined?(:TOC_RE)
712
712
713 # Renders the TOC with given headings
713 # Renders the TOC with given headings
714 def replace_toc(text, headings)
714 def replace_toc(text, headings)
715 text.gsub!(TOC_RE) do
715 text.gsub!(TOC_RE) do
716 if headings.empty?
716 if headings.empty?
717 ''
717 ''
718 else
718 else
719 div_class = 'toc'
719 div_class = 'toc'
720 div_class << ' right' if $1 == '>'
720 div_class << ' right' if $1 == '>'
721 div_class << ' left' if $1 == '<'
721 div_class << ' left' if $1 == '<'
722 out = "<ul class=\"#{div_class}\"><li>"
722 out = "<ul class=\"#{div_class}\"><li>"
723 root = headings.map(&:first).min
723 root = headings.map(&:first).min
724 current = root
724 current = root
725 started = false
725 started = false
726 headings.each do |level, anchor, item|
726 headings.each do |level, anchor, item|
727 if level > current
727 if level > current
728 out << '<ul><li>' * (level - current)
728 out << '<ul><li>' * (level - current)
729 elsif level < current
729 elsif level < current
730 out << "</li></ul>\n" * (current - level) + "</li><li>"
730 out << "</li></ul>\n" * (current - level) + "</li><li>"
731 elsif started
731 elsif started
732 out << '</li><li>'
732 out << '</li><li>'
733 end
733 end
734 out << "<a href=\"##{anchor}\">#{item}</a>"
734 out << "<a href=\"##{anchor}\">#{item}</a>"
735 current = level
735 current = level
736 started = true
736 started = true
737 end
737 end
738 out << '</li></ul>' * (current - root)
738 out << '</li></ul>' * (current - root)
739 out << '</li></ul>'
739 out << '</li></ul>'
740 end
740 end
741 end
741 end
742 end
742 end
743
743
744 # Same as Rails' simple_format helper without using paragraphs
744 # Same as Rails' simple_format helper without using paragraphs
745 def simple_format_without_paragraph(text)
745 def simple_format_without_paragraph(text)
746 text.to_s.
746 text.to_s.
747 gsub(/\r\n?/, "\n"). # \r\n and \r -> \n
747 gsub(/\r\n?/, "\n"). # \r\n and \r -> \n
748 gsub(/\n\n+/, "<br /><br />"). # 2+ newline -> 2 br
748 gsub(/\n\n+/, "<br /><br />"). # 2+ newline -> 2 br
749 gsub(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br
749 gsub(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br
750 end
750 end
751
751
752 def lang_options_for_select(blank=true)
752 def lang_options_for_select(blank=true)
753 (blank ? [["(auto)", ""]] : []) +
753 (blank ? [["(auto)", ""]] : []) +
754 valid_languages.collect{|lang| [ ll(lang.to_s, :general_lang_name), lang.to_s]}.sort{|x,y| x.last <=> y.last }
754 valid_languages.collect{|lang| [ ll(lang.to_s, :general_lang_name), lang.to_s]}.sort{|x,y| x.last <=> y.last }
755 end
755 end
756
756
757 def label_tag_for(name, option_tags = nil, options = {})
757 def label_tag_for(name, option_tags = nil, options = {})
758 label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "")
758 label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "")
759 content_tag("label", label_text)
759 content_tag("label", label_text)
760 end
760 end
761
761
762 def labelled_tabular_form_for(name, object, options, &proc)
762 def labelled_tabular_form_for(name, object, options, &proc)
763 options[:html] ||= {}
763 options[:html] ||= {}
764 options[:html][:class] = 'tabular' unless options[:html].has_key?(:class)
764 options[:html][:class] = 'tabular' unless options[:html].has_key?(:class)
765 form_for(name, object, options.merge({ :builder => TabularFormBuilder, :lang => current_language}), &proc)
765 form_for(name, object, options.merge({ :builder => TabularFormBuilder, :lang => current_language}), &proc)
766 end
766 end
767
767
768 def back_url_hidden_field_tag
768 def back_url_hidden_field_tag
769 back_url = params[:back_url] || request.env['HTTP_REFERER']
769 back_url = params[:back_url] || request.env['HTTP_REFERER']
770 back_url = CGI.unescape(back_url.to_s)
770 back_url = CGI.unescape(back_url.to_s)
771 hidden_field_tag('back_url', CGI.escape(back_url)) unless back_url.blank?
771 hidden_field_tag('back_url', CGI.escape(back_url)) unless back_url.blank?
772 end
772 end
773
773
774 def check_all_links(form_name)
774 def check_all_links(form_name)
775 link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") +
775 link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") +
776 " | " +
776 " | " +
777 link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)")
777 link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)")
778 end
778 end
779
779
780 def progress_bar(pcts, options={})
780 def progress_bar(pcts, options={})
781 pcts = [pcts, pcts] unless pcts.is_a?(Array)
781 pcts = [pcts, pcts] unless pcts.is_a?(Array)
782 pcts = pcts.collect(&:round)
782 pcts = pcts.collect(&:round)
783 pcts[1] = pcts[1] - pcts[0]
783 pcts[1] = pcts[1] - pcts[0]
784 pcts << (100 - pcts[1] - pcts[0])
784 pcts << (100 - pcts[1] - pcts[0])
785 width = options[:width] || '100px;'
785 width = options[:width] || '100px;'
786 legend = options[:legend] || ''
786 legend = options[:legend] || ''
787 content_tag('table',
787 content_tag('table',
788 content_tag('tr',
788 content_tag('tr',
789 (pcts[0] > 0 ? content_tag('td', '', :style => "width: #{pcts[0]}%;", :class => 'closed') : '') +
789 (pcts[0] > 0 ? content_tag('td', '', :style => "width: #{pcts[0]}%;", :class => 'closed') : '') +
790 (pcts[1] > 0 ? content_tag('td', '', :style => "width: #{pcts[1]}%;", :class => 'done') : '') +
790 (pcts[1] > 0 ? content_tag('td', '', :style => "width: #{pcts[1]}%;", :class => 'done') : '') +
791 (pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2]}%;", :class => 'todo') : '')
791 (pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2]}%;", :class => 'todo') : '')
792 ), :class => 'progress', :style => "width: #{width};") +
792 ), :class => 'progress', :style => "width: #{width};") +
793 content_tag('p', legend, :class => 'pourcent')
793 content_tag('p', legend, :class => 'pourcent')
794 end
794 end
795
795
796 def checked_image(checked=true)
796 def checked_image(checked=true)
797 if checked
797 if checked
798 image_tag 'toggle_check.png'
798 image_tag 'toggle_check.png'
799 end
799 end
800 end
800 end
801
801
802 def context_menu(url)
802 def context_menu(url)
803 unless @context_menu_included
803 unless @context_menu_included
804 content_for :header_tags do
804 content_for :header_tags do
805 javascript_include_tag('context_menu') +
805 javascript_include_tag('context_menu') +
806 stylesheet_link_tag('context_menu')
806 stylesheet_link_tag('context_menu')
807 end
807 end
808 if l(:direction) == 'rtl'
808 if l(:direction) == 'rtl'
809 content_for :header_tags do
809 content_for :header_tags do
810 stylesheet_link_tag('context_menu_rtl')
810 stylesheet_link_tag('context_menu_rtl')
811 end
811 end
812 end
812 end
813 @context_menu_included = true
813 @context_menu_included = true
814 end
814 end
815 javascript_tag "new ContextMenu('#{ url_for(url) }')"
815 javascript_tag "new ContextMenu('#{ url_for(url) }')"
816 end
816 end
817
817
818 def context_menu_link(name, url, options={})
818 def context_menu_link(name, url, options={})
819 options[:class] ||= ''
819 options[:class] ||= ''
820 if options.delete(:selected)
820 if options.delete(:selected)
821 options[:class] << ' icon-checked disabled'
821 options[:class] << ' icon-checked disabled'
822 options[:disabled] = true
822 options[:disabled] = true
823 end
823 end
824 if options.delete(:disabled)
824 if options.delete(:disabled)
825 options.delete(:method)
825 options.delete(:method)
826 options.delete(:confirm)
826 options.delete(:confirm)
827 options.delete(:onclick)
827 options.delete(:onclick)
828 options[:class] << ' disabled'
828 options[:class] << ' disabled'
829 url = '#'
829 url = '#'
830 end
830 end
831 link_to name, url, options
831 link_to name, url, options
832 end
832 end
833
833
834 def calendar_for(field_id)
834 def calendar_for(field_id)
835 include_calendar_headers_tags
835 include_calendar_headers_tags
836 image_tag("calendar.png", {:id => "#{field_id}_trigger",:class => "calendar-trigger"}) +
836 image_tag("calendar.png", {:id => "#{field_id}_trigger",:class => "calendar-trigger"}) +
837 javascript_tag("Calendar.setup({inputField : '#{field_id}', ifFormat : '%Y-%m-%d', button : '#{field_id}_trigger' });")
837 javascript_tag("Calendar.setup({inputField : '#{field_id}', ifFormat : '%Y-%m-%d', button : '#{field_id}_trigger' });")
838 end
838 end
839
839
840 def include_calendar_headers_tags
840 def include_calendar_headers_tags
841 unless @calendar_headers_tags_included
841 unless @calendar_headers_tags_included
842 @calendar_headers_tags_included = true
842 @calendar_headers_tags_included = true
843 content_for :header_tags do
843 content_for :header_tags do
844 start_of_week = case Setting.start_of_week.to_i
844 start_of_week = case Setting.start_of_week.to_i
845 when 1
845 when 1
846 'Calendar._FD = 1;' # Monday
846 'Calendar._FD = 1;' # Monday
847 when 7
847 when 7
848 'Calendar._FD = 0;' # Sunday
848 'Calendar._FD = 0;' # Sunday
849 when 6
849 when 6
850 'Calendar._FD = 6;' # Saturday
850 'Calendar._FD = 6;' # Saturday
851 else
851 else
852 '' # use language
852 '' # use language
853 end
853 end
854
854
855 javascript_include_tag('calendar/calendar') +
855 javascript_include_tag('calendar/calendar') +
856 javascript_include_tag("calendar/lang/calendar-#{current_language.to_s.downcase}.js") +
856 javascript_include_tag("calendar/lang/calendar-#{current_language.to_s.downcase}.js") +
857 javascript_tag(start_of_week) +
857 javascript_tag(start_of_week) +
858 javascript_include_tag('calendar/calendar-setup') +
858 javascript_include_tag('calendar/calendar-setup') +
859 stylesheet_link_tag('calendar')
859 stylesheet_link_tag('calendar')
860 end
860 end
861 end
861 end
862 end
862 end
863
863
864 def content_for(name, content = nil, &block)
864 def content_for(name, content = nil, &block)
865 @has_content ||= {}
865 @has_content ||= {}
866 @has_content[name] = true
866 @has_content[name] = true
867 super(name, content, &block)
867 super(name, content, &block)
868 end
868 end
869
869
870 def has_content?(name)
870 def has_content?(name)
871 (@has_content && @has_content[name]) || false
871 (@has_content && @has_content[name]) || false
872 end
872 end
873
873
874 # Returns the avatar image tag for the given +user+ if avatars are enabled
874 # Returns the avatar image tag for the given +user+ if avatars are enabled
875 # +user+ can be a User or a string that will be scanned for an email address (eg. 'joe <joe@foo.bar>')
875 # +user+ can be a User or a string that will be scanned for an email address (eg. 'joe <joe@foo.bar>')
876 def avatar(user, options = { })
876 def avatar(user, options = { })
877 if Setting.gravatar_enabled?
877 if Setting.gravatar_enabled?
878 options.merge!({:ssl => (defined?(request) && request.ssl?), :default => Setting.gravatar_default})
878 options.merge!({:ssl => (defined?(request) && request.ssl?), :default => Setting.gravatar_default})
879 email = nil
879 email = nil
880 if user.respond_to?(:mail)
880 if user.respond_to?(:mail)
881 email = user.mail
881 email = user.mail
882 elsif user.to_s =~ %r{<(.+?)>}
882 elsif user.to_s =~ %r{<(.+?)>}
883 email = $1
883 email = $1
884 end
884 end
885 return gravatar(email.to_s.downcase, options) unless email.blank? rescue nil
885 return gravatar(email.to_s.downcase, options) unless email.blank? rescue nil
886 else
886 else
887 ''
887 ''
888 end
888 end
889 end
889 end
890
890
891 # Returns the javascript tags that are included in the html layout head
891 # Returns the javascript tags that are included in the html layout head
892 def javascript_heads
892 def javascript_heads
893 tags = javascript_include_tag(:defaults)
893 tags = javascript_include_tag(:defaults)
894 unless User.current.pref.warn_on_leaving_unsaved == '0'
894 unless User.current.pref.warn_on_leaving_unsaved == '0'
895 tags << "\n" + javascript_tag("Event.observe(window, 'load', function(){ new WarnLeavingUnsaved('#{escape_javascript( l(:text_warn_on_leaving_unsaved) )}'); });")
895 tags << "\n" + javascript_tag("Event.observe(window, 'load', function(){ new WarnLeavingUnsaved('#{escape_javascript( l(:text_warn_on_leaving_unsaved) )}'); });")
896 end
896 end
897 tags
897 tags
898 end
898 end
899
899
900 def favicon
900 def favicon
901 "<link rel='shortcut icon' href='#{image_path('/favicon.ico')}' />"
901 "<link rel='shortcut icon' href='#{image_path('/favicon.ico')}' />"
902 end
902 end
903
904 def robot_exclusion_tag
905 '<meta name="robots" content="noindex,follow,noarchive" />'
906 end
903
907
904 # Returns true if arg is expected in the API response
908 # Returns true if arg is expected in the API response
905 def include_in_api_response?(arg)
909 def include_in_api_response?(arg)
906 unless @included_in_api_response
910 unless @included_in_api_response
907 param = params[:include]
911 param = params[:include]
908 @included_in_api_response = param.is_a?(Array) ? param.collect(&:to_s) : param.to_s.split(',')
912 @included_in_api_response = param.is_a?(Array) ? param.collect(&:to_s) : param.to_s.split(',')
909 @included_in_api_response.collect!(&:strip)
913 @included_in_api_response.collect!(&:strip)
910 end
914 end
911 @included_in_api_response.include?(arg.to_s)
915 @included_in_api_response.include?(arg.to_s)
912 end
916 end
913
917
914 # Returns options or nil if nometa param or X-Redmine-Nometa header
918 # Returns options or nil if nometa param or X-Redmine-Nometa header
915 # was set in the request
919 # was set in the request
916 def api_meta(options)
920 def api_meta(options)
917 if params[:nometa].present? || request.headers['X-Redmine-Nometa']
921 if params[:nometa].present? || request.headers['X-Redmine-Nometa']
918 # compatibility mode for activeresource clients that raise
922 # compatibility mode for activeresource clients that raise
919 # an error when unserializing an array with attributes
923 # an error when unserializing an array with attributes
920 nil
924 nil
921 else
925 else
922 options
926 options
923 end
927 end
924 end
928 end
925
929
926 private
930 private
927
931
928 def wiki_helper
932 def wiki_helper
929 helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting)
933 helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting)
930 extend helper
934 extend helper
931 return self
935 return self
932 end
936 end
933
937
934 def link_to_content_update(text, url_params = {}, html_options = {})
938 def link_to_content_update(text, url_params = {}, html_options = {})
935 link_to(text, url_params, html_options)
939 link_to(text, url_params, html_options)
936 end
940 end
937 end
941 end
@@ -1,76 +1,79
1 <h2><%= @copy ? l(:button_copy) : l(:button_move) %></h2>
1 <h2><%= @copy ? l(:button_copy) : l(:button_move) %></h2>
2
2
3 <ul>
3 <ul>
4 <% @issues.each do |issue| -%>
4 <% @issues.each do |issue| -%>
5 <li><%= link_to_issue issue %></li>
5 <li><%= link_to_issue issue %></li>
6 <% end -%>
6 <% end -%>
7 </ul>
7 </ul>
8
8
9 <% form_tag({:action => 'create'}, :id => 'move_form') do %>
9 <% form_tag({:action => 'create'}, :id => 'move_form') do %>
10 <%= @issues.collect {|i| hidden_field_tag('ids[]', i.id)}.join %>
10 <%= @issues.collect {|i| hidden_field_tag('ids[]', i.id)}.join %>
11
11
12 <div class="box tabular">
12 <div class="box tabular">
13 <fieldset class="attributes">
13 <fieldset class="attributes">
14 <legend><%= l(:label_change_properties) %></legend>
14 <legend><%= l(:label_change_properties) %></legend>
15
15
16 <div class="splitcontentleft">
16 <div class="splitcontentleft">
17 <p><label for="new_project_id"><%=l(:field_project)%>:</label>
17 <p><label for="new_project_id"><%=l(:field_project)%>:</label>
18 <%= select_tag "new_project_id",
18 <%= select_tag "new_project_id",
19 project_tree_options_for_select(@allowed_projects, :selected => @target_project),
19 project_tree_options_for_select(@allowed_projects, :selected => @target_project),
20 :onchange => remote_function(:url => { :action => 'new' },
20 :onchange => remote_function(:url => { :action => 'new' },
21 :method => :get,
21 :method => :get,
22 :update => 'content',
22 :update => 'content',
23 :with => "Form.serialize('move_form')") %></p>
23 :with => "Form.serialize('move_form')") %></p>
24
24
25 <p><label for="new_tracker_id"><%=l(:field_tracker)%>:</label>
25 <p><label for="new_tracker_id"><%=l(:field_tracker)%>:</label>
26 <%= select_tag "new_tracker_id", "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(@trackers, "id", "name") %></p>
26 <%= select_tag "new_tracker_id", "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(@trackers, "id", "name") %></p>
27
27
28 <p>
28 <p>
29 <label><%= l(:field_status) %></label>
29 <label><%= l(:field_status) %></label>
30 <%= select_tag('status_id', "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(@available_statuses, :id, :name)) %>
30 <%= select_tag('status_id', "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(@available_statuses, :id, :name)) %>
31 </p>
31 </p>
32
32
33 <p>
33 <p>
34 <label><%= l(:field_priority) %></label>
34 <label><%= l(:field_priority) %></label>
35 <%= select_tag('priority_id', "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(IssuePriority.all, :id, :name)) %>
35 <%= select_tag('priority_id', "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(IssuePriority.all, :id, :name)) %>
36 </p>
36 </p>
37
37
38 <p>
38 <p>
39 <label><%= l(:field_assigned_to) %></label>
39 <label><%= l(:field_assigned_to) %></label>
40 <%= select_tag('assigned_to_id', content_tag('option', l(:label_no_change_option), :value => '') +
40 <%= select_tag('assigned_to_id', content_tag('option', l(:label_no_change_option), :value => '') +
41 content_tag('option', l(:label_nobody), :value => 'none') +
41 content_tag('option', l(:label_nobody), :value => 'none') +
42 options_from_collection_for_select(@target_project.assignable_users, :id, :name)) %>
42 options_from_collection_for_select(@target_project.assignable_users, :id, :name)) %>
43 </p>
43 </p>
44 </div>
44 </div>
45
45
46 <div class="splitcontentright">
46 <div class="splitcontentright">
47 <p>
47 <p>
48 <label><%= l(:field_start_date) %></label>
48 <label><%= l(:field_start_date) %></label>
49 <%= text_field_tag 'start_date', '', :size => 10 %><%= calendar_for('start_date') %>
49 <%= text_field_tag 'start_date', '', :size => 10 %><%= calendar_for('start_date') %>
50 </p>
50 </p>
51
51
52 <p>
52 <p>
53 <label><%= l(:field_due_date) %></label>
53 <label><%= l(:field_due_date) %></label>
54 <%= text_field_tag 'due_date', '', :size => 10 %><%= calendar_for('due_date') %>
54 <%= text_field_tag 'due_date', '', :size => 10 %><%= calendar_for('due_date') %>
55 </p>
55 </p>
56 </div>
56 </div>
57
57
58 </fieldset>
58 </fieldset>
59
59
60 <fieldset><legend><%= l(:field_notes) %></legend>
60 <fieldset><legend><%= l(:field_notes) %></legend>
61 <%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10, :class => 'wiki-edit' %>
61 <%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10, :class => 'wiki-edit' %>
62 <%= wikitoolbar_for 'notes' %>
62 <%= wikitoolbar_for 'notes' %>
63 </fieldset>
63 </fieldset>
64
64
65 <%= call_hook(:view_issues_move_bottom, :issues => @issues, :target_project => @target_project, :copy => !!@copy) %>
65 <%= call_hook(:view_issues_move_bottom, :issues => @issues, :target_project => @target_project, :copy => !!@copy) %>
66 </div>
66 </div>
67
67
68 <% if @copy %>
68 <% if @copy %>
69 <%= hidden_field_tag("copy_options[copy]", "1") %>
69 <%= hidden_field_tag("copy_options[copy]", "1") %>
70 <%= submit_tag l(:button_copy) %>
70 <%= submit_tag l(:button_copy) %>
71 <%= submit_tag l(:button_copy_and_follow), :name => 'follow' %>
71 <%= submit_tag l(:button_copy_and_follow), :name => 'follow' %>
72 <% else %>
72 <% else %>
73 <%= submit_tag l(:button_move) %>
73 <%= submit_tag l(:button_move) %>
74 <%= submit_tag l(:button_move_and_follow), :name => 'follow' %>
74 <%= submit_tag l(:button_move_and_follow), :name => 'follow' %>
75 <% end %>
75 <% end %>
76 <% end %>
76 <% end %>
77 <% content_for :header_tags do %>
78 <%= robot_exclusion_tag %>
79 <% end %>
@@ -1,3 +1,6
1 <h2><%=h "#{@issue.tracker.name} ##{@issue.id}" %></h2>
1 <h2><%=h "#{@issue.tracker.name} ##{@issue.id}" %></h2>
2
2
3 <%= render :partial => 'edit' %>
3 <%= render :partial => 'edit' %>
4 <% content_for :header_tags do %>
5 <%= robot_exclusion_tag %>
6 <% end %>
@@ -1,26 +1,27
1 <h2><%=l(:label_issue_new)%></h2>
1 <h2><%=l(:label_issue_new)%></h2>
2
2
3 <% labelled_tabular_form_for :issue, @issue, :url => {:controller => 'issues', :action => 'create', :project_id => @project},
3 <% labelled_tabular_form_for :issue, @issue, :url => {:controller => 'issues', :action => 'create', :project_id => @project},
4 :html => {:multipart => true, :id => 'issue-form', :class => 'tabular new-issue-form'} do |f| %>
4 :html => {:multipart => true, :id => 'issue-form', :class => 'tabular new-issue-form'} do |f| %>
5 <%= error_messages_for 'issue' %>
5 <%= error_messages_for 'issue' %>
6 <div class="box">
6 <div class="box">
7 <%= render :partial => 'issues/form', :locals => {:f => f} %>
7 <%= render :partial => 'issues/form', :locals => {:f => f} %>
8 </div>
8 </div>
9 <%= submit_tag l(:button_create) %>
9 <%= submit_tag l(:button_create) %>
10 <%= submit_tag l(:button_create_and_continue), :name => 'continue' %>
10 <%= submit_tag l(:button_create_and_continue), :name => 'continue' %>
11 <%= link_to_remote l(:label_preview),
11 <%= link_to_remote l(:label_preview),
12 { :url => preview_issue_path(:project_id => @project),
12 { :url => preview_issue_path(:project_id => @project),
13 :method => 'post',
13 :method => 'post',
14 :update => 'preview',
14 :update => 'preview',
15 :with => "Form.serialize('issue-form')",
15 :with => "Form.serialize('issue-form')",
16 :complete => "Element.scrollTo('preview')"
16 :complete => "Element.scrollTo('preview')"
17 }, :accesskey => accesskey(:preview) %>
17 }, :accesskey => accesskey(:preview) %>
18
18
19 <%= javascript_tag "Form.Element.focus('issue_subject');" %>
19 <%= javascript_tag "Form.Element.focus('issue_subject');" %>
20 <% end %>
20 <% end %>
21
21
22 <div id="preview" class="wiki"></div>
22 <div id="preview" class="wiki"></div>
23
23
24 <% content_for :header_tags do %>
24 <% content_for :header_tags do %>
25 <%= stylesheet_link_tag 'scm' %>
25 <%= stylesheet_link_tag 'scm' %>
26 <%= robot_exclusion_tag %>
26 <% end %>
27 <% end %>
@@ -1,28 +1,29
1 <h2><%=h @page.pretty_title %></h2>
1 <h2><%=h @page.pretty_title %></h2>
2
2
3 <% form_for :content, @content, :url => {:action => 'update', :id => @page.title}, :html => {:method => :put, :multipart => true, :id => 'wiki_form'} do |f| %>
3 <% form_for :content, @content, :url => {:action => 'update', :id => @page.title}, :html => {:method => :put, :multipart => true, :id => 'wiki_form'} do |f| %>
4 <%= f.hidden_field :version %>
4 <%= f.hidden_field :version %>
5 <%= error_messages_for 'content' %>
5 <%= error_messages_for 'content' %>
6
6
7 <p><%= f.text_area :text, :cols => 100, :rows => 25, :class => 'wiki-edit', :accesskey => accesskey(:edit) %></p>
7 <p><%= f.text_area :text, :cols => 100, :rows => 25, :class => 'wiki-edit', :accesskey => accesskey(:edit) %></p>
8 <p><label><%= l(:field_comments) %></label><br /><%= f.text_field :comments, :size => 120 %></p>
8 <p><label><%= l(:field_comments) %></label><br /><%= f.text_field :comments, :size => 120 %></p>
9 <p><label><%=l(:label_attachment_plural)%></label><br /><%= render :partial => 'attachments/form' %></p>
9 <p><label><%=l(:label_attachment_plural)%></label><br /><%= render :partial => 'attachments/form' %></p>
10
10
11 <p><%= submit_tag l(:button_save) %>
11 <p><%= submit_tag l(:button_save) %>
12 <%= link_to_remote l(:label_preview),
12 <%= link_to_remote l(:label_preview),
13 { :url => { :controller => 'wiki', :action => 'preview', :project_id => @project, :id => @page.title },
13 { :url => { :controller => 'wiki', :action => 'preview', :project_id => @project, :id => @page.title },
14 :method => :post,
14 :method => :post,
15 :update => 'preview',
15 :update => 'preview',
16 :with => "Form.serialize('wiki_form')",
16 :with => "Form.serialize('wiki_form')",
17 :complete => "Element.scrollTo('preview')"
17 :complete => "Element.scrollTo('preview')"
18 }, :accesskey => accesskey(:preview) %></p>
18 }, :accesskey => accesskey(:preview) %></p>
19 <%= wikitoolbar_for 'content_text' %>
19 <%= wikitoolbar_for 'content_text' %>
20 <% end %>
20 <% end %>
21
21
22 <div id="preview" class="wiki"></div>
22 <div id="preview" class="wiki"></div>
23
23
24 <% content_for :header_tags do %>
24 <% content_for :header_tags do %>
25 <%= stylesheet_link_tag 'scm' %>
25 <%= stylesheet_link_tag 'scm' %>
26 <%= robot_exclusion_tag %>
26 <% end %>
27 <% end %>
27
28
28 <% html_title @page.pretty_title %>
29 <% html_title @page.pretty_title %>
General Comments 0
You need to be logged in to leave comments. Login now