##// END OF EJS Templates
Deprecated :confirm => 'Text' option....
Jean-Philippe Lang -
r9754:7b40767428ac
parent child
Show More
@@ -1,1214 +1,1224
1 1 # encoding: utf-8
2 2 #
3 3 # Redmine - project management software
4 4 # Copyright (C) 2006-2012 Jean-Philippe Lang
5 5 #
6 6 # This program is free software; you can redistribute it and/or
7 7 # modify it under the terms of the GNU General Public License
8 8 # as published by the Free Software Foundation; either version 2
9 9 # of the License, or (at your option) any later version.
10 10 #
11 11 # This program is distributed in the hope that it will be useful,
12 12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 14 # GNU General Public License for more details.
15 15 #
16 16 # You should have received a copy of the GNU General Public License
17 17 # along with this program; if not, write to the Free Software
18 18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 19
20 20 require 'forwardable'
21 21 require 'cgi'
22 22
23 23 module ApplicationHelper
24 24 include Redmine::WikiFormatting::Macros::Definitions
25 25 include Redmine::I18n
26 26 include GravatarHelper::PublicMethods
27 27
28 28 extend Forwardable
29 29 def_delegators :wiki_helper, :wikitoolbar_for, :heads_for_wiki_formatter
30 30
31 31 # Return true if user is authorized for controller/action, otherwise false
32 32 def authorize_for(controller, action)
33 33 User.current.allowed_to?({:controller => controller, :action => action}, @project)
34 34 end
35 35
36 36 # Display a link if user is authorized
37 37 #
38 38 # @param [String] name Anchor text (passed to link_to)
39 39 # @param [Hash] options Hash params. This will checked by authorize_for to see if the user is authorized
40 40 # @param [optional, Hash] html_options Options passed to link_to
41 41 # @param [optional, Hash] parameters_for_method_reference Extra parameters for link_to
42 42 def link_to_if_authorized(name, options = {}, html_options = nil, *parameters_for_method_reference)
43 43 link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for(options[:controller] || params[:controller], options[:action])
44 44 end
45 45
46 46 # Display a link to remote if user is authorized
47 47 def link_to_remote_if_authorized(name, options = {}, html_options = nil)
48 48 url = options[:url] || {}
49 49 link_to_remote(name, options, html_options) if authorize_for(url[:controller] || params[:controller], url[:action])
50 50 end
51 51
52 52 # Displays a link to user's account page if active
53 53 def link_to_user(user, options={})
54 54 if user.is_a?(User)
55 55 name = h(user.name(options[:format]))
56 56 if user.active?
57 57 link_to name, :controller => 'users', :action => 'show', :id => user
58 58 else
59 59 name
60 60 end
61 61 else
62 62 h(user.to_s)
63 63 end
64 64 end
65 65
66 66 # Displays a link to +issue+ with its subject.
67 67 # Examples:
68 68 #
69 69 # link_to_issue(issue) # => Defect #6: This is the subject
70 70 # link_to_issue(issue, :truncate => 6) # => Defect #6: This i...
71 71 # link_to_issue(issue, :subject => false) # => Defect #6
72 72 # link_to_issue(issue, :project => true) # => Foo - Defect #6
73 73 #
74 74 def link_to_issue(issue, options={})
75 75 title = nil
76 76 subject = nil
77 77 if options[:subject] == false
78 78 title = truncate(issue.subject, :length => 60)
79 79 else
80 80 subject = issue.subject
81 81 if options[:truncate]
82 82 subject = truncate(subject, :length => options[:truncate])
83 83 end
84 84 end
85 85 s = link_to "#{h(issue.tracker)} ##{issue.id}", {:controller => "issues", :action => "show", :id => issue},
86 86 :class => issue.css_classes,
87 87 :title => title
88 88 s << h(": #{subject}") if subject
89 89 s = h("#{issue.project} - ") + s if options[:project]
90 90 s
91 91 end
92 92
93 93 # Generates a link to an attachment.
94 94 # Options:
95 95 # * :text - Link text (default to attachment filename)
96 96 # * :download - Force download (default: false)
97 97 def link_to_attachment(attachment, options={})
98 98 text = options.delete(:text) || attachment.filename
99 99 action = options.delete(:download) ? 'download' : 'show'
100 100 opt_only_path = {}
101 101 opt_only_path[:only_path] = (options[:only_path] == false ? false : true)
102 102 options.delete(:only_path)
103 103 link_to(h(text),
104 104 {:controller => 'attachments', :action => action,
105 105 :id => attachment, :filename => attachment.filename}.merge(opt_only_path),
106 106 options)
107 107 end
108 108
109 109 # Generates a link to a SCM revision
110 110 # Options:
111 111 # * :text - Link text (default to the formatted revision)
112 112 def link_to_revision(revision, repository, options={})
113 113 if repository.is_a?(Project)
114 114 repository = repository.repository
115 115 end
116 116 text = options.delete(:text) || format_revision(revision)
117 117 rev = revision.respond_to?(:identifier) ? revision.identifier : revision
118 118 link_to(
119 119 h(text),
120 120 {:controller => 'repositories', :action => 'revision', :id => repository.project, :repository_id => repository.identifier_param, :rev => rev},
121 121 :title => l(:label_revision_id, format_revision(revision))
122 122 )
123 123 end
124 124
125 125 # Generates a link to a message
126 126 def link_to_message(message, options={}, html_options = nil)
127 127 link_to(
128 128 h(truncate(message.subject, :length => 60)),
129 129 { :controller => 'messages', :action => 'show',
130 130 :board_id => message.board_id,
131 131 :id => (message.parent_id || message.id),
132 132 :r => (message.parent_id && message.id),
133 133 :anchor => (message.parent_id ? "message-#{message.id}" : nil)
134 134 }.merge(options),
135 135 html_options
136 136 )
137 137 end
138 138
139 139 # Generates a link to a project if active
140 140 # Examples:
141 141 #
142 142 # link_to_project(project) # => link to the specified project overview
143 143 # link_to_project(project, :action=>'settings') # => link to project settings
144 144 # link_to_project(project, {:only_path => false}, :class => "project") # => 3rd arg adds html options
145 145 # link_to_project(project, {}, :class => "project") # => html options with default url (project overview)
146 146 #
147 147 def link_to_project(project, options={}, html_options = nil)
148 148 if project.archived?
149 149 h(project)
150 150 else
151 151 url = {:controller => 'projects', :action => 'show', :id => project}.merge(options)
152 152 link_to(h(project), url, html_options)
153 153 end
154 154 end
155 155
156 156 def thumbnail_tag(attachment)
157 157 link_to image_tag(url_for(:controller => 'attachments', :action => 'thumbnail', :id => attachment)),
158 158 {:controller => 'attachments', :action => 'show', :id => attachment, :filename => attachment.filename},
159 159 :title => attachment.filename
160 160 end
161 161
162 162 def toggle_link(name, id, options={})
163 163 onclick = "Element.toggle('#{id}'); "
164 164 onclick << (options[:focus] ? "Form.Element.focus('#{options[:focus]}'); " : "this.blur(); ")
165 165 onclick << "return false;"
166 166 link_to(name, "#", :onclick => onclick)
167 167 end
168 168
169 169 def image_to_function(name, function, html_options = {})
170 170 html_options.symbolize_keys!
171 171 tag(:input, html_options.merge({
172 172 :type => "image", :src => image_path(name),
173 173 :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};"
174 174 }))
175 175 end
176 176
177 177 def prompt_to_remote(name, text, param, url, html_options = {})
178 178 html_options[:onclick] = "promptToRemote('#{text}', '#{param}', '#{url_for(url)}'); return false;"
179 179 link_to name, {}, html_options
180 180 end
181 181
182 182 def format_activity_title(text)
183 183 h(truncate_single_line(text, :length => 100))
184 184 end
185 185
186 186 def format_activity_day(date)
187 187 date == User.current.today ? l(:label_today).titleize : format_date(date)
188 188 end
189 189
190 190 def format_activity_description(text)
191 191 h(truncate(text.to_s, :length => 120).gsub(%r{[\r\n]*<(pre|code)>.*$}m, '...')
192 192 ).gsub(/[\r\n]+/, "<br />").html_safe
193 193 end
194 194
195 195 def format_version_name(version)
196 196 if version.project == @project
197 197 h(version)
198 198 else
199 199 h("#{version.project} - #{version}")
200 200 end
201 201 end
202 202
203 203 def due_date_distance_in_words(date)
204 204 if date
205 205 l((date < Date.today ? :label_roadmap_overdue : :label_roadmap_due_in), distance_of_date_in_words(Date.today, date))
206 206 end
207 207 end
208 208
209 209 def render_page_hierarchy(pages, node=nil, options={})
210 210 content = ''
211 211 if pages[node]
212 212 content << "<ul class=\"pages-hierarchy\">\n"
213 213 pages[node].each do |page|
214 214 content << "<li>"
215 215 content << link_to(h(page.pretty_title), {:controller => 'wiki', :action => 'show', :project_id => page.project, :id => page.title},
216 216 :title => (options[:timestamp] && page.updated_on ? l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on)) : nil))
217 217 content << "\n" + render_page_hierarchy(pages, page.id, options) if pages[page.id]
218 218 content << "</li>\n"
219 219 end
220 220 content << "</ul>\n"
221 221 end
222 222 content.html_safe
223 223 end
224 224
225 225 # Renders flash messages
226 226 def render_flash_messages
227 227 s = ''
228 228 flash.each do |k,v|
229 229 s << content_tag('div', v.html_safe, :class => "flash #{k}", :id => "flash_#{k}")
230 230 end
231 231 s.html_safe
232 232 end
233 233
234 234 # Renders tabs and their content
235 235 def render_tabs(tabs)
236 236 if tabs.any?
237 237 render :partial => 'common/tabs', :locals => {:tabs => tabs}
238 238 else
239 239 content_tag 'p', l(:label_no_data), :class => "nodata"
240 240 end
241 241 end
242 242
243 243 # Renders the project quick-jump box
244 244 def render_project_jump_box
245 245 return unless User.current.logged?
246 246 projects = User.current.memberships.collect(&:project).compact.select(&:active?).uniq
247 247 if projects.any?
248 248 options =
249 249 ("<option value=''>#{ l(:label_jump_to_a_project) }</option>" +
250 250 '<option value="" disabled="disabled">---</option>').html_safe
251 251
252 252 options << project_tree_options_for_select(projects, :selected => @project) do |p|
253 253 { :value => project_path(:id => p, :jump => current_menu_item) }
254 254 end
255 255
256 256 select_tag('project_quick_jump_box', options, :onchange => 'if (this.value != \'\') { window.location = this.value; }')
257 257 end
258 258 end
259 259
260 260 def project_tree_options_for_select(projects, options = {})
261 261 s = ''
262 262 project_tree(projects) do |project, level|
263 263 name_prefix = (level > 0 ? '&nbsp;' * 2 * level + '&#187; ' : '').html_safe
264 264 tag_options = {:value => project.id}
265 265 if project == options[:selected] || (options[:selected].respond_to?(:include?) && options[:selected].include?(project))
266 266 tag_options[:selected] = 'selected'
267 267 else
268 268 tag_options[:selected] = nil
269 269 end
270 270 tag_options.merge!(yield(project)) if block_given?
271 271 s << content_tag('option', name_prefix + h(project), tag_options)
272 272 end
273 273 s.html_safe
274 274 end
275 275
276 276 # Yields the given block for each project with its level in the tree
277 277 #
278 278 # Wrapper for Project#project_tree
279 279 def project_tree(projects, &block)
280 280 Project.project_tree(projects, &block)
281 281 end
282 282
283 283 def project_nested_ul(projects, &block)
284 284 s = ''
285 285 if projects.any?
286 286 ancestors = []
287 287 projects.sort_by(&:lft).each do |project|
288 288 if (ancestors.empty? || project.is_descendant_of?(ancestors.last))
289 289 s << "<ul>\n"
290 290 else
291 291 ancestors.pop
292 292 s << "</li>"
293 293 while (ancestors.any? && !project.is_descendant_of?(ancestors.last))
294 294 ancestors.pop
295 295 s << "</ul></li>\n"
296 296 end
297 297 end
298 298 s << "<li>"
299 299 s << yield(project).to_s
300 300 ancestors << project
301 301 end
302 302 s << ("</li></ul>\n" * ancestors.size)
303 303 end
304 304 s.html_safe
305 305 end
306 306
307 307 def principals_check_box_tags(name, principals)
308 308 s = ''
309 309 principals.sort.each do |principal|
310 310 s << "<label>#{ check_box_tag name, principal.id, false } #{h principal}</label>\n"
311 311 end
312 312 s.html_safe
313 313 end
314 314
315 315 # Returns a string for users/groups option tags
316 316 def principals_options_for_select(collection, selected=nil)
317 317 s = ''
318 318 if collection.include?(User.current)
319 319 s << content_tag('option', "<< #{l(:label_me)} >>".html_safe, :value => User.current.id)
320 320 end
321 321 groups = ''
322 322 collection.sort.each do |element|
323 323 selected_attribute = ' selected="selected"' if option_value_selected?(element, selected)
324 324 (element.is_a?(Group) ? groups : s) << %(<option value="#{element.id}"#{selected_attribute}>#{h element.name}</option>)
325 325 end
326 326 unless groups.empty?
327 327 s << %(<optgroup label="#{h(l(:label_group_plural))}">#{groups}</optgroup>)
328 328 end
329 329 s.html_safe
330 330 end
331 331
332 332 # Truncates and returns the string as a single line
333 333 def truncate_single_line(string, *args)
334 334 truncate(string.to_s, *args).gsub(%r{[\r\n]+}m, ' ')
335 335 end
336 336
337 337 # Truncates at line break after 250 characters or options[:length]
338 338 def truncate_lines(string, options={})
339 339 length = options[:length] || 250
340 340 if string.to_s =~ /\A(.{#{length}}.*?)$/m
341 341 "#{$1}..."
342 342 else
343 343 string
344 344 end
345 345 end
346 346
347 347 def anchor(text)
348 348 text.to_s.gsub(' ', '_')
349 349 end
350 350
351 351 def html_hours(text)
352 352 text.gsub(%r{(\d+)\.(\d+)}, '<span class="hours hours-int">\1</span><span class="hours hours-dec">.\2</span>').html_safe
353 353 end
354 354
355 355 def authoring(created, author, options={})
356 356 l(options[:label] || :label_added_time_by, :author => link_to_user(author), :age => time_tag(created)).html_safe
357 357 end
358 358
359 359 def time_tag(time)
360 360 text = distance_of_time_in_words(Time.now, time)
361 361 if @project
362 362 link_to(text, {:controller => 'activities', :action => 'index', :id => @project, :from => User.current.time_to_date(time)}, :title => format_time(time))
363 363 else
364 364 content_tag('acronym', text, :title => format_time(time))
365 365 end
366 366 end
367 367
368 368 def syntax_highlight_lines(name, content)
369 369 lines = []
370 370 syntax_highlight(name, content).each_line { |line| lines << line }
371 371 lines
372 372 end
373 373
374 374 def syntax_highlight(name, content)
375 375 Redmine::SyntaxHighlighting.highlight_by_filename(content, name)
376 376 end
377 377
378 378 def to_path_param(path)
379 379 str = path.to_s.split(%r{[/\\]}).select{|p| !p.blank?}.join("/")
380 380 str.blank? ? nil : str
381 381 end
382 382
383 383 def pagination_links_full(paginator, count=nil, options={})
384 384 page_param = options.delete(:page_param) || :page
385 385 per_page_links = options.delete(:per_page_links)
386 386 url_param = params.dup
387 387
388 388 html = ''
389 389 if paginator.current.previous
390 390 # \xc2\xab(utf-8) = &#171;
391 391 html << link_to_content_update(
392 392 "\xc2\xab " + l(:label_previous),
393 393 url_param.merge(page_param => paginator.current.previous)) + ' '
394 394 end
395 395
396 396 html << (pagination_links_each(paginator, options) do |n|
397 397 link_to_content_update(n.to_s, url_param.merge(page_param => n))
398 398 end || '')
399 399
400 400 if paginator.current.next
401 401 # \xc2\xbb(utf-8) = &#187;
402 402 html << ' ' + link_to_content_update(
403 403 (l(:label_next) + " \xc2\xbb"),
404 404 url_param.merge(page_param => paginator.current.next))
405 405 end
406 406
407 407 unless count.nil?
408 408 html << " (#{paginator.current.first_item}-#{paginator.current.last_item}/#{count})"
409 409 if per_page_links != false && links = per_page_links(paginator.items_per_page, count)
410 410 html << " | #{links}"
411 411 end
412 412 end
413 413
414 414 html.html_safe
415 415 end
416 416
417 417 def per_page_links(selected=nil, item_count=nil)
418 418 values = Setting.per_page_options_array
419 419 if item_count && values.any?
420 420 if item_count > values.first
421 421 max = values.detect {|value| value >= item_count} || item_count
422 422 else
423 423 max = item_count
424 424 end
425 425 values = values.select {|value| value <= max || value == selected}
426 426 end
427 427 if values.empty? || (values.size == 1 && values.first == selected)
428 428 return nil
429 429 end
430 430 links = values.collect do |n|
431 431 n == selected ? n : link_to_content_update(n, params.merge(:per_page => n))
432 432 end
433 433 l(:label_display_per_page, links.join(', '))
434 434 end
435 435
436 436 def reorder_links(name, url, method = :post)
437 437 link_to(image_tag('2uparrow.png', :alt => l(:label_sort_highest)),
438 438 url.merge({"#{name}[move_to]" => 'highest'}),
439 439 :method => method, :title => l(:label_sort_highest)) +
440 440 link_to(image_tag('1uparrow.png', :alt => l(:label_sort_higher)),
441 441 url.merge({"#{name}[move_to]" => 'higher'}),
442 442 :method => method, :title => l(:label_sort_higher)) +
443 443 link_to(image_tag('1downarrow.png', :alt => l(:label_sort_lower)),
444 444 url.merge({"#{name}[move_to]" => 'lower'}),
445 445 :method => method, :title => l(:label_sort_lower)) +
446 446 link_to(image_tag('2downarrow.png', :alt => l(:label_sort_lowest)),
447 447 url.merge({"#{name}[move_to]" => 'lowest'}),
448 448 :method => method, :title => l(:label_sort_lowest))
449 449 end
450 450
451 451 def breadcrumb(*args)
452 452 elements = args.flatten
453 453 elements.any? ? content_tag('p', (args.join(" \xc2\xbb ") + " \xc2\xbb ").html_safe, :class => 'breadcrumb') : nil
454 454 end
455 455
456 456 def other_formats_links(&block)
457 457 concat('<p class="other-formats">'.html_safe + l(:label_export_to))
458 458 yield Redmine::Views::OtherFormatsBuilder.new(self)
459 459 concat('</p>'.html_safe)
460 460 end
461 461
462 462 def page_header_title
463 463 if @project.nil? || @project.new_record?
464 464 h(Setting.app_title)
465 465 else
466 466 b = []
467 467 ancestors = (@project.root? ? [] : @project.ancestors.visible.all)
468 468 if ancestors.any?
469 469 root = ancestors.shift
470 470 b << link_to_project(root, {:jump => current_menu_item}, :class => 'root')
471 471 if ancestors.size > 2
472 472 b << "\xe2\x80\xa6"
473 473 ancestors = ancestors[-2, 2]
474 474 end
475 475 b += ancestors.collect {|p| link_to_project(p, {:jump => current_menu_item}, :class => 'ancestor') }
476 476 end
477 477 b << h(@project)
478 478 b.join(" \xc2\xbb ").html_safe
479 479 end
480 480 end
481 481
482 482 def html_title(*args)
483 483 if args.empty?
484 484 title = @html_title || []
485 485 title << @project.name if @project
486 486 title << Setting.app_title unless Setting.app_title == title.last
487 487 title.select {|t| !t.blank? }.join(' - ')
488 488 else
489 489 @html_title ||= []
490 490 @html_title += args
491 491 end
492 492 end
493 493
494 494 # Returns the theme, controller name, and action as css classes for the
495 495 # HTML body.
496 496 def body_css_classes
497 497 css = []
498 498 if theme = Redmine::Themes.theme(Setting.ui_theme)
499 499 css << 'theme-' + theme.name
500 500 end
501 501
502 502 css << 'controller-' + controller_name
503 503 css << 'action-' + action_name
504 504 css.join(' ')
505 505 end
506 506
507 507 def accesskey(s)
508 508 Redmine::AccessKeys.key_for s
509 509 end
510 510
511 511 # Formats text according to system settings.
512 512 # 2 ways to call this method:
513 513 # * with a String: textilizable(text, options)
514 514 # * with an object and one of its attribute: textilizable(issue, :description, options)
515 515 def textilizable(*args)
516 516 options = args.last.is_a?(Hash) ? args.pop : {}
517 517 case args.size
518 518 when 1
519 519 obj = options[:object]
520 520 text = args.shift
521 521 when 2
522 522 obj = args.shift
523 523 attr = args.shift
524 524 text = obj.send(attr).to_s
525 525 else
526 526 raise ArgumentError, 'invalid arguments to textilizable'
527 527 end
528 528 return '' if text.blank?
529 529 project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil)
530 530 only_path = options.delete(:only_path) == false ? false : true
531 531
532 532 text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text, :object => obj, :attribute => attr)
533 533
534 534 @parsed_headings = []
535 535 @heading_anchors = {}
536 536 @current_section = 0 if options[:edit_section_links]
537 537
538 538 parse_sections(text, project, obj, attr, only_path, options)
539 539 text = parse_non_pre_blocks(text) do |text|
540 540 [:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links, :parse_macros].each do |method_name|
541 541 send method_name, text, project, obj, attr, only_path, options
542 542 end
543 543 end
544 544 parse_headings(text, project, obj, attr, only_path, options)
545 545
546 546 if @parsed_headings.any?
547 547 replace_toc(text, @parsed_headings)
548 548 end
549 549
550 550 text.html_safe
551 551 end
552 552
553 553 def parse_non_pre_blocks(text)
554 554 s = StringScanner.new(text)
555 555 tags = []
556 556 parsed = ''
557 557 while !s.eos?
558 558 s.scan(/(.*?)(<(\/)?(pre|code)(.*?)>|\z)/im)
559 559 text, full_tag, closing, tag = s[1], s[2], s[3], s[4]
560 560 if tags.empty?
561 561 yield text
562 562 end
563 563 parsed << text
564 564 if tag
565 565 if closing
566 566 if tags.last == tag.downcase
567 567 tags.pop
568 568 end
569 569 else
570 570 tags << tag.downcase
571 571 end
572 572 parsed << full_tag
573 573 end
574 574 end
575 575 # Close any non closing tags
576 576 while tag = tags.pop
577 577 parsed << "</#{tag}>"
578 578 end
579 579 parsed
580 580 end
581 581
582 582 def parse_inline_attachments(text, project, obj, attr, only_path, options)
583 583 # when using an image link, try to use an attachment, if possible
584 584 if options[:attachments] || (obj && obj.respond_to?(:attachments))
585 585 attachments = options[:attachments] || obj.attachments
586 586 text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpe|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m|
587 587 filename, ext, alt, alttext = $1.downcase, $2, $3, $4
588 588 # search for the picture in attachments
589 589 if found = Attachment.latest_attach(attachments, filename)
590 590 image_url = url_for :only_path => only_path, :controller => 'attachments',
591 591 :action => 'download', :id => found
592 592 desc = found.description.to_s.gsub('"', '')
593 593 if !desc.blank? && alttext.blank?
594 594 alt = " title=\"#{desc}\" alt=\"#{desc}\""
595 595 end
596 596 "src=\"#{image_url}\"#{alt}"
597 597 else
598 598 m
599 599 end
600 600 end
601 601 end
602 602 end
603 603
604 604 # Wiki links
605 605 #
606 606 # Examples:
607 607 # [[mypage]]
608 608 # [[mypage|mytext]]
609 609 # wiki links can refer other project wikis, using project name or identifier:
610 610 # [[project:]] -> wiki starting page
611 611 # [[project:|mytext]]
612 612 # [[project:mypage]]
613 613 # [[project:mypage|mytext]]
614 614 def parse_wiki_links(text, project, obj, attr, only_path, options)
615 615 text.gsub!(/(!)?(\[\[([^\]\n\|]+)(\|([^\]\n\|]+))?\]\])/) do |m|
616 616 link_project = project
617 617 esc, all, page, title = $1, $2, $3, $5
618 618 if esc.nil?
619 619 if page =~ /^([^\:]+)\:(.*)$/
620 620 link_project = Project.find_by_identifier($1) || Project.find_by_name($1)
621 621 page = $2
622 622 title ||= $1 if page.blank?
623 623 end
624 624
625 625 if link_project && link_project.wiki
626 626 # extract anchor
627 627 anchor = nil
628 628 if page =~ /^(.+?)\#(.+)$/
629 629 page, anchor = $1, $2
630 630 end
631 631 anchor = sanitize_anchor_name(anchor) if anchor.present?
632 632 # check if page exists
633 633 wiki_page = link_project.wiki.find_page(page)
634 634 url = if anchor.present? && wiki_page.present? && (obj.is_a?(WikiContent) || obj.is_a?(WikiContent::Version)) && obj.page == wiki_page
635 635 "##{anchor}"
636 636 else
637 637 case options[:wiki_links]
638 638 when :local; "#{page.present? ? Wiki.titleize(page) : ''}.html" + (anchor.present? ? "##{anchor}" : '')
639 639 when :anchor; "##{page.present? ? Wiki.titleize(page) : title}" + (anchor.present? ? "_#{anchor}" : '') # used for single-file wiki export
640 640 else
641 641 wiki_page_id = page.present? ? Wiki.titleize(page) : nil
642 642 parent = wiki_page.nil? && obj.is_a?(WikiContent) && obj.page && project == link_project ? obj.page.title : nil
643 643 url_for(:only_path => only_path, :controller => 'wiki', :action => 'show', :project_id => link_project,
644 644 :id => wiki_page_id, :anchor => anchor, :parent => parent)
645 645 end
646 646 end
647 647 link_to(title.present? ? title.html_safe : h(page), url, :class => ('wiki-page' + (wiki_page ? '' : ' new')))
648 648 else
649 649 # project or wiki doesn't exist
650 650 all
651 651 end
652 652 else
653 653 all
654 654 end
655 655 end
656 656 end
657 657
658 658 # Redmine links
659 659 #
660 660 # Examples:
661 661 # Issues:
662 662 # #52 -> Link to issue #52
663 663 # Changesets:
664 664 # r52 -> Link to revision 52
665 665 # commit:a85130f -> Link to scmid starting with a85130f
666 666 # Documents:
667 667 # document#17 -> Link to document with id 17
668 668 # document:Greetings -> Link to the document with title "Greetings"
669 669 # document:"Some document" -> Link to the document with title "Some document"
670 670 # Versions:
671 671 # version#3 -> Link to version with id 3
672 672 # version:1.0.0 -> Link to version named "1.0.0"
673 673 # version:"1.0 beta 2" -> Link to version named "1.0 beta 2"
674 674 # Attachments:
675 675 # attachment:file.zip -> Link to the attachment of the current object named file.zip
676 676 # Source files:
677 677 # source:some/file -> Link to the file located at /some/file in the project's repository
678 678 # source:some/file@52 -> Link to the file's revision 52
679 679 # source:some/file#L120 -> Link to line 120 of the file
680 680 # source:some/file@52#L120 -> Link to line 120 of the file's revision 52
681 681 # export:some/file -> Force the download of the file
682 682 # Forum messages:
683 683 # message#1218 -> Link to message with id 1218
684 684 #
685 685 # Links can refer other objects from other projects, using project identifier:
686 686 # identifier:r52
687 687 # identifier:document:"Some document"
688 688 # identifier:version:1.0.0
689 689 # identifier:source:some/file
690 690 def parse_redmine_links(text, project, obj, attr, only_path, options)
691 691 text.gsub!(%r{([\s\(,\-\[\>]|^)(!)?(([a-z0-9\-_]+):)?(attachment|document|version|forum|news|message|project|commit|source|export)?(((#)|((([a-z0-9\-]+)\|)?(r)))((\d+)((#note)?-(\d+))?)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]][^A-Za-z0-9_/])|,|\s|\]|<|$)}) do |m|
692 692 leading, esc, project_prefix, project_identifier, prefix, repo_prefix, repo_identifier, sep, identifier, comment_suffix, comment_id = $1, $2, $3, $4, $5, $10, $11, $8 || $12 || $18, $14 || $19, $15, $17
693 693 link = nil
694 694 if project_identifier
695 695 project = Project.visible.find_by_identifier(project_identifier)
696 696 end
697 697 if esc.nil?
698 698 if prefix.nil? && sep == 'r'
699 699 if project
700 700 repository = nil
701 701 if repo_identifier
702 702 repository = project.repositories.detect {|repo| repo.identifier == repo_identifier}
703 703 else
704 704 repository = project.repository
705 705 end
706 706 # project.changesets.visible raises an SQL error because of a double join on repositories
707 707 if repository && (changeset = Changeset.visible.find_by_repository_id_and_revision(repository.id, identifier))
708 708 link = link_to(h("#{project_prefix}#{repo_prefix}r#{identifier}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :repository_id => repository.identifier_param, :rev => changeset.revision},
709 709 :class => 'changeset',
710 710 :title => truncate_single_line(changeset.comments, :length => 100))
711 711 end
712 712 end
713 713 elsif sep == '#'
714 714 oid = identifier.to_i
715 715 case prefix
716 716 when nil
717 717 if issue = Issue.visible.find_by_id(oid, :include => :status)
718 718 anchor = comment_id ? "note-#{comment_id}" : nil
719 719 link = link_to("##{oid}", {:only_path => only_path, :controller => 'issues', :action => 'show', :id => oid, :anchor => anchor},
720 720 :class => issue.css_classes,
721 721 :title => "#{truncate(issue.subject, :length => 100)} (#{issue.status.name})")
722 722 end
723 723 when 'document'
724 724 if document = Document.visible.find_by_id(oid)
725 725 link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},
726 726 :class => 'document'
727 727 end
728 728 when 'version'
729 729 if version = Version.visible.find_by_id(oid)
730 730 link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
731 731 :class => 'version'
732 732 end
733 733 when 'message'
734 734 if message = Message.visible.find_by_id(oid, :include => :parent)
735 735 link = link_to_message(message, {:only_path => only_path}, :class => 'message')
736 736 end
737 737 when 'forum'
738 738 if board = Board.visible.find_by_id(oid)
739 739 link = link_to h(board.name), {:only_path => only_path, :controller => 'boards', :action => 'show', :id => board, :project_id => board.project},
740 740 :class => 'board'
741 741 end
742 742 when 'news'
743 743 if news = News.visible.find_by_id(oid)
744 744 link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news},
745 745 :class => 'news'
746 746 end
747 747 when 'project'
748 748 if p = Project.visible.find_by_id(oid)
749 749 link = link_to_project(p, {:only_path => only_path}, :class => 'project')
750 750 end
751 751 end
752 752 elsif sep == ':'
753 753 # removes the double quotes if any
754 754 name = identifier.gsub(%r{^"(.*)"$}, "\\1")
755 755 case prefix
756 756 when 'document'
757 757 if project && document = project.documents.visible.find_by_title(name)
758 758 link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},
759 759 :class => 'document'
760 760 end
761 761 when 'version'
762 762 if project && version = project.versions.visible.find_by_name(name)
763 763 link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
764 764 :class => 'version'
765 765 end
766 766 when 'forum'
767 767 if project && board = project.boards.visible.find_by_name(name)
768 768 link = link_to h(board.name), {:only_path => only_path, :controller => 'boards', :action => 'show', :id => board, :project_id => board.project},
769 769 :class => 'board'
770 770 end
771 771 when 'news'
772 772 if project && news = project.news.visible.find_by_title(name)
773 773 link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news},
774 774 :class => 'news'
775 775 end
776 776 when 'commit', 'source', 'export'
777 777 if project
778 778 repository = nil
779 779 if name =~ %r{^(([a-z0-9\-]+)\|)(.+)$}
780 780 repo_prefix, repo_identifier, name = $1, $2, $3
781 781 repository = project.repositories.detect {|repo| repo.identifier == repo_identifier}
782 782 else
783 783 repository = project.repository
784 784 end
785 785 if prefix == 'commit'
786 786 if repository && (changeset = Changeset.visible.find(:first, :conditions => ["repository_id = ? AND scmid LIKE ?", repository.id, "#{name}%"]))
787 787 link = link_to h("#{project_prefix}#{repo_prefix}#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :repository_id => repository.identifier_param, :rev => changeset.identifier},
788 788 :class => 'changeset',
789 789 :title => truncate_single_line(h(changeset.comments), :length => 100)
790 790 end
791 791 else
792 792 if repository && User.current.allowed_to?(:browse_repository, project)
793 793 name =~ %r{^[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?$}
794 794 path, rev, anchor = $1, $3, $5
795 795 link = link_to h("#{project_prefix}#{prefix}:#{repo_prefix}#{name}"), {:controller => 'repositories', :action => 'entry', :id => project, :repository_id => repository.identifier_param,
796 796 :path => to_path_param(path),
797 797 :rev => rev,
798 798 :anchor => anchor,
799 799 :format => (prefix == 'export' ? 'raw' : nil)},
800 800 :class => (prefix == 'export' ? 'source download' : 'source')
801 801 end
802 802 end
803 803 repo_prefix = nil
804 804 end
805 805 when 'attachment'
806 806 attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil)
807 807 if attachments && attachment = attachments.detect {|a| a.filename == name }
808 808 link = link_to h(attachment.filename), {:only_path => only_path, :controller => 'attachments', :action => 'download', :id => attachment},
809 809 :class => 'attachment'
810 810 end
811 811 when 'project'
812 812 if p = Project.visible.find(:first, :conditions => ["identifier = :s OR LOWER(name) = :s", {:s => name.downcase}])
813 813 link = link_to_project(p, {:only_path => only_path}, :class => 'project')
814 814 end
815 815 end
816 816 end
817 817 end
818 818 (leading + (link || "#{project_prefix}#{prefix}#{repo_prefix}#{sep}#{identifier}#{comment_suffix}"))
819 819 end
820 820 end
821 821
822 822 HEADING_RE = /(<h(1|2|3|4)( [^>]+)?>(.+?)<\/h(1|2|3|4)>)/i unless const_defined?(:HEADING_RE)
823 823
824 824 def parse_sections(text, project, obj, attr, only_path, options)
825 825 return unless options[:edit_section_links]
826 826 text.gsub!(HEADING_RE) do
827 827 heading = $1
828 828 @current_section += 1
829 829 if @current_section > 1
830 830 content_tag('div',
831 831 link_to(image_tag('edit.png'), options[:edit_section_links].merge(:section => @current_section)),
832 832 :class => 'contextual',
833 833 :title => l(:button_edit_section)) + heading.html_safe
834 834 else
835 835 heading
836 836 end
837 837 end
838 838 end
839 839
840 840 # Headings and TOC
841 841 # Adds ids and links to headings unless options[:headings] is set to false
842 842 def parse_headings(text, project, obj, attr, only_path, options)
843 843 return if options[:headings] == false
844 844
845 845 text.gsub!(HEADING_RE) do
846 846 level, attrs, content = $2.to_i, $3, $4
847 847 item = strip_tags(content).strip
848 848 anchor = sanitize_anchor_name(item)
849 849 # used for single-file wiki export
850 850 anchor = "#{obj.page.title}_#{anchor}" if options[:wiki_links] == :anchor && (obj.is_a?(WikiContent) || obj.is_a?(WikiContent::Version))
851 851 @heading_anchors[anchor] ||= 0
852 852 idx = (@heading_anchors[anchor] += 1)
853 853 if idx > 1
854 854 anchor = "#{anchor}-#{idx}"
855 855 end
856 856 @parsed_headings << [level, anchor, item]
857 857 "<a name=\"#{anchor}\"></a>\n<h#{level} #{attrs}>#{content}<a href=\"##{anchor}\" class=\"wiki-anchor\">&para;</a></h#{level}>"
858 858 end
859 859 end
860 860
861 861 MACROS_RE = /
862 862 (!)? # escaping
863 863 (
864 864 \{\{ # opening tag
865 865 ([\w]+) # macro name
866 866 (\(([^\}]*)\))? # optional arguments
867 867 \}\} # closing tag
868 868 )
869 869 /x unless const_defined?(:MACROS_RE)
870 870
871 871 # Macros substitution
872 872 def parse_macros(text, project, obj, attr, only_path, options)
873 873 text.gsub!(MACROS_RE) do
874 874 esc, all, macro = $1, $2, $3.downcase
875 875 args = ($5 || '').split(',').each(&:strip)
876 876 if esc.nil?
877 877 begin
878 878 exec_macro(macro, obj, args)
879 879 rescue => e
880 880 "<div class=\"flash error\">Error executing the <strong>#{macro}</strong> macro (#{e})</div>"
881 881 end || all
882 882 else
883 883 all
884 884 end
885 885 end
886 886 end
887 887
888 888 TOC_RE = /<p>\{\{([<>]?)toc\}\}<\/p>/i unless const_defined?(:TOC_RE)
889 889
890 890 # Renders the TOC with given headings
891 891 def replace_toc(text, headings)
892 892 text.gsub!(TOC_RE) do
893 893 if headings.empty?
894 894 ''
895 895 else
896 896 div_class = 'toc'
897 897 div_class << ' right' if $1 == '>'
898 898 div_class << ' left' if $1 == '<'
899 899 out = "<ul class=\"#{div_class}\"><li>"
900 900 root = headings.map(&:first).min
901 901 current = root
902 902 started = false
903 903 headings.each do |level, anchor, item|
904 904 if level > current
905 905 out << '<ul><li>' * (level - current)
906 906 elsif level < current
907 907 out << "</li></ul>\n" * (current - level) + "</li><li>"
908 908 elsif started
909 909 out << '</li><li>'
910 910 end
911 911 out << "<a href=\"##{anchor}\">#{item}</a>"
912 912 current = level
913 913 started = true
914 914 end
915 915 out << '</li></ul>' * (current - root)
916 916 out << '</li></ul>'
917 917 end
918 918 end
919 919 end
920 920
921 921 # Same as Rails' simple_format helper without using paragraphs
922 922 def simple_format_without_paragraph(text)
923 923 text.to_s.
924 924 gsub(/\r\n?/, "\n"). # \r\n and \r -> \n
925 925 gsub(/\n\n+/, "<br /><br />"). # 2+ newline -> 2 br
926 926 gsub(/([^\n]\n)(?=[^\n])/, '\1<br />'). # 1 newline -> br
927 927 html_safe
928 928 end
929 929
930 930 def lang_options_for_select(blank=true)
931 931 (blank ? [["(auto)", ""]] : []) +
932 932 valid_languages.collect{|lang| [ ll(lang.to_s, :general_lang_name), lang.to_s]}.sort{|x,y| x.last <=> y.last }
933 933 end
934 934
935 935 def label_tag_for(name, option_tags = nil, options = {})
936 936 label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "")
937 937 content_tag("label", label_text)
938 938 end
939 939
940 940 def labelled_tabular_form_for(*args, &proc)
941 941 ActiveSupport::Deprecation.warn "ApplicationHelper#labelled_tabular_form_for is deprecated and will be removed in Redmine 1.5. Use #labelled_form_for instead."
942 942 args << {} unless args.last.is_a?(Hash)
943 943 options = args.last
944 944 options[:html] ||= {}
945 945 options[:html][:class] = 'tabular' unless options[:html].has_key?(:class)
946 946 options.merge!({:builder => Redmine::Views::LabelledFormBuilder})
947 947 form_for(*args, &proc)
948 948 end
949 949
950 950 def labelled_form_for(*args, &proc)
951 951 args << {} unless args.last.is_a?(Hash)
952 952 options = args.last
953 953 if args.first.is_a?(Symbol)
954 954 options.merge!(:as => args.shift)
955 955 end
956 956 options.merge!({:builder => Redmine::Views::LabelledFormBuilder})
957 957 form_for(*args, &proc)
958 958 end
959 959
960 960 def labelled_fields_for(*args, &proc)
961 961 args << {} unless args.last.is_a?(Hash)
962 962 options = args.last
963 963 options.merge!({:builder => Redmine::Views::LabelledFormBuilder})
964 964 fields_for(*args, &proc)
965 965 end
966 966
967 967 def labelled_remote_form_for(*args, &proc)
968 968 args << {} unless args.last.is_a?(Hash)
969 969 options = args.last
970 970 options.merge!({:builder => Redmine::Views::LabelledFormBuilder, :remote => true})
971 971 form_for(*args, &proc)
972 972 end
973 973
974 974 def error_messages_for(*objects)
975 975 html = ""
976 976 objects = objects.map {|o| o.is_a?(String) ? instance_variable_get("@#{o}") : o}.compact
977 977 errors = objects.map {|o| o.errors.full_messages}.flatten
978 978 if errors.any?
979 979 html << "<div id='errorExplanation'><ul>\n"
980 980 errors.each do |error|
981 981 html << "<li>#{h error}</li>\n"
982 982 end
983 983 html << "</ul></div>\n"
984 984 end
985 985 html.html_safe
986 986 end
987 987
988 def delete_link(url, options={})
989 options = {
990 :method => :delete,
991 :data => {:confirm => l(:text_are_you_sure)},
992 :class => 'icon icon-del'
993 }.merge(options)
994
995 link_to l(:button_delete), url, options
996 end
997
988 998 def back_url_hidden_field_tag
989 999 back_url = params[:back_url] || request.env['HTTP_REFERER']
990 1000 back_url = CGI.unescape(back_url.to_s)
991 1001 hidden_field_tag('back_url', CGI.escape(back_url), :id => nil) unless back_url.blank?
992 1002 end
993 1003
994 1004 def check_all_links(form_name)
995 1005 link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") +
996 1006 " | ".html_safe +
997 1007 link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)")
998 1008 end
999 1009
1000 1010 def progress_bar(pcts, options={})
1001 1011 pcts = [pcts, pcts] unless pcts.is_a?(Array)
1002 1012 pcts = pcts.collect(&:round)
1003 1013 pcts[1] = pcts[1] - pcts[0]
1004 1014 pcts << (100 - pcts[1] - pcts[0])
1005 1015 width = options[:width] || '100px;'
1006 1016 legend = options[:legend] || ''
1007 1017 content_tag('table',
1008 1018 content_tag('tr',
1009 1019 (pcts[0] > 0 ? content_tag('td', '', :style => "width: #{pcts[0]}%;", :class => 'closed') : ''.html_safe) +
1010 1020 (pcts[1] > 0 ? content_tag('td', '', :style => "width: #{pcts[1]}%;", :class => 'done') : ''.html_safe) +
1011 1021 (pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2]}%;", :class => 'todo') : ''.html_safe)
1012 1022 ), :class => 'progress', :style => "width: #{width};").html_safe +
1013 1023 content_tag('p', legend, :class => 'pourcent').html_safe
1014 1024 end
1015 1025
1016 1026 def checked_image(checked=true)
1017 1027 if checked
1018 1028 image_tag 'toggle_check.png'
1019 1029 end
1020 1030 end
1021 1031
1022 1032 def context_menu(url)
1023 1033 unless @context_menu_included
1024 1034 content_for :header_tags do
1025 1035 javascript_include_tag('context_menu') +
1026 1036 stylesheet_link_tag('context_menu')
1027 1037 end
1028 1038 if l(:direction) == 'rtl'
1029 1039 content_for :header_tags do
1030 1040 stylesheet_link_tag('context_menu_rtl')
1031 1041 end
1032 1042 end
1033 1043 @context_menu_included = true
1034 1044 end
1035 1045 javascript_tag "new ContextMenu('#{ url_for(url) }')"
1036 1046 end
1037 1047
1038 1048 def calendar_for(field_id)
1039 1049 include_calendar_headers_tags
1040 1050 image_tag("calendar.png", {:id => "#{field_id}_trigger",:class => "calendar-trigger"}) +
1041 1051 javascript_tag("Calendar.setup({inputField : '#{field_id}', ifFormat : '%Y-%m-%d', button : '#{field_id}_trigger' });")
1042 1052 end
1043 1053
1044 1054 def include_calendar_headers_tags
1045 1055 unless @calendar_headers_tags_included
1046 1056 @calendar_headers_tags_included = true
1047 1057 content_for :header_tags do
1048 1058 start_of_week = case Setting.start_of_week.to_i
1049 1059 when 1
1050 1060 'Calendar._FD = 1;' # Monday
1051 1061 when 7
1052 1062 'Calendar._FD = 0;' # Sunday
1053 1063 when 6
1054 1064 'Calendar._FD = 6;' # Saturday
1055 1065 else
1056 1066 '' # use language
1057 1067 end
1058 1068
1059 1069 javascript_include_tag('calendar/calendar') +
1060 1070 javascript_include_tag("calendar/lang/calendar-#{current_language.to_s.downcase}.js") +
1061 1071 javascript_tag(start_of_week) +
1062 1072 javascript_include_tag('calendar/calendar-setup') +
1063 1073 stylesheet_link_tag('calendar')
1064 1074 end
1065 1075 end
1066 1076 end
1067 1077
1068 1078 # Overrides Rails' stylesheet_link_tag with themes and plugins support.
1069 1079 # Examples:
1070 1080 # stylesheet_link_tag('styles') # => picks styles.css from the current theme or defaults
1071 1081 # stylesheet_link_tag('styles', :plugin => 'foo) # => picks styles.css from plugin's assets
1072 1082 #
1073 1083 def stylesheet_link_tag(*sources)
1074 1084 options = sources.last.is_a?(Hash) ? sources.pop : {}
1075 1085 plugin = options.delete(:plugin)
1076 1086 sources = sources.map do |source|
1077 1087 if plugin
1078 1088 "/plugin_assets/#{plugin}/stylesheets/#{source}"
1079 1089 elsif current_theme && current_theme.stylesheets.include?(source)
1080 1090 current_theme.stylesheet_path(source)
1081 1091 else
1082 1092 source
1083 1093 end
1084 1094 end
1085 1095 super sources, options
1086 1096 end
1087 1097
1088 1098 # Overrides Rails' image_tag with themes and plugins support.
1089 1099 # Examples:
1090 1100 # image_tag('image.png') # => picks image.png from the current theme or defaults
1091 1101 # image_tag('image.png', :plugin => 'foo) # => picks image.png from plugin's assets
1092 1102 #
1093 1103 def image_tag(source, options={})
1094 1104 if plugin = options.delete(:plugin)
1095 1105 source = "/plugin_assets/#{plugin}/images/#{source}"
1096 1106 elsif current_theme && current_theme.images.include?(source)
1097 1107 source = current_theme.image_path(source)
1098 1108 end
1099 1109 super source, options
1100 1110 end
1101 1111
1102 1112 # Overrides Rails' javascript_include_tag with plugins support
1103 1113 # Examples:
1104 1114 # javascript_include_tag('scripts') # => picks scripts.js from defaults
1105 1115 # javascript_include_tag('scripts', :plugin => 'foo) # => picks scripts.js from plugin's assets
1106 1116 #
1107 1117 def javascript_include_tag(*sources)
1108 1118 options = sources.last.is_a?(Hash) ? sources.pop : {}
1109 1119 if plugin = options.delete(:plugin)
1110 1120 sources = sources.map do |source|
1111 1121 if plugin
1112 1122 "/plugin_assets/#{plugin}/javascripts/#{source}"
1113 1123 else
1114 1124 source
1115 1125 end
1116 1126 end
1117 1127 end
1118 1128 super sources, options
1119 1129 end
1120 1130
1121 1131 def content_for(name, content = nil, &block)
1122 1132 @has_content ||= {}
1123 1133 @has_content[name] = true
1124 1134 super(name, content, &block)
1125 1135 end
1126 1136
1127 1137 def has_content?(name)
1128 1138 (@has_content && @has_content[name]) || false
1129 1139 end
1130 1140
1131 1141 def sidebar_content?
1132 1142 has_content?(:sidebar) || view_layouts_base_sidebar_hook_response.present?
1133 1143 end
1134 1144
1135 1145 def view_layouts_base_sidebar_hook_response
1136 1146 @view_layouts_base_sidebar_hook_response ||= call_hook(:view_layouts_base_sidebar)
1137 1147 end
1138 1148
1139 1149 def email_delivery_enabled?
1140 1150 !!ActionMailer::Base.perform_deliveries
1141 1151 end
1142 1152
1143 1153 # Returns the avatar image tag for the given +user+ if avatars are enabled
1144 1154 # +user+ can be a User or a string that will be scanned for an email address (eg. 'joe <joe@foo.bar>')
1145 1155 def avatar(user, options = { })
1146 1156 if Setting.gravatar_enabled?
1147 1157 options.merge!({:ssl => (request && request.ssl?), :default => Setting.gravatar_default})
1148 1158 email = nil
1149 1159 if user.respond_to?(:mail)
1150 1160 email = user.mail
1151 1161 elsif user.to_s =~ %r{<(.+?)>}
1152 1162 email = $1
1153 1163 end
1154 1164 return gravatar(email.to_s.downcase, options) unless email.blank? rescue nil
1155 1165 else
1156 1166 ''
1157 1167 end
1158 1168 end
1159 1169
1160 1170 def sanitize_anchor_name(anchor)
1161 1171 anchor.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
1162 1172 end
1163 1173
1164 1174 # Returns the javascript tags that are included in the html layout head
1165 1175 def javascript_heads
1166 1176 tags = javascript_include_tag('prototype', 'effects', 'dragdrop', 'controls', 'rails', 'application')
1167 1177 unless User.current.pref.warn_on_leaving_unsaved == '0'
1168 1178 tags << "\n".html_safe + javascript_tag("Event.observe(window, 'load', function(){ new WarnLeavingUnsaved('#{escape_javascript( l(:text_warn_on_leaving_unsaved) )}'); });")
1169 1179 end
1170 1180 tags
1171 1181 end
1172 1182
1173 1183 def favicon
1174 1184 "<link rel='shortcut icon' href='#{image_path('/favicon.ico')}' />".html_safe
1175 1185 end
1176 1186
1177 1187 def robot_exclusion_tag
1178 1188 '<meta name="robots" content="noindex,follow,noarchive" />'.html_safe
1179 1189 end
1180 1190
1181 1191 # Returns true if arg is expected in the API response
1182 1192 def include_in_api_response?(arg)
1183 1193 unless @included_in_api_response
1184 1194 param = params[:include]
1185 1195 @included_in_api_response = param.is_a?(Array) ? param.collect(&:to_s) : param.to_s.split(',')
1186 1196 @included_in_api_response.collect!(&:strip)
1187 1197 end
1188 1198 @included_in_api_response.include?(arg.to_s)
1189 1199 end
1190 1200
1191 1201 # Returns options or nil if nometa param or X-Redmine-Nometa header
1192 1202 # was set in the request
1193 1203 def api_meta(options)
1194 1204 if params[:nometa].present? || request.headers['X-Redmine-Nometa']
1195 1205 # compatibility mode for activeresource clients that raise
1196 1206 # an error when unserializing an array with attributes
1197 1207 nil
1198 1208 else
1199 1209 options
1200 1210 end
1201 1211 end
1202 1212
1203 1213 private
1204 1214
1205 1215 def wiki_helper
1206 1216 helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting)
1207 1217 extend helper
1208 1218 return self
1209 1219 end
1210 1220
1211 1221 def link_to_content_update(text, url_params = {}, html_options = {})
1212 1222 link_to(text, url_params, html_options)
1213 1223 end
1214 1224 end
@@ -1,45 +1,45
1 1 <div class="contextual">
2 2 <%= link_to l(:label_project_new), {:controller => 'projects', :action => 'new'}, :class => 'icon icon-add' %>
3 3 </div>
4 4
5 5 <h2><%=l(:label_project_plural)%></h2>
6 6
7 7 <%= form_tag({}, :method => :get) do %>
8 8 <fieldset><legend><%= l(:label_filter_plural) %></legend>
9 9 <label for='status'><%= l(:field_status) %> :</label>
10 10 <%= select_tag 'status', project_status_options_for_select(@status), :class => "small", :onchange => "this.form.submit(); return false;" %>
11 11 <label for='name'><%= l(:label_project) %>:</label>
12 12 <%= text_field_tag 'name', params[:name], :size => 30 %>
13 13 <%= submit_tag l(:button_apply), :class => "small", :name => nil %>
14 14 <%= link_to l(:button_clear), {:controller => 'admin', :action => 'projects'}, :class => 'icon icon-reload' %>
15 15 </fieldset>
16 16 <% end %>
17 17 &nbsp;
18 18
19 19 <div class="autoscroll">
20 20 <table class="list">
21 21 <thead><tr>
22 22 <th><%=l(:label_project)%></th>
23 23 <th><%=l(:field_is_public)%></th>
24 24 <th><%=l(:field_created_on)%></th>
25 25 <th></th>
26 26 </tr></thead>
27 27 <tbody>
28 28 <% project_tree(@projects) do |project, level| %>
29 29 <tr class="<%= cycle("odd", "even") %> <%= project.css_classes %> <%= level > 0 ? "idnt idnt-#{level}" : nil %>">
30 30 <td class="name"><span><%= link_to_project(project, {:action => (project.active? ? 'settings' : 'show')}, :title => project.short_description) %></span></td>
31 31 <td align="center"><%= checked_image project.is_public? %></td>
32 32 <td align="center"><%= format_date(project.created_on) %></td>
33 33 <td class="buttons">
34 <%= 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') unless project.archived? %>
34 <%= link_to(l(:button_archive), { :controller => 'projects', :action => 'archive', :id => project, :status => params[:status] }, :data => {:confirm => l(:text_are_you_sure)}, :method => :post, :class => 'icon icon-lock') unless project.archived? %>
35 35 <%= link_to(l(:button_unarchive), { :controller => 'projects', :action => 'unarchive', :id => project, :status => params[:status] }, :method => :post, :class => 'icon icon-unlock') if project.archived? && (project.parent.nil? || !project.parent.archived?) %>
36 36 <%= link_to(l(:button_copy), { :controller => 'projects', :action => 'copy', :id => project }, :class => 'icon icon-copy') %>
37 37 <%= link_to(l(:button_delete), project_path(project), :method => :delete, :class => 'icon icon-del') %>
38 38 </td>
39 39 </tr>
40 40 <% end %>
41 41 </tbody>
42 42 </table>
43 43 </div>
44 44
45 45 <% html_title(l(:label_project_plural)) -%>
@@ -1,33 +1,33
1 1 <div class="attachments">
2 2 <% for attachment in attachments %>
3 3 <p><%= link_to_attachment attachment, :class => 'icon icon-attachment', :download => true -%>
4 4 <% if attachment.is_text? %>
5 5 <%= link_to image_tag('magnifier.png'),
6 6 :controller => 'attachments', :action => 'show',
7 7 :id => attachment, :filename => attachment.filename %>
8 8 <% end %>
9 9 <%= h(" - #{attachment.description}") unless attachment.description.blank? %>
10 10 <span class="size">(<%= number_to_human_size attachment.filesize %>)</span>
11 11 <% if options[:deletable] %>
12 12 <%= link_to image_tag('delete.png'), attachment_path(attachment),
13 :confirm => l(:text_are_you_sure),
13 :data => {:confirm => l(:text_are_you_sure)},
14 14 :method => :delete,
15 15 :class => 'delete',
16 16 :title => l(:button_delete) %>
17 17 <% end %>
18 18 <% if options[:author] %>
19 19 <span class="author"><%= h(attachment.author) %>, <%= format_time(attachment.created_on) %></span>
20 20 <% end %>
21 21 </p>
22 22 <% end %>
23 23 <% if defined?(thumbnails) && thumbnails %>
24 24 <% images = attachments.select(&:thumbnailable?) %>
25 25 <% if images.any? %>
26 26 <div class="thumbnails">
27 27 <% images.each do |attachment| %>
28 28 <div><%= thumbnail_tag(attachment) %></div>
29 29 <% end %>
30 30 </div>
31 31 <% end %>
32 32 <% end %>
33 33 </div>
@@ -1,35 +1,31
1 1 <div class="contextual">
2 2 <%= link_to l(:label_auth_source_new), {:action => 'new'}, :class => 'icon icon-add' %>
3 3 </div>
4 4
5 5 <h2><%=l(:label_auth_source_plural)%></h2>
6 6
7 7 <table class="list">
8 8 <thead><tr>
9 9 <th><%=l(:field_name)%></th>
10 10 <th><%=l(:field_type)%></th>
11 11 <th><%=l(:field_host)%></th>
12 12 <th><%=l(:label_user_plural)%></th>
13 13 <th></th>
14 14 </tr></thead>
15 15 <tbody>
16 16 <% for source in @auth_sources %>
17 17 <tr id="auth-source-<%= source.id %>" class="<%= cycle("odd", "even") %>">
18 18 <td><%= link_to(h(source.name), :action => 'edit', :id => source)%></td>
19 19 <td align="center"><%= h source.auth_method_name %></td>
20 20 <td align="center"><%= h source.host %></td>
21 21 <td align="center"><%= h source.users.count %></td>
22 22 <td class="buttons">
23 23 <%= link_to l(:button_test), {:action => 'test_connection', :id => source}, :class => 'icon icon-test' %>
24 <%= link_to l(:button_delete), { :action => 'destroy', :id => source },
25 :method => :delete,
26 :confirm => l(:text_are_you_sure),
27 :class => 'icon icon-del',
28 :disabled => source.users.any? %>
24 <%= delete_link auth_source_path(source) %>
29 25 </td>
30 26 </tr>
31 27 <% end %>
32 28 </tbody>
33 29 </table>
34 30
35 31 <p class="pagination"><%= pagination_links_full @auth_source_pages %></p>
@@ -1,142 +1,142
1 1 <ul>
2 2 <%= call_hook(:view_issues_context_menu_start, {:issues => @issues, :can => @can, :back => @back }) %>
3 3
4 4 <% if !@issue.nil? -%>
5 5 <li><%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'edit', :id => @issue},
6 6 :class => 'icon-edit', :disabled => !@can[:edit] %></li>
7 7 <% else %>
8 8 <li><%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id)},
9 9 :class => 'icon-edit', :disabled => !@can[:edit] %></li>
10 10 <% end %>
11 11
12 12 <% if @allowed_statuses.present? %>
13 13 <li class="folder">
14 14 <a href="#" class="submenu"><%= l(:field_status) %></a>
15 15 <ul>
16 16 <% @allowed_statuses.each do |s| -%>
17 17 <li><%= context_menu_link h(s.name), {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {:status_id => s}, :back_url => @back}, :method => :post,
18 18 :selected => (@issue && s == @issue.status), :disabled => !@can[:update] %></li>
19 19 <% end -%>
20 20 </ul>
21 21 </li>
22 22 <% end %>
23 23
24 24 <% unless @trackers.nil? %>
25 25 <li class="folder">
26 26 <a href="#" class="submenu"><%= l(:field_tracker) %></a>
27 27 <ul>
28 28 <% @trackers.each do |t| -%>
29 29 <li><%= context_menu_link h(t.name), {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {'tracker_id' => t}, :back_url => @back}, :method => :post,
30 30 :selected => (@issue && t == @issue.tracker), :disabled => !@can[:edit] %></li>
31 31 <% end -%>
32 32 </ul>
33 33 </li>
34 34 <% end %>
35 35
36 36 <% if @safe_attributes.include?('priority_id') -%>
37 37 <li class="folder">
38 38 <a href="#" class="submenu"><%= l(:field_priority) %></a>
39 39 <ul>
40 40 <% @priorities.each do |p| -%>
41 41 <li><%= context_menu_link h(p.name), {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {'priority_id' => p}, :back_url => @back}, :method => :post,
42 42 :selected => (@issue && p == @issue.priority), :disabled => (!@can[:edit] || @issues.detect {|i| !i.leaf?}) %></li>
43 43 <% end -%>
44 44 </ul>
45 45 </li>
46 46 <% end %>
47 47
48 48 <% #TODO: allow editing versions when multiple projects %>
49 49 <% if @safe_attributes.include?('fixed_version_id') && @project && @project.shared_versions.open.any? -%>
50 50 <li class="folder">
51 51 <a href="#" class="submenu"><%= l(:field_fixed_version) %></a>
52 52 <ul>
53 53 <% @project.shared_versions.open.sort.each do |v| -%>
54 54 <li><%= context_menu_link format_version_name(v), {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {'fixed_version_id' => v}, :back_url => @back}, :method => :post,
55 55 :selected => (@issue && v == @issue.fixed_version), :disabled => !@can[:update] %></li>
56 56 <% end -%>
57 57 <li><%= context_menu_link l(:label_none), {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {'fixed_version_id' => 'none'}, :back_url => @back}, :method => :post,
58 58 :selected => (@issue && @issue.fixed_version.nil?), :disabled => !@can[:update] %></li>
59 59 </ul>
60 60 </li>
61 61 <% end %>
62 62
63 63 <% if @safe_attributes.include?('assigned_to_id') && @assignables.present? -%>
64 64 <li class="folder">
65 65 <a href="#" class="submenu"><%= l(:field_assigned_to) %></a>
66 66 <ul>
67 67 <% if @assignables.include?(User.current) %>
68 68 <li><%= context_menu_link "<< #{l(:label_me)} >>", {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {'assigned_to_id' => User.current}, :back_url => @back}, :method => :post,
69 69 :disabled => !@can[:update] %></li>
70 70 <% end %>
71 71 <% @assignables.each do |u| -%>
72 72 <li><%= context_menu_link h(u.name), {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {'assigned_to_id' => u}, :back_url => @back}, :method => :post,
73 73 :selected => (@issue && u == @issue.assigned_to), :disabled => !@can[:update] %></li>
74 74 <% end -%>
75 75 <li><%= context_menu_link l(:label_nobody), {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {'assigned_to_id' => 'none'}, :back_url => @back}, :method => :post,
76 76 :selected => (@issue && @issue.assigned_to.nil?), :disabled => !@can[:update] %></li>
77 77 </ul>
78 78 </li>
79 79 <% end %>
80 80
81 81 <% if @safe_attributes.include?('category_id') && @project && @project.issue_categories.any? -%>
82 82 <li class="folder">
83 83 <a href="#" class="submenu"><%= l(:field_category) %></a>
84 84 <ul>
85 85 <% @project.issue_categories.each do |u| -%>
86 86 <li><%= context_menu_link h(u.name), {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {'category_id' => u}, :back_url => @back}, :method => :post,
87 87 :selected => (@issue && u == @issue.category), :disabled => !@can[:update] %></li>
88 88 <% end -%>
89 89 <li><%= context_menu_link l(:label_none), {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {'category_id' => 'none'}, :back_url => @back}, :method => :post,
90 90 :selected => (@issue && @issue.category.nil?), :disabled => !@can[:update] %></li>
91 91 </ul>
92 92 </li>
93 93 <% end -%>
94 94
95 95 <% if @safe_attributes.include?('done_ratio') && Issue.use_field_for_done_ratio? %>
96 96 <li class="folder">
97 97 <a href="#" class="submenu"><%= l(:field_done_ratio) %></a>
98 98 <ul>
99 99 <% (0..10).map{|x|x*10}.each do |p| -%>
100 100 <li><%= context_menu_link "#{p}%", {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {'done_ratio' => p}, :back_url => @back}, :method => :post,
101 101 :selected => (@issue && p == @issue.done_ratio), :disabled => (!@can[:edit] || @issues.detect {|i| !i.leaf?}) %></li>
102 102 <% end -%>
103 103 </ul>
104 104 </li>
105 105 <% end %>
106 106
107 107 <% @options_by_custom_field.each do |field, options| %>
108 108 <li class="folder">
109 109 <a href="#" class="submenu"><%= h(field.name) %></a>
110 110 <ul>
111 111 <% options.each do |text, value| %>
112 112 <li><%= bulk_update_custom_field_context_menu_link(field, text, value || text) %></li>
113 113 <% end %>
114 114 <% unless field.is_required? %>
115 115 <li><%= bulk_update_custom_field_context_menu_link(field, l(:label_none), '') %></li>
116 116 <% end %>
117 117 </ul>
118 118 </li>
119 119 <% end %>
120 120
121 121 <% if !@issue.nil? %>
122 122 <% if @can[:log_time] -%>
123 123 <li><%= context_menu_link l(:button_log_time), {:controller => 'timelog', :action => 'new', :issue_id => @issue},
124 124 :class => 'icon-time-add' %></li>
125 125 <% end %>
126 126 <% if User.current.logged? %>
127 127 <li><%= watcher_link(@issue, User.current) %></li>
128 128 <% end %>
129 129 <% end %>
130 130
131 131 <% if @issue.present? %>
132 132 <li><%= context_menu_link l(:button_copy), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue},
133 133 :class => 'icon-copy', :disabled => !@can[:copy] %></li>
134 134 <% else %>
135 135 <li><%= context_menu_link l(:button_copy), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :copy => '1'},
136 136 :class => 'icon-copy', :disabled => !@can[:move] %></li>
137 137 <% end %>
138 138 <li><%= context_menu_link l(:button_delete), issues_path(:ids => @issues.collect(&:id), :back_url => @back),
139 :method => :delete, :confirm => issues_destroy_confirmation_message(@issues), :class => 'icon-del', :disabled => !@can[:delete] %></li>
139 :method => :delete, :data => {:confirm => issues_destroy_confirmation_message(@issues)}, :class => 'icon-del', :disabled => !@can[:delete] %></li>
140 140
141 141 <%= call_hook(:view_issues_context_menu_end, {:issues => @issues, :can => @can, :back => @back }) %>
142 142 </ul>
@@ -1,33 +1,33
1 1 <ul>
2 2 <% if !@time_entry.nil? -%>
3 3 <li><%= context_menu_link l(:button_edit), {:controller => 'timelog', :action => 'edit', :id => @time_entry},
4 4 :class => 'icon-edit', :disabled => !@can[:edit] %></li>
5 5 <% else %>
6 6 <li><%= context_menu_link l(:button_edit), {:controller => 'timelog', :action => 'bulk_edit', :ids => @time_entries.collect(&:id)},
7 7 :class => 'icon-edit', :disabled => !@can[:edit] %></li>
8 8 <% end %>
9 9
10 10 <%= call_hook(:view_time_entries_context_menu_start, {:time_entries => @time_entries, :can => @can, :back => @back }) %>
11 11
12 12 <% if @activities.present? -%>
13 13 <li class="folder">
14 14 <a href="#" class="submenu"><%= l(:field_activity) %></a>
15 15 <ul>
16 16 <% @activities.each do |u| -%>
17 17 <li><%= context_menu_link h(u.name), {:controller => 'timelog', :action => 'bulk_update', :ids => @time_entries.collect(&:id), :time_entry => {'activity_id' => u}, :back_url => @back}, :method => :post,
18 18 :selected => (@time_entry && u == @time_entry.activity), :disabled => !@can[:edit] %></li>
19 19 <% end -%>
20 20 <li><%= context_menu_link l(:label_none), {:controller => 'timelog', :action => 'bulk_update', :ids => @time_entries.collect(&:id), :time_entry => {'activity_id' => 'none'}, :back_url => @back}, :method => :post,
21 21 :selected => (@time_entry && @time_entry.activity.nil?), :disabled => !@can[:edit] %></li>
22 22 </ul>
23 23 </li>
24 24 <% end %>
25 25
26 26 <%= call_hook(:view_time_entries_context_menu_end, {:time_entries => @time_entries, :can => @can, :back => @back }) %>
27 27
28 28 <li>
29 29 <%= context_menu_link l(:button_delete),
30 30 {:controller => 'timelog', :action => 'destroy', :ids => @time_entries.collect(&:id), :back_url => @back},
31 :method => :delete, :confirm => l(:text_time_entries_destroy_confirmation), :class => 'icon-del', :disabled => !@can[:delete] %>
31 :method => :delete, :data => {:confirm => l(:text_time_entries_destroy_confirmation)}, :class => 'icon-del', :disabled => !@can[:delete] %>
32 32 </li>
33 33 </ul>
@@ -1,35 +1,32
1 1 <table class="list">
2 2 <thead><tr>
3 3 <th width="30%"><%=l(:field_name)%></th>
4 4 <th><%=l(:field_field_format)%></th>
5 5 <th><%=l(:field_is_required)%></th>
6 6 <% if tab[:name] == 'IssueCustomField' %>
7 7 <th><%=l(:field_is_for_all)%></th>
8 8 <th><%=l(:label_used_by)%></th>
9 9 <% end %>
10 10 <th><%=l(:button_sort)%></th>
11 11 <th width="10%"></th>
12 12 </tr></thead>
13 13 <tbody>
14 14 <% (@custom_fields_by_type[tab[:name]] || []).sort.each do |custom_field| -%>
15 15 <tr class="<%= cycle("odd", "even") %>">
16 16 <td><%= link_to h(custom_field.name), edit_custom_field_path(custom_field) %></td>
17 17 <td align="center"><%= l(Redmine::CustomFieldFormat.label_for(custom_field.field_format)) %></td>
18 18 <td align="center"><%= checked_image custom_field.is_required? %></td>
19 19 <% if tab[:name] == 'IssueCustomField' %>
20 20 <td align="center"><%= checked_image custom_field.is_for_all? %></td>
21 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 22 <% end %>
23 23 <td align="center" style="width:15%;"><%= reorder_links('custom_field', {:action => 'update', :id => custom_field}, :put) %></td>
24 24 <td class="buttons">
25 <%= link_to(l(:button_delete), custom_field_path(custom_field),
26 :method => :delete,
27 :confirm => l(:text_are_you_sure),
28 :class => 'icon icon-del') %>
25 <%= delete_link custom_field_path(custom_field) %>
29 26 </td>
30 27 </tr>
31 28 <% end; reset_cycle %>
32 29 </tbody>
33 30 </table>
34 31
35 32 <p><%= link_to l(:label_custom_field_new), new_custom_field_path(:type => tab[:name]), :class => 'icon icon-add' %></p>
@@ -1,34 +1,34
1 1 <div class="contextual">
2 2 <% if User.current.allowed_to?(:manage_documents, @project) %>
3 3 <%= link_to l(:button_edit), edit_document_path(@document), :class => 'icon icon-edit', :accesskey => accesskey(:edit) %>
4 <%= link_to l(:button_delete), document_path(@document), :confirm => l(:text_are_you_sure), :method => :delete, :class => 'icon icon-del' %>
4 <%= delete_link document_path(@document) %>
5 5 <% end %>
6 6 </div>
7 7
8 8 <h2><%=h @document.title %></h2>
9 9
10 10 <p><em><%=h @document.category.name %><br />
11 11 <%= format_date @document.created_on %></em></p>
12 12 <div class="wiki">
13 13 <%= textilizable @document.description, :attachments => @document.attachments %>
14 14 </div>
15 15
16 16 <h3><%= l(:label_attachment_plural) %></h3>
17 17 <%= link_to_attachments @document %>
18 18
19 19 <% if authorize_for('documents', 'add_attachment') %>
20 20 <p><%= link_to l(:label_attachment_new), {}, :onclick => "Element.show('add_attachment_form'); Element.hide(this); Element.scrollTo('add_attachment_form'); return false;",
21 21 :id => 'attach_files_link' %></p>
22 22 <%= form_tag({ :controller => 'documents', :action => 'add_attachment', :id => @document }, :multipart => true, :id => "add_attachment_form", :style => "display:none;") do %>
23 23 <div class="box">
24 24 <p><%= render :partial => 'attachments/form' %></p>
25 25 </div>
26 26 <%= submit_tag l(:button_add) %>
27 27 <% end %>
28 28 <% end %>
29 29
30 30 <% html_title @document.title -%>
31 31
32 32 <% content_for :header_tags do %>
33 33 <%= stylesheet_link_tag 'scm' %>
34 34 <% end %>
@@ -1,37 +1,34
1 1 <h2><%=l(:label_enumerations)%></h2>
2 2
3 3 <% Enumeration.get_subclasses.each do |klass| %>
4 4 <h3><%= l(klass::OptionName) %></h3>
5 5
6 6 <% enumerations = klass.shared %>
7 7 <% if enumerations.any? %>
8 8 <table class="list"><thead>
9 9 <tr>
10 10 <th><%= l(:field_name) %></th>
11 11 <th style="width:15%;"><%= l(:field_is_default) %></th>
12 12 <th style="width:15%;"><%= l(:field_active) %></th>
13 13 <th style="width:15%;"></th>
14 14 <th align="center" style="width:10%;"> </th>
15 15 </tr></thead>
16 16 <% enumerations.each do |enumeration| %>
17 17 <tr class="<%= cycle('odd', 'even') %>">
18 18 <td><%= link_to h(enumeration), edit_enumeration_path(enumeration) %></td>
19 19 <td class="center" style="width:15%;"><%= checked_image enumeration.is_default? %></td>
20 20 <td class="center" style="width:15%;"><%= checked_image enumeration.active? %></td>
21 21 <td style="width:15%;"><%= reorder_links('enumeration', {:action => 'update', :id => enumeration}, :put) %></td>
22 22 <td class="buttons">
23 <%= link_to l(:button_delete), enumeration_path(enumeration),
24 :method => :delete,
25 :confirm => l(:text_are_you_sure),
26 :class => 'icon icon-del' %>
23 <%= delete_link enumeration_path(enumeration) %>
27 24 </td>
28 25 </tr>
29 26 <% end %>
30 27 </table>
31 28 <% reset_cycle %>
32 29 <% end %>
33 30
34 31 <p><%= link_to l(:label_enumeration_new), new_enumeration_path(:type => klass.name) %></p>
35 32 <% end %>
36 33
37 34 <% html_title(l(:label_enumerations)) -%>
@@ -1,46 +1,46
1 1 <div class="contextual">
2 2 <%= link_to(l(:label_attachment_new), new_project_file_path(@project), :class => 'icon icon-add') if User.current.allowed_to?(:manage_files, @project) %>
3 3 </div>
4 4
5 5 <h2><%=l(:label_attachment_plural)%></h2>
6 6
7 7 <% delete_allowed = User.current.allowed_to?(:manage_files, @project) %>
8 8
9 9 <table class="list files">
10 10 <thead><tr>
11 11 <%= sort_header_tag('filename', :caption => l(:field_filename)) %>
12 12 <%= sort_header_tag('created_on', :caption => l(:label_date), :default_order => 'desc') %>
13 13 <%= sort_header_tag('size', :caption => l(:field_filesize), :default_order => 'desc') %>
14 14 <%= sort_header_tag('downloads', :caption => l(:label_downloads_abbr), :default_order => 'desc') %>
15 15 <th>MD5</th>
16 16 <th></th>
17 17 </tr></thead>
18 18 <tbody>
19 19 <% @containers.each do |container| %>
20 20 <% next if container.attachments.empty? -%>
21 21 <% if container.is_a?(Version) -%>
22 22 <tr>
23 23 <th colspan="6" align="left">
24 24 <%= link_to(h(container), {:controller => 'versions', :action => 'show', :id => container}, :class => "icon icon-package") %>
25 25 </th>
26 26 </tr>
27 27 <% end -%>
28 28 <% container.attachments.each do |file| %>
29 29 <tr class="file <%= cycle("odd", "even") %>">
30 30 <td class="filename"><%= link_to_attachment file, :download => true, :title => file.description %></td>
31 31 <td class="created_on"><%= format_time(file.created_on) %></td>
32 32 <td class="filesize"><%= number_to_human_size(file.filesize) %></td>
33 33 <td class="downloads"><%= file.downloads %></td>
34 34 <td class="digest"><%= file.digest %></td>
35 35 <td align="center">
36 36 <%= link_to(image_tag('delete.png'), attachment_path(file),
37 :confirm => l(:text_are_you_sure), :method => :delete) if delete_allowed %>
37 :data => {:confirm => l(:text_are_you_sure)}, :method => :delete) if delete_allowed %>
38 38 </td>
39 39 </tr>
40 40 <% end
41 41 reset_cycle %>
42 42 <% end %>
43 43 </tbody>
44 44 </table>
45 45
46 46 <% html_title(l(:label_attachment_plural)) -%>
@@ -1,25 +1,25
1 1 <div class="contextual">
2 2 <%= link_to l(:label_group_new), new_group_path, :class => 'icon icon-add' %>
3 3 </div>
4 4
5 5 <h2><%= l(:label_group_plural) %></h2>
6 6
7 7 <% if @groups.any? %>
8 8 <table class="list groups">
9 9 <thead><tr>
10 10 <th><%=l(:label_group)%></th>
11 11 <th><%=l(:label_user_plural)%></th>
12 12 <th></th>
13 13 </tr></thead>
14 14 <tbody>
15 15 <% @groups.each do |group| %>
16 16 <tr class="<%= cycle 'odd', 'even' %>">
17 17 <td><%= link_to h(group), edit_group_path(group) %></td>
18 18 <td align="center"><%= group.users.size %></td>
19 <td class="buttons"><%= link_to l(:button_delete), group, :confirm => l(:text_are_you_sure), :method => :delete, :class => 'icon icon-del' %></td>
19 <td class="buttons"><%= delete_link group %></td>
20 20 </tr>
21 21 <% end %>
22 22 </table>
23 23 <% else %>
24 24 <p class="nodata"><%= l(:label_no_data) %></p>
25 25 <% end %>
@@ -1,42 +1,39
1 1 <div class="contextual">
2 2 <%= link_to l(:label_issue_status_new), new_issue_status_path, :class => 'icon icon-add' %>
3 <%= link_to(l(:label_update_issue_done_ratios), update_issue_done_ratio_issue_statuses_path, :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), update_issue_done_ratio_issue_statuses_path, :class => 'icon icon-multiple', :method => 'post', :data => {:confirm => l(:text_are_you_sure)}) if Issue.use_status_for_done_ratio? %>
4 4 </div>
5 5
6 6 <h2><%=l(:label_issue_status_plural)%></h2>
7 7
8 8 <table class="list">
9 9 <thead><tr>
10 10 <th><%=l(:field_status)%></th>
11 11 <% if Issue.use_status_for_done_ratio? %>
12 12 <th><%=l(:field_done_ratio)%></th>
13 13 <% end %>
14 14 <th><%=l(:field_is_default)%></th>
15 15 <th><%=l(:field_is_closed)%></th>
16 16 <th><%=l(:button_sort)%></th>
17 17 <th></th>
18 18 </tr></thead>
19 19 <tbody>
20 20 <% for status in @issue_statuses %>
21 21 <tr class="<%= cycle("odd", "even") %>">
22 22 <td><%= link_to h(status.name), edit_issue_status_path(status) %></td>
23 23 <% if Issue.use_status_for_done_ratio? %>
24 24 <td align="center"><%= h status.default_done_ratio %></td>
25 25 <% end %>
26 26 <td align="center"><%= checked_image status.is_default? %></td>
27 27 <td align="center"><%= checked_image status.is_closed? %></td>
28 28 <td align="center" style="width:15%;"><%= reorder_links('issue_status', {:action => 'update', :id => status}, :put) %></td>
29 29 <td class="buttons">
30 <%= link_to(l(:button_delete), issue_status_path(status),
31 :method => :delete,
32 :confirm => l(:text_are_you_sure),
33 :class => 'icon icon-del') %>
30 <%= delete_link issue_status_path(status) %>
34 31 </td>
35 32 </tr>
36 33 <% end %>
37 34 </tbody>
38 35 </table>
39 36
40 37 <p class="pagination"><%= pagination_links_full @issue_status_pages %></p>
41 38
42 39 <% html_title(l(:label_issue_status_plural)) -%>
@@ -1,7 +1,7
1 1 <div class="contextual">
2 2 <%= link_to_if_authorized(l(:button_update), {:controller => 'issues', :action => 'edit', :id => @issue }, :onclick => 'showAndScrollTo("update", "notes"); return false;', :class => 'icon icon-edit', :accesskey => accesskey(:edit)) %>
3 3 <%= link_to l(:button_log_time), new_issue_time_entry_path(@issue), :class => 'icon icon-time-add' if User.current.allowed_to?(:log_time, @project) %>
4 4 <%= watcher_tag(@issue, User.current) %>
5 5 <%= link_to_if_authorized l(:button_copy), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue}, :class => 'icon icon-copy' %>
6 <%= link_to l(:button_delete), issue_path(@issue), :confirm => issues_destroy_confirmation_message(@issue), :method => :delete, :class => 'icon icon-del' if User.current.allowed_to?(:delete_issues, @project) %>
6 <%= link_to l(:button_delete), issue_path(@issue), :data => {:confirm => issues_destroy_confirmation_message(@issue)}, :method => :delete, :class => 'icon icon-del' if User.current.allowed_to?(:delete_issues, @project) %>
7 7 </div>
@@ -1,43 +1,43
1 1 <div class="contextual">
2 2 <% if User.current.allowed_to?(:manage_issue_relations, @project) %>
3 3 <%= toggle_link l(:button_add), 'new-relation-form', {:focus => 'relation_issue_to_id'} %>
4 4 <% end %>
5 5 </div>
6 6
7 7 <p><strong><%=l(:label_related_issues)%></strong></p>
8 8
9 9 <% if @relations.present? %>
10 10 <form>
11 11 <table class="list issues">
12 12 <% @relations.each do |relation| %>
13 13 <tr class="issue hascontextmenu" id="relation-<%= relation.id %>">
14 14 <td class="checkbox"><%= check_box_tag("ids[]", relation.other_issue(@issue).id, false, :id => nil) %></td>
15 15 <td class="subject"><%= l(relation.label_for(@issue)) %> <%= "(#{l('datetime.distance_in_words.x_days', :count => relation.delay)})" if relation.delay && relation.delay != 0 %>
16 16 <%= h(relation.other_issue(@issue).project) + ' - ' if Setting.cross_project_issue_relations? %>
17 17 <%= link_to_issue(relation.other_issue(@issue), :truncate => 60) %>
18 18 </td>
19 19 <td class="status"><%=h relation.other_issue(@issue).status.name %></td>
20 20 <td class="start_date"><%= format_date(relation.other_issue(@issue).start_date) %></td>
21 21 <td class="due_date"><%= format_date(relation.other_issue(@issue).due_date) %></td>
22 22 <td class="buttons"><%= link_to_remote(
23 23 image_tag('link_break.png'),
24 24 { :url => {:controller => 'issue_relations', :action => 'destroy', :id => relation},
25 25 :method => :delete,
26 :confirm => l(:text_are_you_sure) },
26 :data => {:confirm => l(:text_are_you_sure)} },
27 27 :title => l(:label_relation_delete)
28 28 ) if authorize_for('issue_relations', 'destroy') %></td>
29 29 </tr>
30 30 <% end %>
31 31 </table>
32 32 </form>
33 33 <% end %>
34 34
35 35 <%= form_for @relation, {
36 36 :as => :relation, :remote => true,
37 37 :url => {:controller => 'issue_relations', :action => 'create', :issue_id => @issue},
38 38 :method => :post,
39 39 :complete => "Form.Element.focus('relation_issue_to_id');",
40 40 :html => {:id => 'new-relation-form', :style => (@relation ? '' : 'display: none;')}
41 41 } do |f| %>
42 42 <%= render :partial => 'issue_relations/form', :locals => {:f => f}%>
43 43 <% end %>
@@ -1,105 +1,104
1 1 <div class="contextual">
2 2 <% if !@query.new_record? && @query.editable_by?(User.current) %>
3 3 <%= link_to l(:button_edit), edit_query_path(@query), :class => 'icon icon-edit' %>
4 <%= link_to l(:button_delete), query_path(@query), :confirm => l(:text_are_you_sure),
5 :method => :delete, :class => 'icon icon-del' %>
4 <%= delete_link query_path(@query) %>
6 5 <% end %>
7 6 </div>
8 7
9 8 <h2><%= @query.new_record? ? l(:label_issue_plural) : h(@query.name) %></h2>
10 9 <% html_title(@query.new_record? ? l(:label_issue_plural) : @query.name) %>
11 10
12 11 <%= form_tag({ :controller => 'issues', :action => 'index', :project_id => @project },
13 12 :method => :get, :id => 'query_form') do %>
14 13 <%= hidden_field_tag 'set_filter', '1' %>
15 14 <div id="query_form_content" class="hide-when-print">
16 15 <fieldset id="filters" class="collapsible <%= @query.new_record? ? "" : "collapsed" %>">
17 16 <legend onclick="toggleFieldset(this);"><%= l(:label_filter_plural) %></legend>
18 17 <div style="<%= @query.new_record? ? "" : "display: none;" %>">
19 18 <%= render :partial => 'queries/filters', :locals => {:query => @query} %>
20 19 </div>
21 20 </fieldset>
22 21 <fieldset class="collapsible collapsed">
23 22 <legend onclick="toggleFieldset(this);"><%= l(:label_options) %></legend>
24 23 <div style="display: none;">
25 24 <table>
26 25 <tr>
27 26 <td><%= l(:field_column_names) %></td>
28 27 <td><%= render :partial => 'queries/columns', :locals => {:query => @query} %></td>
29 28 </tr>
30 29 <tr>
31 30 <td><label for='group_by'><%= l(:field_group_by) %></label></td>
32 31 <td><%= select_tag('group_by',
33 32 options_for_select(
34 33 [[]] + @query.groupable_columns.collect {|c| [c.caption, c.name.to_s]},
35 34 @query.group_by)
36 35 ) %></td>
37 36 </tr>
38 37 </table>
39 38 </div>
40 39 </fieldset>
41 40 </div>
42 41 <p class="buttons hide-when-print">
43 42
44 43 <%= link_to_function l(:button_apply), 'submit_query_form("query_form")', :class => 'icon icon-checked' %>
45 44 <%= link_to l(:button_clear), { :set_filter => 1, :project_id => @project }, :class => 'icon icon-reload' %>
46 45 <% if @query.new_record? && User.current.allowed_to?(:save_queries, @project, :global => true) %>
47 46 <%= link_to_function l(:button_save),
48 47 "$('query_form').action='#{ @project ? new_project_query_path(@project) : new_query_path }'; submit_query_form('query_form')",
49 48 :class => 'icon icon-save' %>
50 49 <% end %>
51 50 </p>
52 51 <% end %>
53 52
54 53 <%= error_messages_for 'query' %>
55 54 <% if @query.valid? %>
56 55 <% if @issues.empty? %>
57 56 <p class="nodata"><%= l(:label_no_data) %></p>
58 57 <% else %>
59 58 <%= render :partial => 'issues/list', :locals => {:issues => @issues, :query => @query} %>
60 59 <p class="pagination"><%= pagination_links_full @issue_pages, @issue_count %></p>
61 60 <% end %>
62 61
63 62 <% other_formats_links do |f| %>
64 63 <%= f.link_to 'Atom', :url => params.merge(:key => User.current.rss_key) %>
65 64 <%= f.link_to 'CSV', :url => params, :onclick => "showModal('csv-export-options', '330px'); return false;" %>
66 65 <%= f.link_to 'PDF', :url => params %>
67 66 <% end %>
68 67
69 68 <div id="csv-export-options" style="display:none;">
70 69 <h3 class="title"><%= l(:label_export_options, :export_format => 'CSV') %></h3>
71 70 <%= form_tag(params.merge({:format => 'csv',:page=>nil}), :method => :get, :id => 'csv-export-form') do %>
72 71 <p>
73 72 <label><%= radio_button_tag 'columns', '', true %> <%= l(:description_selected_columns) %></label><br />
74 73 <label><%= radio_button_tag 'columns', 'all' %> <%= l(:description_all_columns) %></label>
75 74 </p>
76 75 <p>
77 76 <label><%= check_box_tag 'description', '1' %> <%= l(:field_description) %></label>
78 77 </p>
79 78 <p class="buttons">
80 79 <%= submit_tag l(:button_export), :name => nil, :onclick => "hideModal(this);" %>
81 80 <%= submit_tag l(:button_cancel), :name => nil, :onclick => "hideModal(this);", :type => 'button' %>
82 81 </p>
83 82 <% end %>
84 83 </div>
85 84
86 85 <% end %>
87 86 <%= call_hook(:view_issues_index_bottom, { :issues => @issues, :project => @project, :query => @query }) %>
88 87
89 88 <% content_for :sidebar do %>
90 89 <%= render :partial => 'issues/sidebar' %>
91 90 <% end %>
92 91
93 92 <% content_for :header_tags do %>
94 93 <%= auto_discovery_link_tag(:atom,
95 94 {:query_id => @query, :format => 'atom',
96 95 :page => nil, :key => User.current.rss_key},
97 96 :title => l(:label_issue_plural)) %>
98 97 <%= auto_discovery_link_tag(:atom,
99 98 {:controller => 'journals', :action => 'index',
100 99 :query_id => @query, :format => 'atom',
101 100 :page => nil, :key => User.current.rss_key},
102 101 :title => l(:label_changes_details)) %>
103 102 <% end %>
104 103
105 104 <%= context_menu issues_context_menu_path %>
@@ -1,94 +1,94
1 1 <%= breadcrumb link_to(l(:label_board_plural), project_boards_path(@project)),
2 2 link_to(h(@board.name), project_board_path(@project, @board)) %>
3 3
4 4 <div class="contextual">
5 5 <%= watcher_tag(@topic, User.current) %>
6 6 <%= link_to_remote_if_authorized(
7 7 l(:button_quote),
8 8 { :url => {:action => 'quote', :id => @topic} },
9 9 :class => 'icon icon-comment'
10 10 ) unless @topic.locked? %>
11 11 <%= link_to(
12 12 l(:button_edit),
13 13 {:action => 'edit', :id => @topic},
14 14 :class => 'icon icon-edit'
15 15 ) if @message.editable_by?(User.current) %>
16 16 <%= link_to(
17 17 l(:button_delete),
18 18 {:action => 'destroy', :id => @topic},
19 19 :method => :post,
20 :confirm => l(:text_are_you_sure),
20 :data => {:confirm => l(:text_are_you_sure)},
21 21 :class => 'icon icon-del'
22 22 ) if @message.destroyable_by?(User.current) %>
23 23 </div>
24 24
25 25 <h2><%= avatar(@topic.author, :size => "24") %><%=h @topic.subject %></h2>
26 26
27 27 <div class="message">
28 28 <p><span class="author"><%= authoring @topic.created_on, @topic.author %></span></p>
29 29 <div class="wiki">
30 30 <%= textilizable(@topic, :content) %>
31 31 </div>
32 32 <%= link_to_attachments @topic, :author => false %>
33 33 </div>
34 34 <br />
35 35
36 36 <% unless @replies.empty? %>
37 37 <h3 class="comments"><%= l(:label_reply_plural) %> (<%= @reply_count %>)</h3>
38 38 <% @replies.each do |message| %>
39 39 <div class="message reply" id="<%= "message-#{message.id}" %>">
40 40 <div class="contextual">
41 41 <%= link_to_remote_if_authorized(
42 42 image_tag('comment.png'),
43 43 { :url => {:action => 'quote', :id => message} },
44 44 :title => l(:button_quote)
45 45 ) unless @topic.locked? %>
46 46 <%= link_to(
47 47 image_tag('edit.png'),
48 48 {:action => 'edit', :id => message},
49 49 :title => l(:button_edit)
50 50 ) if message.editable_by?(User.current) %>
51 51 <%= link_to(
52 52 image_tag('delete.png'),
53 53 {:action => 'destroy', :id => message},
54 54 :method => :post,
55 :confirm => l(:text_are_you_sure),
55 :data => {:confirm => l(:text_are_you_sure)},
56 56 :title => l(:button_delete)
57 57 ) if message.destroyable_by?(User.current) %>
58 58 </div>
59 59 <h4>
60 60 <%= avatar(message.author, :size => "24") %>
61 61 <%= link_to h(message.subject), { :controller => 'messages', :action => 'show', :board_id => @board, :id => @topic, :r => message, :anchor => "message-#{message.id}" } %>
62 62 -
63 63 <%= authoring message.created_on, message.author %>
64 64 </h4>
65 65 <div class="wiki"><%= textilizable message, :content, :attachments => message.attachments %></div>
66 66 <%= link_to_attachments message, :author => false %>
67 67 </div>
68 68 <% end %>
69 69 <p class="pagination"><%= pagination_links_full @reply_pages, @reply_count, :per_page_links => false %></p>
70 70 <% end %>
71 71
72 72 <% if !@topic.locked? && authorize_for('messages', 'reply') %>
73 73 <p><%= toggle_link l(:button_reply), "reply", :focus => 'message_content' %></p>
74 74 <div id="reply" style="display:none;">
75 75 <%= form_for @reply, :as => :reply, :url => {:action => 'reply', :id => @topic}, :html => {:multipart => true, :id => 'message-form'} do |f| %>
76 76 <%= render :partial => 'form', :locals => {:f => f, :replying => true} %>
77 77 <%= submit_tag l(:button_submit) %>
78 78 <%= link_to_remote l(:label_preview),
79 79 { :url => { :controller => 'messages', :action => 'preview', :board_id => @board },
80 80 :method => 'post',
81 81 :update => 'preview',
82 82 :with => "Form.serialize('message-form')",
83 83 :complete => "Element.scrollTo('preview')"
84 84 }, :accesskey => accesskey(:preview) %>
85 85 <% end %>
86 86 <div id="preview" class="wiki"></div>
87 87 </div>
88 88 <% end %>
89 89
90 90 <% content_for :header_tags do %>
91 91 <%= stylesheet_link_tag 'scm' %>
92 92 <% end %>
93 93
94 94 <% html_title @topic.subject %>
@@ -1,52 +1,52
1 1 <h3><%=l(:label_spent_time)%> (<%= l(:label_last_n_days, 7) %>)</h3>
2 2 <%
3 3 entries = TimeEntry.find(:all,
4 4 :conditions => ["#{TimeEntry.table_name}.user_id = ? AND #{TimeEntry.table_name}.spent_on BETWEEN ? AND ?", @user.id, Date.today - 6, Date.today],
5 5 :include => [:activity, :project, {:issue => [:tracker, :status]}],
6 6 :order => "#{TimeEntry.table_name}.spent_on DESC, #{Project.table_name}.name ASC, #{Tracker.table_name}.position ASC, #{Issue.table_name}.id ASC")
7 7 entries_by_day = entries.group_by(&:spent_on)
8 8 %>
9 9
10 10 <div class="total-hours">
11 11 <p><%= l(:label_total) %>: <%= html_hours("%.2f" % entries.sum(&:hours).to_f) %></p>
12 12 </div>
13 13
14 14 <% if entries.any? %>
15 15 <table class="list time-entries">
16 16 <thead><tr>
17 17 <th><%= l(:label_activity) %></th>
18 18 <th><%= l(:label_project) %></th>
19 19 <th><%= l(:field_comments) %></th>
20 20 <th><%= l(:field_hours) %></th>
21 21 <th></th>
22 22 </tr></thead>
23 23 <tbody>
24 24 <% entries_by_day.keys.sort.reverse.each do |day| %>
25 25 <tr class="odd">
26 26 <td><strong><%= day == Date.today ? l(:label_today).titleize : format_date(day) %></strong></td>
27 27 <td colspan="2"></td>
28 28 <td class="hours"><em><%= html_hours("%.2f" % entries_by_day[day].sum(&:hours).to_f) %></em></td>
29 29 <td></td>
30 30 </tr>
31 31 <% entries_by_day[day].each do |entry| -%>
32 32 <tr class="time-entry" style="border-bottom: 1px solid #f5f5f5;">
33 33 <td class="activity"><%=h entry.activity %></td>
34 34 <td class="subject"><%=h entry.project %> <%= h(' - ') + link_to_issue(entry.issue, :truncate => 50) if entry.issue %></td>
35 35 <td class="comments"><%=h entry.comments %></td>
36 36 <td class="hours"><%= html_hours("%.2f" % entry.hours) %></td>
37 37 <td align="center">
38 38 <% if entry.editable_by?(@user) -%>
39 39 <%= link_to image_tag('edit.png'), {:controller => 'timelog', :action => 'edit', :id => entry},
40 40 :title => l(:button_edit) %>
41 41 <%= link_to image_tag('delete.png'), {:controller => 'timelog', :action => 'destroy', :id => entry},
42 :confirm => l(:text_are_you_sure),
42 :data => {:confirm => l(:text_are_you_sure)},
43 43 :method => :delete,
44 44 :title => l(:button_delete) %>
45 45 <% end -%>
46 46 </td>
47 47 </tr>
48 48 <% end -%>
49 49 <% end -%>
50 50 </tbody>
51 51 </table>
52 52 <% end %>
@@ -1,71 +1,67
1 1 <div class="contextual">
2 2 <%= watcher_tag(@news, User.current) %>
3 3 <%= link_to(l(:button_edit),
4 4 edit_news_path(@news),
5 5 :class => 'icon icon-edit',
6 6 :accesskey => accesskey(:edit),
7 7 :onclick => 'Element.show("edit-news"); return false;') if User.current.allowed_to?(:manage_news, @project) %>
8 <%= link_to(l(:button_delete),
9 news_path(@news),
10 :confirm => l(:text_are_you_sure),
11 :method => :delete,
12 :class => 'icon icon-del') if User.current.allowed_to?(:manage_news, @project) %>
8 <%= delete_link news_path(@news) if User.current.allowed_to?(:manage_news, @project) %>
13 9 </div>
14 10
15 11 <h2><%= avatar(@news.author, :size => "24") %><%=h @news.title %></h2>
16 12
17 13 <% if authorize_for('news', 'edit') %>
18 14 <div id="edit-news" style="display:none;">
19 15 <%= labelled_form_for :news, @news, :url => news_path(@news),
20 16 :html => { :id => 'news-form', :multipart => true, :method => :put } do |f| %>
21 17 <%= render :partial => 'form', :locals => { :f => f } %>
22 18 <%= submit_tag l(:button_save) %>
23 19 <%= link_to_remote l(:label_preview),
24 20 { :url => preview_news_path(:project_id => @project),
25 21 :method => 'get',
26 22 :update => 'preview',
27 23 :with => "Form.serialize('news-form')"
28 24 }, :accesskey => accesskey(:preview) %> |
29 25 <%= link_to l(:button_cancel), "#", :onclick => 'Element.hide("edit-news"); return false;' %>
30 26 <% end %>
31 27 <div id="preview" class="wiki"></div>
32 28 </div>
33 29 <% end %>
34 30
35 31 <p><% unless @news.summary.blank? %><em><%=h @news.summary %></em><br /><% end %>
36 32 <span class="author"><%= authoring @news.created_on, @news.author %></span></p>
37 33 <div class="wiki">
38 34 <%= textilizable(@news, :description) %>
39 35 </div>
40 36 <%= link_to_attachments @news %>
41 37 <br />
42 38
43 39 <div id="comments" style="margin-bottom:16px;">
44 40 <h3 class="comments"><%= l(:label_comment_plural) %></h3>
45 41 <% @comments.each do |comment| %>
46 42 <% next if comment.new_record? %>
47 43 <div class="contextual">
48 44 <%= link_to_if_authorized image_tag('delete.png'), {:controller => 'comments', :action => 'destroy', :id => @news, :comment_id => comment},
49 :confirm => l(:text_are_you_sure), :method => :delete, :title => l(:button_delete) %>
45 :data => {:confirm => l(:text_are_you_sure)}, :method => :delete, :title => l(:button_delete) %>
50 46 </div>
51 47 <h4><%= avatar(comment.author, :size => "24") %><%= authoring comment.created_on, comment.author %></h4>
52 48 <%= textilizable(comment.comments) %>
53 49 <% end if @comments.any? %>
54 50 </div>
55 51
56 52 <% if @news.commentable? %>
57 53 <p><%= toggle_link l(:label_comment_add), "add_comment_form", :focus => "comment_comments" %></p>
58 54 <%= form_tag({:controller => 'comments', :action => 'create', :id => @news}, :id => "add_comment_form", :style => "display:none;") do %>
59 55 <div class="box">
60 56 <%= text_area 'comment', 'comments', :cols => 80, :rows => 15, :class => 'wiki-edit' %>
61 57 <%= wikitoolbar_for 'comment_comments' %>
62 58 </div>
63 59 <p><%= submit_tag l(:button_add) %></p>
64 60 <% end %>
65 61 <% end %>
66 62
67 63 <% html_title @news.title -%>
68 64
69 65 <% content_for :header_tags do %>
70 66 <%= stylesheet_link_tag 'scm' %>
71 67 <% end %>
@@ -1,42 +1,42
1 1 <%= form_tag(project_enumerations_path(@project), :method => :put, :class => "tabular") do %>
2 2
3 3 <table class="list">
4 4 <thead><tr>
5 5 <th><%= l(:field_name) %></th>
6 6 <th><%= l(:enumeration_system_activity) %></th>
7 7 <% TimeEntryActivity.new.available_custom_fields.each do |value| %>
8 8 <th><%= h value.name %></th>
9 9 <% end %>
10 10 <th style="width:15%;"><%= l(:field_active) %></th>
11 11 </tr></thead>
12 12
13 13 <% @project.activities(true).each do |enumeration| %>
14 14 <%= fields_for "enumerations[#{enumeration.id}]", enumeration do |ff| %>
15 15 <tr class="<%= cycle('odd', 'even') %>">
16 16 <td>
17 17 <%= ff.hidden_field :parent_id, :value => enumeration.id unless enumeration.project %>
18 18 <%= h(enumeration) %>
19 19 </td>
20 20 <td align="center" style="width:15%;"><%= checked_image !enumeration.project %></td>
21 21 <% enumeration.custom_field_values.each do |value| %>
22 22 <td align="center">
23 23 <%= custom_field_tag "enumerations[#{enumeration.id}]", value %>
24 24 </td>
25 25 <% end %>
26 26 <td align="center" style="width:15%;">
27 27 <%= ff.check_box :active %>
28 28 </td>
29 29 </tr>
30 30 <% end %>
31 31 <% end %>
32 32 </table>
33 33
34 34 <div class="contextual">
35 35 <%= link_to(l(:button_reset), project_enumerations_path(@project),
36 36 :method => :delete,
37 :confirm => l(:text_are_you_sure),
37 :data => {:confirm => l(:text_are_you_sure)},
38 38 :class => 'icon icon-del') %>
39 39 </div>
40 40
41 41 <%= submit_tag l(:button_save) %>
42 42 <% end %>
@@ -1,36 +1,36
1 1 <% if @project.boards.any? %>
2 2 <table class="list">
3 3 <thead><tr>
4 4 <th><%= l(:label_board) %></th>
5 5 <th><%= l(:field_description) %></th>
6 6 <th></th>
7 7 <th></th>
8 8 </tr></thead>
9 9 <tbody>
10 10 <% @project.boards.each do |board|
11 11 next if board.new_record? %>
12 12 <tr class="<%= cycle 'odd', 'even' %>">
13 13 <td><%=h board.name %></td>
14 14 <td><%=h board.description %></td>
15 15 <td align="center">
16 16 <% if authorize_for("boards", "edit") %>
17 17 <%= reorder_links('board', {:controller => 'boards', :action => 'update', :project_id => @project, :id => board}, :put) %>
18 18 <% end %>
19 19 </td>
20 20 <td class="buttons">
21 21 <% if User.current.allowed_to?(:manage_boards, @project) %>
22 22 <%= link_to l(:button_edit), edit_project_board_path(@project, board), :class => 'icon icon-edit' %>
23 <%= link_to l(:button_delete), project_board_path(@project, board), :confirm => l(:text_are_you_sure), :method => :delete, :class => 'icon icon-del' %>
23 <%= delete_link project_board_path(@project, board) %>
24 24 <% end %>
25 25 </td>
26 26 </tr>
27 27 <% end %>
28 28 </tbody>
29 29 </table>
30 30 <% else %>
31 31 <p class="nodata"><%= l(:label_no_data) %></p>
32 32 <% end %>
33 33
34 34 <% if User.current.allowed_to?(:manage_boards, @project) %>
35 35 <p><%= link_to l(:label_board_new), new_project_board_path(@project), :class => 'icon icon-add' %></p>
36 36 <% end %>
@@ -1,29 +1,29
1 1 <% if @project.issue_categories.any? %>
2 2 <table class="list">
3 3 <thead><tr>
4 4 <th><%= l(:label_issue_category) %></th>
5 5 <th><%= l(:field_assigned_to) %></th>
6 6 <th></th>
7 7 </tr></thead>
8 8 <tbody>
9 9 <% for category in @project.issue_categories %>
10 10 <% unless category.new_record? %>
11 11 <tr class="<%= cycle 'odd', 'even' %>">
12 12 <td><%=h(category.name) %></td>
13 13 <td><%=h(category.assigned_to.name) if category.assigned_to %></td>
14 14 <td class="buttons">
15 15 <% if User.current.allowed_to?(:manage_categories, @project) %>
16 16 <%= link_to l(:button_edit), edit_issue_category_path(category), :class => 'icon icon-edit' %>
17 <%= link_to l(:button_delete), issue_category_path(category), :confirm => l(:text_are_you_sure), :method => :delete, :class => 'icon icon-del' %>
17 <%= delete_link issue_category_path(category) %>
18 18 <% end %>
19 19 </td>
20 20 </tr>
21 21 <% end %>
22 22 <% end %>
23 23 </tbody>
24 24 </table>
25 25 <% else %>
26 26 <p class="nodata"><%= l(:label_no_data) %></p>
27 27 <% end %>
28 28
29 29 <p><%= link_to l(:label_issue_category_new), new_project_issue_category_path(@project), :class => 'icon icon-add' if User.current.allowed_to?(:manage_categories, @project) %></p>
@@ -1,94 +1,94
1 1 <%= error_messages_for 'member' %>
2 2 <% roles = Role.find_all_givable
3 3 members = @project.member_principals.find(:all, :include => [:roles, :principal]).sort %>
4 4
5 5 <div class="splitcontentleft">
6 6 <% if members.any? %>
7 7 <table class="list members">
8 8 <thead><tr>
9 9 <th><%= l(:label_user) %> / <%= l(:label_group) %></th>
10 10 <th><%= l(:label_role_plural) %></th>
11 11 <th style="width:15%"></th>
12 12 <%= call_hook(:view_projects_settings_members_table_header, :project => @project) %>
13 13 </tr></thead>
14 14 <tbody>
15 15 <% members.each do |member| %>
16 16 <% next if member.new_record? %>
17 17 <tr id="member-<%= member.id %>" class="<%= cycle 'odd', 'even' %> member">
18 18 <td class="<%= member.principal.class.name.downcase %>"><%= link_to_user member.principal %></td>
19 19 <td class="roles">
20 20 <span id="member-<%= member.id %>-roles"><%=h member.roles.sort.collect(&:to_s).join(', ') %></span>
21 21 <%= form_for(member, {:as => :membership, :remote => true, :url => membership_path(member),
22 22 :method => :put,
23 23 :html => { :id => "member-#{member.id}-roles-form", :class => 'hol' }}
24 24 ) do |f| %>
25 25 <p><% roles.each do |role| %>
26 26 <label><%= check_box_tag 'membership[role_ids][]', role.id, member.roles.include?(role),
27 27 :disabled => member.member_roles.detect {|mr| mr.role_id == role.id && !mr.inherited_from.nil?} %> <%=h role %></label><br />
28 28 <% end %></p>
29 29 <%= hidden_field_tag 'membership[role_ids][]', '' %>
30 30 <p><%= submit_tag l(:button_change), :class => "small" %>
31 31 <%= link_to_function l(:button_cancel),
32 32 "$('member-#{member.id}-roles').show(); $('member-#{member.id}-roles-form').hide(); return false;"
33 33 %></p>
34 34 <% end %>
35 35 </td>
36 36 <td class="buttons">
37 37 <%= link_to_function l(:button_edit),
38 38 "$('member-#{member.id}-roles').hide(); $('member-#{member.id}-roles-form').show(); return false;",
39 39 :class => 'icon icon-edit' %>
40 40 <%= link_to_remote(
41 41 l(:button_delete),
42 42 { :url => membership_path(member),
43 43 :method => :delete,
44 :confirm => (!User.current.admin? && member.include?(User.current) ? l(:text_own_membership_delete_confirmation) : nil) },
44 :data => {:confirm => (!User.current.admin? && member.include?(User.current) ? l(:text_own_membership_delete_confirmation) : nil)} },
45 45 :title => l(:button_delete),
46 46 :class => 'icon icon-del'
47 47 ) if member.deletable? %>
48 48 </td>
49 49 <%= call_hook(:view_projects_settings_members_table_row, { :project => @project, :member => member}) %>
50 50 </tr>
51 51 <% end; reset_cycle %>
52 52 </tbody>
53 53 </table>
54 54 <% else %>
55 55 <p class="nodata"><%= l(:label_no_data) %></p>
56 56 <% end %>
57 57 </div>
58 58
59 59 <% principals = Principal.active.not_member_of(@project).all(:limit => 100, :order => 'type, login, lastname ASC') %>
60 60
61 61 <div class="splitcontentright">
62 62 <% if roles.any? && principals.any? %>
63 63 <%= form_for(@member, {:as => :membership, :remote => true,
64 64 :url => project_memberships_path(@project), :method => :post,
65 65 :loading => '$(\'member-add-submit\').disable();',
66 66 :complete => 'if($(\'member-add-submit\')) $(\'member-add-submit\').enable();'
67 67 } ) do |f| %>
68 68 <fieldset><legend><%=l(:label_member_new)%></legend>
69 69
70 70 <p><%= label_tag "principal_search", l(:label_principal_search) %><%= text_field_tag 'principal_search', nil %></p>
71 71 <%= observe_field(:principal_search,
72 72 :frequency => 0.5,
73 73 :update => :principals,
74 74 :url => autocomplete_project_memberships_path(@project),
75 75 :method => :get,
76 76 :before => '$("principal_search").addClassName("ajax-loading")',
77 77 :complete => '$("principal_search").removeClassName("ajax-loading")',
78 78 :with => 'q')
79 79 %>
80 80
81 81 <div id="principals">
82 82 <%= principals_check_box_tags 'membership[user_ids][]', principals %>
83 83 </div>
84 84
85 85 <p><%= l(:label_role_plural) %>:
86 86 <% roles.each do |role| %>
87 87 <label><%= check_box_tag 'membership[role_ids][]', role.id %> <%=h role %></label>
88 88 <% end %></p>
89 89
90 90 <p><%= submit_tag l(:button_add), :id => 'member-add-submit' %></p>
91 91 </fieldset>
92 92 <% end %>
93 93 <% end %>
94 94 </div>
@@ -1,41 +1,38
1 1 <% if @project.repositories.any? %>
2 2 <table class="list">
3 3 <thead>
4 4 <tr>
5 5 <th><%= l(:label_scm) %></th>
6 6 <th><%= l(:field_identifier) %></th>
7 7 <th><%= l(:field_repository_is_default) %></th>
8 8 <th><%= l(:label_repository) %></th>
9 9 <th></th>
10 10 </tr>
11 11 </thead>
12 12 <tbody>
13 13 <% @project.repositories.sort.each do |repository| %>
14 14 <tr class="<%= cycle 'odd', 'even' %>">
15 15 <td><%=h repository.scm_name %></td>
16 16 <td><%=h repository.identifier %></td>
17 17 <td align="center"><%= checked_image repository.is_default? %></td>
18 18 <td><%=h repository.url %></td>
19 19 <td class="buttons">
20 20 <% if User.current.allowed_to?(:manage_repository, @project) %>
21 21 <%= link_to(l(:label_user_plural), committers_repository_path(repository),
22 22 :class => 'icon icon-user') %>
23 23 <%= link_to(l(:button_edit), edit_repository_path(repository),
24 24 :class => 'icon icon-edit') %>
25 <%= link_to(l(:button_delete), repository_path(repository),
26 :confirm => l(:text_are_you_sure),
27 :method => :delete,
28 :class => 'icon icon-del') %>
25 <%= delete_link repository_path(repository) %>
29 26 <% end %>
30 27 </td>
31 28 </tr>
32 29 <% end %>
33 30 </tbody>
34 31 </table>
35 32 <% else %>
36 33 <p class="nodata"><%= l(:label_no_data) %></p>
37 34 <% end %>
38 35
39 36 <% if User.current.allowed_to?(:manage_repository, @project) %>
40 37 <p><%= link_to l(:label_repository_new), new_project_repository_path(@project), :class => 'icon icon-add' %></p>
41 38 <% end %>
@@ -1,41 +1,41
1 1 <% if @project.shared_versions.any? %>
2 2 <table class="list versions">
3 3 <thead><tr>
4 4 <th><%= l(:label_version) %></th>
5 5 <th><%= l(:field_effective_date) %></th>
6 6 <th><%= l(:field_description) %></th>
7 7 <th><%= l(:field_status) %></th>
8 8 <th><%= l(:field_sharing) %></th>
9 9 <th><%= l(:label_wiki_page) %></th>
10 10 <th style="width:15%"></th>
11 11 </tr></thead>
12 12 <tbody>
13 13 <% for version in @project.shared_versions.sort %>
14 14 <tr class="version <%= cycle 'odd', 'even' %> <%=h version.status %> <%= 'shared' if version.project != @project %>">
15 15 <td class="name"><%= link_to_version version %></td>
16 16 <td class="date"><%= format_date(version.effective_date) %></td>
17 17 <td class="description"><%=h version.description %></td>
18 18 <td class="status"><%= l("version_status_#{version.status}") %></td>
19 19 <td class="sharing"><%=h format_version_sharing(version.sharing) %></td>
20 20 <td><%= link_to_if_authorized(h(version.wiki_page_title), {:controller => 'wiki', :action => 'show', :project_id => version.project, :id => Wiki.titleize(version.wiki_page_title)}) || h(version.wiki_page_title) unless version.wiki_page_title.blank? || version.project.wiki.nil? %></td>
21 21 <td class="buttons">
22 22 <% if version.project == @project && User.current.allowed_to?(:manage_versions, @project) %>
23 23 <%= link_to l(:button_edit), edit_version_path(version), :class => 'icon icon-edit' %>
24 <%= link_to l(:button_delete), version_path(version), :confirm => l(:text_are_you_sure), :method => :delete, :class => 'icon icon-del' %>
24 <%= delete_link version_path(version) %>
25 25 <% end %>
26 26 </td>
27 27 </tr>
28 28 <% end; reset_cycle %>
29 29 </tbody>
30 30 </table>
31 31 <% else %>
32 32 <p class="nodata"><%= l(:label_no_data) %></p>
33 33 <% end %>
34 34
35 35 <div class="contextual">
36 36 <% if @project.versions.any? %>
37 37 <%= link_to l(:label_close_versions), close_completed_project_versions_path(@project), :method => :put %>
38 38 <% end %>
39 39 </div>
40 40
41 41 <p><%= link_to l(:label_version_new), new_project_version_path(@project, :back_url => ''), :class => 'icon icon-add' if User.current.allowed_to?(:manage_versions, @project) %></p>
@@ -1,27 +1,27
1 1 <div class="contextual">
2 2 <%= link_to_if_authorized l(:label_query_new), new_project_query_path(:project_id => @project), :class => 'icon icon-add' %>
3 3 </div>
4 4
5 5 <h2><%= l(:label_query_plural) %></h2>
6 6
7 7 <% if @queries.empty? %>
8 8 <p><i><%=l(:label_no_data)%></i></p>
9 9 <% else %>
10 10 <table class="list">
11 11 <% @queries.each do |query| %>
12 12 <tr class="<%= cycle('odd', 'even') %>">
13 13 <td>
14 14 <%= link_to h(query.name), :controller => 'issues', :action => 'index', :project_id => @project, :query_id => query %>
15 15 </td>
16 16 <td align="right">
17 17 <small>
18 18 <% if query.editable_by?(User.current) %>
19 19 <%= link_to l(:button_edit), edit_query_path(query), :class => 'icon icon-edit' %>
20 <%= link_to l(:button_delete), query_path(query), :confirm => l(:text_are_you_sure), :method => :delete, :class => 'icon icon-del' %>
20 <%= delete_link query_path(query) %>
21 21 </small>
22 22 <% end %>
23 23 </td>
24 24 </tr>
25 25 <% end %>
26 26 </table>
27 27 <% end %>
@@ -1,37 +1,34
1 1 <div class="contextual">
2 2 <%= link_to l(:label_role_new), new_role_path, :class => 'icon icon-add' %>
3 3 </div>
4 4
5 5 <h2><%=l(:label_role_plural)%></h2>
6 6
7 7 <table class="list">
8 8 <thead><tr>
9 9 <th><%=l(:label_role)%></th>
10 10 <th><%=l(:button_sort)%></th>
11 11 <th></th>
12 12 </tr></thead>
13 13 <tbody>
14 14 <% for role in @roles %>
15 15 <tr class="<%= cycle("odd", "even") %>">
16 16 <td><%= content_tag(role.builtin? ? 'em' : 'span', link_to(h(role.name), edit_role_path(role))) %></td>
17 17 <td align="center" style="width:15%;">
18 18 <% unless role.builtin? %>
19 19 <%= reorder_links('role', {:action => 'update', :id => role}, :put) %>
20 20 <% end %>
21 21 </td>
22 22 <td class="buttons">
23 <%= link_to(l(:button_delete), role_path(role),
24 :method => :delete,
25 :confirm => l(:text_are_you_sure),
26 :class => 'icon icon-del') unless role.builtin? %>
23 <%= delete_link role_path(role) unless role.builtin? %>
27 24 </td>
28 25 </tr>
29 26 <% end %>
30 27 </tbody>
31 28 </table>
32 29
33 30 <p class="pagination"><%= pagination_links_full @role_pages %></p>
34 31
35 32 <p><%= link_to l(:label_permissions_report), :action => 'permissions' %></p>
36 33
37 34 <% html_title(l(:label_role_plural)) -%>
@@ -1,55 +1,55
1 1 <%= form_tag({}) do -%>
2 2 <%= hidden_field_tag 'back_url', url_for(params) %>
3 3 <div class="autoscroll">
4 4 <table class="list time-entries">
5 5 <thead>
6 6 <tr>
7 7 <th class="checkbox hide-when-print">
8 8 <%= link_to image_tag('toggle_check.png'),
9 9 {},
10 10 :onclick => 'toggleIssuesSelection(Element.up(this, "form")); return false;',
11 11 :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}" %>
12 12 </th>
13 13 <%= sort_header_tag('spent_on', :caption => l(:label_date), :default_order => 'desc') %>
14 14 <%= sort_header_tag('user', :caption => l(:label_member)) %>
15 15 <%= sort_header_tag('activity', :caption => l(:label_activity)) %>
16 16 <%= sort_header_tag('project', :caption => l(:label_project)) %>
17 17 <%= sort_header_tag('issue', :caption => l(:label_issue), :default_order => 'desc') %>
18 18 <th><%= l(:field_comments) %></th>
19 19 <%= sort_header_tag('hours', :caption => l(:field_hours)) %>
20 20 <th></th>
21 21 </tr>
22 22 </thead>
23 23 <tbody>
24 24 <% entries.each do |entry| -%>
25 25 <tr class="time-entry <%= cycle("odd", "even") %> hascontextmenu">
26 26 <td class="checkbox hide-when-print"><%= check_box_tag("ids[]", entry.id, false, :id => nil) %></td>
27 27 <td class="spent_on"><%= format_date(entry.spent_on) %></td>
28 28 <td class="user"><%= link_to_user(entry.user) %></td>
29 29 <td class="activity"><%=h entry.activity %></td>
30 30 <td class="project"><%= link_to_project(entry.project) %></td>
31 31 <td class="subject">
32 32 <% if entry.issue -%>
33 33 <%= entry.issue.visible? ? link_to_issue(entry.issue, :truncate => 50) : "##{entry.issue.id}" -%>
34 34 <% end -%>
35 35 </td>
36 36 <td class="comments"><%=h entry.comments %></td>
37 37 <td class="hours"><%= html_hours("%.2f" % entry.hours) %></td>
38 38 <td align="center">
39 39 <% if entry.editable_by?(User.current) -%>
40 40 <%= link_to image_tag('edit.png'), {:controller => 'timelog', :action => 'edit', :id => entry, :project_id => nil},
41 41 :title => l(:button_edit) %>
42 42 <%= link_to image_tag('delete.png'), {:controller => 'timelog', :action => 'destroy', :id => entry, :project_id => nil},
43 :confirm => l(:text_are_you_sure),
43 :data => {:confirm => l(:text_are_you_sure)},
44 44 :method => :delete,
45 45 :title => l(:button_delete) %>
46 46 <% end -%>
47 47 </td>
48 48 </tr>
49 49 <% end -%>
50 50 </tbody>
51 51 </table>
52 52 </div>
53 53 <% end -%>
54 54
55 55 <%= context_menu time_entries_context_menu_path %>
@@ -1,33 +1,30
1 1 <div class="contextual">
2 2 <%= link_to l(:label_tracker_new), new_tracker_path, :class => 'icon icon-add' %>
3 3 </div>
4 4
5 5 <h2><%=l(:label_tracker_plural)%></h2>
6 6
7 7 <table class="list">
8 8 <thead><tr>
9 9 <th><%=l(:label_tracker)%></th>
10 10 <th></th>
11 11 <th><%=l(:button_sort)%></th>
12 12 <th></th>
13 13 </tr></thead>
14 14 <tbody>
15 15 <% for tracker in @trackers %>
16 16 <tr class="<%= cycle("odd", "even") %>">
17 17 <td><%= link_to h(tracker.name), edit_tracker_path(tracker) %></td>
18 18 <td align="center"><% unless tracker.workflows.count > 0 %><span class="icon icon-warning"><%= l(:text_tracker_no_workflow) %> (<%= link_to l(:button_edit), {:controller => 'workflows', :action => 'edit', :tracker_id => tracker} %>)</span><% end %></td>
19 19 <td align="center" style="width:15%;"><%= reorder_links('tracker', {:action => 'update', :id => tracker}, :put) %></td>
20 20 <td class="buttons">
21 <%= link_to(l(:button_delete), tracker_path(tracker),
22 :method => :delete,
23 :confirm => l(:text_are_you_sure),
24 :class => 'icon icon-del') %>
21 <%= delete_link tracker_path(tracker) %>
25 22 </td>
26 23 </tr>
27 24 <% end %>
28 25 </tbody>
29 26 </table>
30 27
31 28 <p class="pagination"><%= pagination_links_full @tracker_pages %></p>
32 29
33 30 <% html_title(l(:label_tracker_plural)) -%>
@@ -1,11 +1,11
1 1 <div class="contextual">
2 2 <%= link_to l(:label_profile), user_path(@user), :class => 'icon icon-user' %>
3 3 <%= change_status_link(@user) %>
4 <%= link_to(l(:button_delete), @user, :confirm => l(:text_are_you_sure), :method => :delete, :class => 'icon icon-del') if User.current != @user %>
4 <%= delete_link user_path(@user) if User.current != @user %>
5 5 </div>
6 6
7 7 <h2><%= link_to l(:label_user_plural), users_path %> &#187; <%=h @user.login %></h2>
8 8
9 9 <%= render_tabs user_settings_tabs %>
10 10
11 11 <% html_title(l(:label_user), @user.login, l(:label_administration)) -%>
@@ -1,58 +1,58
1 1 <div class="contextual">
2 2 <%= link_to l(:label_user_new), new_user_path, :class => 'icon icon-add' %>
3 3 </div>
4 4
5 5 <h2><%=l(:label_user_plural)%></h2>
6 6
7 7 <%= form_tag({}, :method => :get) do %>
8 8 <fieldset><legend><%= l(:label_filter_plural) %></legend>
9 9 <label for='status'><%= l(:field_status) %>:</label>
10 10 <%= select_tag 'status', users_status_options_for_select(@status), :class => "small", :onchange => "this.form.submit(); return false;" %>
11 11
12 12 <% if @groups.present? %>
13 13 <label for='group_id'><%= l(:label_group) %>:</label>
14 14 <%= select_tag 'group_id', content_tag('option') + options_from_collection_for_select(@groups, :id, :name, params[:group_id].to_i), :onchange => "this.form.submit(); return false;" %>
15 15 <% end %>
16 16
17 17 <label for='name'><%= l(:label_user) %>:</label>
18 18 <%= text_field_tag 'name', params[:name], :size => 30 %>
19 19 <%= submit_tag l(:button_apply), :class => "small", :name => nil %>
20 20 <%= link_to l(:button_clear), users_path, :class => 'icon icon-reload' %>
21 21 </fieldset>
22 22 <% end %>
23 23 &nbsp;
24 24
25 25 <div class="autoscroll">
26 26 <table class="list">
27 27 <thead><tr>
28 28 <%= sort_header_tag('login', :caption => l(:field_login)) %>
29 29 <%= sort_header_tag('firstname', :caption => l(:field_firstname)) %>
30 30 <%= sort_header_tag('lastname', :caption => l(:field_lastname)) %>
31 31 <%= sort_header_tag('mail', :caption => l(:field_mail)) %>
32 32 <%= sort_header_tag('admin', :caption => l(:field_admin), :default_order => 'desc') %>
33 33 <%= sort_header_tag('created_on', :caption => l(:field_created_on), :default_order => 'desc') %>
34 34 <%= sort_header_tag('last_login_on', :caption => l(:field_last_login_on), :default_order => 'desc') %>
35 35 <th></th>
36 36 </tr></thead>
37 37 <tbody>
38 38 <% for user in @users -%>
39 39 <tr class="user <%= cycle("odd", "even") %> <%= %w(anon active registered locked)[user.status] %>">
40 40 <td class="username"><%= avatar(user, :size => "14") %><%= link_to h(user.login), edit_user_path(user) %></td>
41 41 <td class="firstname"><%= h(user.firstname) %></td>
42 42 <td class="lastname"><%= h(user.lastname) %></td>
43 43 <td class="email"><%= mail_to(h(user.mail)) %></td>
44 44 <td align="center"><%= checked_image user.admin? %></td>
45 45 <td class="created_on" align="center"><%= format_time(user.created_on) %></td>
46 46 <td class="last_login_on" align="center"><%= format_time(user.last_login_on) unless user.last_login_on.nil? %></td>
47 47 <td class="buttons">
48 48 <%= change_status_link(user) %>
49 <%= link_to(l(:button_delete), user_path(user), :confirm => l(:text_are_you_sure), :method => :delete, :class => 'icon icon-del') unless User.current == user %>
49 <%= delete_link user_path(user) unless User.current == user %>
50 50 </td>
51 51 </tr>
52 52 <% end -%>
53 53 </tbody>
54 54 </table>
55 55 </div>
56 56 <p class="pagination"><%= pagination_links_full @user_pages, @user_count %></p>
57 57
58 58 <% html_title(l(:label_user_plural)) -%>
@@ -1,56 +1,55
1 1 <div class="contextual">
2 2 <%= link_to(l(:button_edit), edit_version_path(@version), :class => 'icon icon-edit') if User.current.allowed_to?(:manage_versions, @version.project) %>
3 3 <%= link_to_if_authorized(l(:button_edit_associated_wikipage, :page_title => @version.wiki_page_title), {:controller => 'wiki', :action => 'edit', :project_id => @version.project, :id => Wiki.titleize(@version.wiki_page_title)}, :class => 'icon icon-edit') unless @version.wiki_page_title.blank? || @version.project.wiki.nil? %>
4 <%= link_to(l(:button_delete), version_path(@version, :back_url => url_for(:controller => 'versions', :action => 'index', :project_id => @version.project)),
5 :confirm => l(:text_are_you_sure), :method => :delete, :class => 'icon icon-del') if User.current.allowed_to?(:manage_versions, @version.project) %>
4 <%= delete_link version_path(@version, :back_url => url_for(:controller => 'versions', :action => 'index', :project_id => @version.project)) if User.current.allowed_to?(:manage_versions, @version.project) %>
6 5 <%= call_hook(:view_versions_show_contextual, { :version => @version, :project => @project }) %>
7 6 </div>
8 7
9 8 <h2><%= h(@version.name) %></h2>
10 9
11 10 <div id="roadmap">
12 11 <%= render :partial => 'versions/overview', :locals => {:version => @version} %>
13 12 <%= render(:partial => "wiki/content", :locals => {:content => @version.wiki_page.content}) if @version.wiki_page %>
14 13
15 14 <div id="version-summary">
16 15 <% if @version.estimated_hours > 0 || User.current.allowed_to?(:view_time_entries, @project) %>
17 16 <fieldset class="time-tracking"><legend><%= l(:label_time_tracking) %></legend>
18 17 <table>
19 18 <tr>
20 19 <th><%= l(:field_estimated_hours) %></th>
21 20 <td class="total-hours"><%= html_hours(l_hours(@version.estimated_hours)) %></td>
22 21 </tr>
23 22 <% if User.current.allowed_to?(:view_time_entries, @project) %>
24 23 <tr>
25 24 <th><%= l(:label_spent_time) %></th>
26 25 <td class="total-hours"><%= html_hours(l_hours(@version.spent_hours)) %></td>
27 26 </tr>
28 27 <% end %>
29 28 </table>
30 29 </fieldset>
31 30 <% end %>
32 31
33 32 <div id="status_by">
34 33 <%= render_issue_status_by(@version, params[:status_by]) if @version.fixed_issues.count > 0 %>
35 34 </div>
36 35 </div>
37 36
38 37 <% if @issues.present? %>
39 38 <%= form_tag({}) do -%>
40 39 <table class="list related-issues">
41 40 <caption><%= l(:label_related_issues) %></caption>
42 41 <%- @issues.each do |issue| -%>
43 42 <tr class="hascontextmenu">
44 43 <td class="checkbox"><%= check_box_tag 'ids[]', issue.id, false, :id => nil %></td>
45 44 <td><%= link_to_issue(issue, :project => (@project != issue.project)) %></td>
46 45 </tr>
47 46 <% end %>
48 47 </table>
49 48 <% end %>
50 49 <%= context_menu issues_context_menu_path %>
51 50 <% end %>
52 51 </div>
53 52
54 53 <%= call_hook :view_versions_show_bottom, :version => @version %>
55 54
56 55 <% html_title @version.name %>
@@ -1,72 +1,72
1 1 <div class="contextual">
2 2 <% if @editable %>
3 3 <%= link_to_if_authorized(l(:button_edit), {:action => 'edit', :id => @page.title}, :class => 'icon icon-edit', :accesskey => accesskey(:edit)) if @content.current_version? %>
4 4 <%= watcher_tag(@page, User.current) %>
5 5 <%= link_to_if_authorized(l(:button_lock), {:action => 'protect', :id => @page.title, :protected => 1}, :method => :post, :class => 'icon icon-lock') if !@page.protected? %>
6 6 <%= link_to_if_authorized(l(:button_unlock), {:action => 'protect', :id => @page.title, :protected => 0}, :method => :post, :class => 'icon icon-unlock') if @page.protected? %>
7 7 <%= link_to_if_authorized(l(:button_rename), {:action => 'rename', :id => @page.title}, :class => 'icon icon-move') if @content.current_version? %>
8 <%= link_to_if_authorized(l(:button_delete), {:action => 'destroy', :id => @page.title}, :method => :delete, :confirm => l(:text_are_you_sure), :class => 'icon icon-del') %>
8 <%= link_to_if_authorized(l(:button_delete), {:action => 'destroy', :id => @page.title}, :method => :delete, :data => {:confirm => l(:text_are_you_sure)}, :class => 'icon icon-del') %>
9 9 <%= link_to_if_authorized(l(:button_rollback), {:action => 'edit', :id => @page.title, :version => @content.version }, :class => 'icon icon-cancel') unless @content.current_version? %>
10 10 <% end %>
11 11 <%= link_to_if_authorized(l(:label_history), {:action => 'history', :id => @page.title}, :class => 'icon icon-history') %>
12 12 </div>
13 13
14 14 <%= wiki_page_breadcrumb(@page) %>
15 15
16 16 <% unless @content.current_version? %>
17 17 <p>
18 18 <%= link_to(("\xc2\xab " + l(:label_previous)),
19 19 :action => 'show', :id => @page.title, :project_id => @page.project,
20 20 :version => (@content.version - 1)) + " - " if @content.version > 1 %>
21 21 <%= "#{l(:label_version)} #{@content.version}/#{@page.content.version}" %>
22 22 <%= '('.html_safe + link_to(l(:label_diff), :controller => 'wiki', :action => 'diff',
23 23 :id => @page.title, :project_id => @page.project,
24 24 :version => @content.version) + ')'.html_safe if @content.version > 1 %> -
25 25 <%= link_to((l(:label_next) + " \xc2\xbb"), :action => 'show',
26 26 :id => @page.title, :project_id => @page.project,
27 27 :version => (@content.version + 1)) + " - " if @content.version < @page.content.version %>
28 28 <%= link_to(l(:label_current_version), :action => 'show', :id => @page.title, :project_id => @page.project) %>
29 29 <br />
30 30 <em><%= @content.author ? link_to_user(@content.author) : l(:label_user_anonymous)
31 31 %>, <%= format_time(@content.updated_on) %> </em><br />
32 32 <%=h @content.comments %>
33 33 </p>
34 34 <hr />
35 35 <% end %>
36 36
37 37 <%= render(:partial => "wiki/content", :locals => {:content => @content}) %>
38 38
39 39 <%= link_to_attachments @page %>
40 40
41 41 <% if @editable && authorize_for('wiki', 'add_attachment') %>
42 42 <div id="wiki_add_attachment">
43 43 <p><%= link_to l(:label_attachment_new), {}, :onclick => "Element.show('add_attachment_form'); Element.hide(this); Element.scrollTo('add_attachment_form'); return false;",
44 44 :id => 'attach_files_link' %></p>
45 45 <%= form_tag({:controller => 'wiki', :action => 'add_attachment',
46 46 :project_id => @project, :id => @page.title},
47 47 :multipart => true, :id => "add_attachment_form",
48 48 :style => "display:none;") do %>
49 49 <div class="box">
50 50 <p><%= render :partial => 'attachments/form' %></p>
51 51 </div>
52 52 <%= submit_tag l(:button_add) %>
53 53 <%= link_to l(:button_cancel), {}, :onclick => "Element.hide('add_attachment_form'); Element.show('attach_files_link'); return false;" %>
54 54 <% end %>
55 55 </div>
56 56 <% end %>
57 57
58 58 <% other_formats_links do |f| %>
59 59 <%= f.link_to 'PDF', :url => {:id => @page.title, :version => params[:version]} %>
60 60 <%= f.link_to 'HTML', :url => {:id => @page.title, :version => params[:version]} %>
61 61 <%= f.link_to 'TXT', :url => {:id => @page.title, :version => params[:version]} %>
62 62 <% end if User.current.allowed_to?(:export_wiki_pages, @project) %>
63 63
64 64 <% content_for :header_tags do %>
65 65 <%= stylesheet_link_tag 'scm' %>
66 66 <% end %>
67 67
68 68 <% content_for :sidebar do %>
69 69 <%= render :partial => 'sidebar' %>
70 70 <% end %>
71 71
72 72 <% html_title @page.pretty_title %>
General Comments 0
You need to be logged in to leave comments. Login now