comparison app/helpers/application_helper.rb @ 1464:261b3d9a4903 redmine-2.4

Update to Redmine 2.4 branch rev 12663
author Chris Cannam
date Tue, 14 Jan 2014 14:37:42 +0000
parents 3e4c3460b6ca
children 51364c0cd58f e248c7af89ec
comparison
equal deleted inserted replaced
1296:038ba2d95de8 1464:261b3d9a4903
1 # encoding: utf-8 1 # encoding: utf-8
2 # 2 #
3 # Redmine - project management software 3 # Redmine - project management software
4 # Copyright (C) 2006-2012 Jean-Philippe Lang 4 # Copyright (C) 2006-2013 Jean-Philippe Lang
5 # 5 #
6 # This program is free software; you can redistribute it and/or 6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License 7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2 8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version. 9 # of the License, or (at your option) any later version.
22 22
23 module ApplicationHelper 23 module ApplicationHelper
24 include Redmine::WikiFormatting::Macros::Definitions 24 include Redmine::WikiFormatting::Macros::Definitions
25 include Redmine::I18n 25 include Redmine::I18n
26 include GravatarHelper::PublicMethods 26 include GravatarHelper::PublicMethods
27 include Redmine::Pagination::Helper
27 28
28 extend Forwardable 29 extend Forwardable
29 def_delegators :wiki_helper, :wikitoolbar_for, :heads_for_wiki_formatter 30 def_delegators :wiki_helper, :wikitoolbar_for, :heads_for_wiki_formatter
30 31
31 # Return true if user is authorized for controller/action, otherwise false 32 # Return true if user is authorized for controller/action, otherwise false
76 subject = issue.subject 77 subject = issue.subject
77 if options[:truncate] 78 if options[:truncate]
78 subject = truncate(subject, :length => options[:truncate]) 79 subject = truncate(subject, :length => options[:truncate])
79 end 80 end
80 end 81 end
81 s = link_to text, issue_path(issue), :class => issue.css_classes, :title => title 82 only_path = options[:only_path].nil? ? true : options[:only_path]
83 s = link_to text, issue_path(issue, :only_path => only_path), :class => issue.css_classes, :title => title
82 s << h(": #{subject}") if subject 84 s << h(": #{subject}") if subject
83 s = h("#{issue.project} - ") + s if options[:project] 85 s = h("#{issue.project} - ") + s if options[:project]
84 s 86 s
85 end 87 end
86 88
88 # Options: 90 # Options:
89 # * :text - Link text (default to attachment filename) 91 # * :text - Link text (default to attachment filename)
90 # * :download - Force download (default: false) 92 # * :download - Force download (default: false)
91 def link_to_attachment(attachment, options={}) 93 def link_to_attachment(attachment, options={})
92 text = options.delete(:text) || attachment.filename 94 text = options.delete(:text) || attachment.filename
93 action = options.delete(:download) ? 'download' : 'show' 95 route_method = options.delete(:download) ? :download_named_attachment_path : :named_attachment_path
94 opt_only_path = {} 96 html_options = options.slice!(:only_path)
95 opt_only_path[:only_path] = (options[:only_path] == false ? false : true) 97 url = send(route_method, attachment, attachment.filename, options)
96 options.delete(:only_path) 98 link_to text, url, html_options
97 link_to(h(text),
98 {:controller => 'attachments', :action => action,
99 :id => attachment, :filename => attachment.filename}.merge(opt_only_path),
100 options)
101 end 99 end
102 100
103 # Generates a link to a SCM revision 101 # Generates a link to a SCM revision
104 # Options: 102 # Options:
105 # * :text - Link text (default to the formatted revision) 103 # * :text - Link text (default to the formatted revision)
117 end 115 end
118 116
119 # Generates a link to a message 117 # Generates a link to a message
120 def link_to_message(message, options={}, html_options = nil) 118 def link_to_message(message, options={}, html_options = nil)
121 link_to( 119 link_to(
122 h(truncate(message.subject, :length => 60)), 120 truncate(message.subject, :length => 60),
123 { :controller => 'messages', :action => 'show', 121 board_message_path(message.board_id, message.parent_id || message.id, {
124 :board_id => message.board_id,
125 :id => (message.parent_id || message.id),
126 :r => (message.parent_id && message.id), 122 :r => (message.parent_id && message.id),
127 :anchor => (message.parent_id ? "message-#{message.id}" : nil) 123 :anchor => (message.parent_id ? "message-#{message.id}" : nil)
128 }.merge(options), 124 }.merge(options)),
129 html_options 125 html_options
130 ) 126 )
131 end 127 end
132 128
133 # Generates a link to a project if active 129 # Generates a link to a project if active
134 # Examples: 130 # Examples:
135 # 131 #
136 # link_to_project(project) # => link to the specified project overview 132 # link_to_project(project) # => link to the specified project overview
137 # link_to_project(project, :action=>'settings') # => link to project settings
138 # link_to_project(project, {:only_path => false}, :class => "project") # => 3rd arg adds html options 133 # link_to_project(project, {:only_path => false}, :class => "project") # => 3rd arg adds html options
139 # link_to_project(project, {}, :class => "project") # => html options with default url (project overview) 134 # link_to_project(project, {}, :class => "project") # => html options with default url (project overview)
140 # 135 #
141 def link_to_project(project, options={}, html_options = nil) 136 def link_to_project(project, options={}, html_options = nil)
142 if project.archived? 137 if project.archived?
143 h(project) 138 h(project.name)
144 else 139 elsif options.key?(:action)
140 ActiveSupport::Deprecation.warn "#link_to_project with :action option is deprecated and will be removed in Redmine 3.0."
145 url = {:controller => 'projects', :action => 'show', :id => project}.merge(options) 141 url = {:controller => 'projects', :action => 'show', :id => project}.merge(options)
146 link_to(h(project), url, html_options) 142 link_to project.name, url, html_options
143 else
144 link_to project.name, project_path(project, options), html_options
145 end
146 end
147
148 # Generates a link to a project settings if active
149 def link_to_project_settings(project, options={}, html_options=nil)
150 if project.active?
151 link_to project.name, settings_project_path(project, options), html_options
152 elsif project.archived?
153 h(project.name)
154 else
155 link_to project.name, project_path(project, options), html_options
147 end 156 end
148 end 157 end
149 158
150 def wiki_page_path(page, options={}) 159 def wiki_page_path(page, options={})
151 url_for({:controller => 'wiki', :action => 'show', :project_id => page.project, :id => page.title}.merge(options)) 160 url_for({:controller => 'wiki', :action => 'show', :project_id => page.project, :id => page.title}.merge(options))
152 end 161 end
153 162
154 def thumbnail_tag(attachment) 163 def thumbnail_tag(attachment)
155 link_to image_tag(url_for(:controller => 'attachments', :action => 'thumbnail', :id => attachment)), 164 link_to image_tag(thumbnail_path(attachment)),
156 {:controller => 'attachments', :action => 'show', :id => attachment, :filename => attachment.filename}, 165 named_attachment_path(attachment, attachment.filename),
157 :title => attachment.filename 166 :title => attachment.filename
158 end 167 end
159 168
160 def toggle_link(name, id, options={}) 169 def toggle_link(name, id, options={})
161 onclick = "$('##{id}').toggle(); " 170 onclick = "$('##{id}').toggle(); "
185 ).gsub(/[\r\n]+/, "<br />").html_safe 194 ).gsub(/[\r\n]+/, "<br />").html_safe
186 end 195 end
187 196
188 def format_version_name(version) 197 def format_version_name(version)
189 if version.project == @project 198 if version.project == @project
190 h(version) 199 h(version)
191 else 200 else
192 h("#{version.project} - #{version}") 201 h("#{version.project} - #{version}")
193 end 202 end
194 end 203 end
195 204
306 Project.project_tree(projects, &block) 315 Project.project_tree(projects, &block)
307 end 316 end
308 317
309 def principals_check_box_tags(name, principals) 318 def principals_check_box_tags(name, principals)
310 s = '' 319 s = ''
311 principals.sort.each do |principal| 320 principals.each do |principal|
312 s << "<label>#{ check_box_tag name, principal.id, false } #{h principal}</label>\n" 321 s << "<label>#{ check_box_tag name, principal.id, false, :id => nil } #{h principal}</label>\n"
313 end 322 end
314 s.html_safe 323 s.html_safe
315 end 324 end
316 325
317 # Returns a string for users/groups option tags 326 # Returns a string for users/groups option tags
320 if collection.include?(User.current) 329 if collection.include?(User.current)
321 s << content_tag('option', "<< #{l(:label_me)} >>", :value => User.current.id) 330 s << content_tag('option', "<< #{l(:label_me)} >>", :value => User.current.id)
322 end 331 end
323 groups = '' 332 groups = ''
324 collection.sort.each do |element| 333 collection.sort.each do |element|
325 selected_attribute = ' selected="selected"' if option_value_selected?(element, selected) 334 selected_attribute = ' selected="selected"' if option_value_selected?(element, selected) || element.id.to_s == selected
326 (element.is_a?(Group) ? groups : s) << %(<option value="#{element.id}"#{selected_attribute}>#{h element.name}</option>) 335 (element.is_a?(Group) ? groups : s) << %(<option value="#{element.id}"#{selected_attribute}>#{h element.name}</option>)
327 end 336 end
328 unless groups.empty? 337 unless groups.empty?
329 s << %(<optgroup label="#{h(l(:label_group_plural))}">#{groups}</optgroup>) 338 s << %(<optgroup label="#{h(l(:label_group_plural))}">#{groups}</optgroup>)
330 end 339 end
333 342
334 # Options for the new membership projects combo-box 343 # Options for the new membership projects combo-box
335 def options_for_membership_project_select(principal, projects) 344 def options_for_membership_project_select(principal, projects)
336 options = content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---") 345 options = content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---")
337 options << project_tree_options_for_select(projects) do |p| 346 options << project_tree_options_for_select(projects) do |p|
338 {:disabled => principal.projects.include?(p)} 347 {:disabled => principal.projects.to_a.include?(p)}
339 end 348 end
340 options 349 options
350 end
351
352 def option_tag(name, text, value, selected=nil, options={})
353 content_tag 'option', value, options.merge(:value => value, :selected => (value == selected))
341 end 354 end
342 355
343 # Truncates and returns the string as a single line 356 # Truncates and returns the string as a single line
344 def truncate_single_line(string, *args) 357 def truncate_single_line(string, *args)
345 truncate(string.to_s, *args).gsub(%r{[\r\n]+}m, ' ') 358 truncate(string.to_s, *args).gsub(%r{[\r\n]+}m, ' ')
370 def time_tag(time) 383 def time_tag(time)
371 text = distance_of_time_in_words(Time.now, time) 384 text = distance_of_time_in_words(Time.now, time)
372 if @project 385 if @project
373 link_to(text, {:controller => 'activities', :action => 'index', :id => @project, :from => User.current.time_to_date(time)}, :title => format_time(time)) 386 link_to(text, {:controller => 'activities', :action => 'index', :id => @project, :from => User.current.time_to_date(time)}, :title => format_time(time))
374 else 387 else
375 content_tag('acronym', text, :title => format_time(time)) 388 content_tag('abbr', text, :title => format_time(time))
376 end 389 end
377 end 390 end
378 391
379 def syntax_highlight_lines(name, content) 392 def syntax_highlight_lines(name, content)
380 lines = [] 393 lines = []
387 end 400 end
388 401
389 def to_path_param(path) 402 def to_path_param(path)
390 str = path.to_s.split(%r{[/\\]}).select{|p| !p.blank?}.join("/") 403 str = path.to_s.split(%r{[/\\]}).select{|p| !p.blank?}.join("/")
391 str.blank? ? nil : str 404 str.blank? ? nil : str
392 end
393
394 def pagination_links_full(paginator, count=nil, options={})
395 page_param = options.delete(:page_param) || :page
396 per_page_links = options.delete(:per_page_links)
397 url_param = params.dup
398
399 html = ''
400 if paginator.current.previous
401 # \xc2\xab(utf-8) = &#171;
402 html << link_to_content_update(
403 "\xc2\xab " + l(:label_previous),
404 url_param.merge(page_param => paginator.current.previous)) + ' '
405 end
406
407 html << (pagination_links_each(paginator, options) do |n|
408 link_to_content_update(n.to_s, url_param.merge(page_param => n))
409 end || '')
410
411 if paginator.current.next
412 # \xc2\xbb(utf-8) = &#187;
413 html << ' ' + link_to_content_update(
414 (l(:label_next) + " \xc2\xbb"),
415 url_param.merge(page_param => paginator.current.next))
416 end
417
418 unless count.nil?
419 html << " (#{paginator.current.first_item}-#{paginator.current.last_item}/#{count})"
420 if per_page_links != false && links = per_page_links(paginator.items_per_page, count)
421 html << " | #{links}"
422 end
423 end
424
425 html.html_safe
426 end
427
428 def per_page_links(selected=nil, item_count=nil)
429 values = Setting.per_page_options_array
430 if item_count && values.any?
431 if item_count > values.first
432 max = values.detect {|value| value >= item_count} || item_count
433 else
434 max = item_count
435 end
436 values = values.select {|value| value <= max || value == selected}
437 end
438 if values.empty? || (values.size == 1 && values.first == selected)
439 return nil
440 end
441 links = values.collect do |n|
442 n == selected ? n : link_to_content_update(n, params.merge(:per_page => n))
443 end
444 l(:label_display_per_page, links.join(', '))
445 end 405 end
446 406
447 def reorder_links(name, url, method = :post) 407 def reorder_links(name, url, method = :post)
448 link_to(image_tag('2uparrow.png', :alt => l(:label_sort_highest)), 408 link_to(image_tag('2uparrow.png', :alt => l(:label_sort_highest)),
449 url.merge({"#{name}[move_to]" => 'highest'}), 409 url.merge({"#{name}[move_to]" => 'highest'}),
488 b << h(@project) 448 b << h(@project)
489 b.join(" \xc2\xbb ").html_safe 449 b.join(" \xc2\xbb ").html_safe
490 end 450 end
491 end 451 end
492 452
453 # Returns a h2 tag and sets the html title with the given arguments
454 def title(*args)
455 strings = args.map do |arg|
456 if arg.is_a?(Array) && arg.size >= 2
457 link_to(*arg)
458 else
459 h(arg.to_s)
460 end
461 end
462 html_title args.reverse.map {|s| (s.is_a?(Array) ? s.first : s).to_s}
463 content_tag('h2', strings.join(' &#187; ').html_safe)
464 end
465
466 # Sets the html title
467 # Returns the html title when called without arguments
468 # Current project name and app_title and automatically appended
469 # Exemples:
470 # html_title 'Foo', 'Bar'
471 # html_title # => 'Foo - Bar - My Project - Redmine'
493 def html_title(*args) 472 def html_title(*args)
494 if args.empty? 473 if args.empty?
495 title = @html_title || [] 474 title = @html_title || []
496 title << @project.name if @project 475 title << @project.name if @project
497 title << Setting.app_title unless Setting.app_title == title.last 476 title << Setting.app_title unless Setting.app_title == title.last
498 title.select {|t| !t.blank? }.join(' - ') 477 title.reject(&:blank?).join(' - ')
499 else 478 else
500 @html_title ||= [] 479 @html_title ||= []
501 @html_title += args 480 @html_title += args
502 end 481 end
503 end 482 end
508 css = [] 487 css = []
509 if theme = Redmine::Themes.theme(Setting.ui_theme) 488 if theme = Redmine::Themes.theme(Setting.ui_theme)
510 css << 'theme-' + theme.name 489 css << 'theme-' + theme.name
511 end 490 end
512 491
492 css << 'project-' + @project.identifier if @project && @project.identifier.present?
513 css << 'controller-' + controller_name 493 css << 'controller-' + controller_name
514 css << 'action-' + action_name 494 css << 'action-' + action_name
515 css.join(' ') 495 css.join(' ')
516 end 496 end
517 497
518 def accesskey(s) 498 def accesskey(s)
519 Redmine::AccessKeys.key_for s 499 @used_accesskeys ||= []
500 key = Redmine::AccessKeys.key_for(s)
501 return nil if @used_accesskeys.include?(key)
502 @used_accesskeys << key
503 key
520 end 504 end
521 505
522 # Formats text according to system settings. 506 # Formats text according to system settings.
523 # 2 ways to call this method: 507 # 2 ways to call this method:
524 # * with a String: textilizable(text, options) 508 # * with a String: textilizable(text, options)
602 if attachments.present? 586 if attachments.present?
603 text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpe|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m| 587 text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpe|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m|
604 filename, ext, alt, alttext = $1.downcase, $2, $3, $4 588 filename, ext, alt, alttext = $1.downcase, $2, $3, $4
605 # search for the picture in attachments 589 # search for the picture in attachments
606 if found = Attachment.latest_attach(attachments, filename) 590 if found = Attachment.latest_attach(attachments, filename)
607 image_url = url_for :only_path => only_path, :controller => 'attachments', 591 image_url = download_named_attachment_path(found, found.filename, :only_path => only_path)
608 :action => 'download', :id => found
609 desc = found.description.to_s.gsub('"', '') 592 desc = found.description.to_s.gsub('"', '')
610 if !desc.blank? && alttext.blank? 593 if !desc.blank? && alttext.blank?
611 alt = " title=\"#{desc}\" alt=\"#{desc}\"" 594 alt = " title=\"#{desc}\" alt=\"#{desc}\""
612 end 595 end
613 "src=\"#{image_url}\"#{alt}" 596 "src=\"#{image_url}\"#{alt}"
632 text.gsub!(/(!)?(\[\[([^\]\n\|]+)(\|([^\]\n\|]+))?\]\])/) do |m| 615 text.gsub!(/(!)?(\[\[([^\]\n\|]+)(\|([^\]\n\|]+))?\]\])/) do |m|
633 link_project = project 616 link_project = project
634 esc, all, page, title = $1, $2, $3, $5 617 esc, all, page, title = $1, $2, $3, $5
635 if esc.nil? 618 if esc.nil?
636 if page =~ /^([^\:]+)\:(.*)$/ 619 if page =~ /^([^\:]+)\:(.*)$/
637 link_project = Project.find_by_identifier($1) || Project.find_by_name($1) 620 identifier, page = $1, $2
638 page = $2 621 link_project = Project.find_by_identifier(identifier) || Project.find_by_name(identifier)
639 title ||= $1 if page.blank? 622 title ||= identifier if page.blank?
640 end 623 end
641 624
642 if link_project && link_project.wiki 625 if link_project && link_project.wiki
643 # extract anchor 626 # extract anchor
644 anchor = nil 627 anchor = nil
655 when :local; "#{page.present? ? Wiki.titleize(page) : ''}.html" + (anchor.present? ? "##{anchor}" : '') 638 when :local; "#{page.present? ? Wiki.titleize(page) : ''}.html" + (anchor.present? ? "##{anchor}" : '')
656 when :anchor; "##{page.present? ? Wiki.titleize(page) : title}" + (anchor.present? ? "_#{anchor}" : '') # used for single-file wiki export 639 when :anchor; "##{page.present? ? Wiki.titleize(page) : title}" + (anchor.present? ? "_#{anchor}" : '') # used for single-file wiki export
657 else 640 else
658 wiki_page_id = page.present? ? Wiki.titleize(page) : nil 641 wiki_page_id = page.present? ? Wiki.titleize(page) : nil
659 parent = wiki_page.nil? && obj.is_a?(WikiContent) && obj.page && project == link_project ? obj.page.title : nil 642 parent = wiki_page.nil? && obj.is_a?(WikiContent) && obj.page && project == link_project ? obj.page.title : nil
660 url_for(:only_path => only_path, :controller => 'wiki', :action => 'show', :project_id => link_project, 643 url_for(:only_path => only_path, :controller => 'wiki', :action => 'show', :project_id => link_project,
661 :id => wiki_page_id, :version => nil, :anchor => anchor, :parent => parent) 644 :id => wiki_page_id, :version => nil, :anchor => anchor, :parent => parent)
662 end 645 end
663 end 646 end
664 link_to(title.present? ? title.html_safe : h(page), url, :class => ('wiki-page' + (wiki_page ? '' : ' new'))) 647 link_to(title.present? ? title.html_safe : h(page), url, :class => ('wiki-page' + (wiki_page ? '' : ' new')))
665 else 648 else
696 # source:some/file#L120 -> Link to line 120 of the file 679 # source:some/file#L120 -> Link to line 120 of the file
697 # source:some/file@52#L120 -> Link to line 120 of the file's revision 52 680 # source:some/file@52#L120 -> Link to line 120 of the file's revision 52
698 # export:some/file -> Force the download of the file 681 # export:some/file -> Force the download of the file
699 # Forum messages: 682 # Forum messages:
700 # message#1218 -> Link to message with id 1218 683 # message#1218 -> Link to message with id 1218
684 # Projects:
685 # project:someproject -> Link to project named "someproject"
686 # project#3 -> Link to project with id 3
701 # 687 #
702 # Links can refer other objects from other projects, using project identifier: 688 # Links can refer other objects from other projects, using project identifier:
703 # identifier:r52 689 # identifier:r52
704 # identifier:document:"Some document" 690 # identifier:document:"Some document"
705 # identifier:version:1.0.0 691 # identifier:version:1.0.0
732 oid = identifier.to_i 718 oid = identifier.to_i
733 case prefix 719 case prefix
734 when nil 720 when nil
735 if oid.to_s == identifier && issue = Issue.visible.find_by_id(oid, :include => :status) 721 if oid.to_s == identifier && issue = Issue.visible.find_by_id(oid, :include => :status)
736 anchor = comment_id ? "note-#{comment_id}" : nil 722 anchor = comment_id ? "note-#{comment_id}" : nil
737 link = link_to("##{oid}", {:only_path => only_path, :controller => 'issues', :action => 'show', :id => oid, :anchor => anchor}, 723 link = link_to(h("##{oid}#{comment_suffix}"), {:only_path => only_path, :controller => 'issues', :action => 'show', :id => oid, :anchor => anchor},
738 :class => issue.css_classes, 724 :class => issue.css_classes,
739 :title => "#{truncate(issue.subject, :length => 100)} (#{issue.status.name})") 725 :title => "#{truncate(issue.subject, :length => 100)} (#{issue.status.name})")
740 end 726 end
741 when 'document' 727 when 'document'
742 if document = Document.visible.find_by_id(oid) 728 if document = Document.visible.find_by_id(oid)
799 repository = project.repositories.detect {|repo| repo.identifier == repo_identifier} 785 repository = project.repositories.detect {|repo| repo.identifier == repo_identifier}
800 else 786 else
801 repository = project.repository 787 repository = project.repository
802 end 788 end
803 if prefix == 'commit' 789 if prefix == 'commit'
804 if repository && (changeset = Changeset.visible.find(:first, :conditions => ["repository_id = ? AND scmid LIKE ?", repository.id, "#{name}%"])) 790 if repository && (changeset = Changeset.visible.where("repository_id = ? AND scmid LIKE ?", repository.id, "#{name}%").first)
805 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}, 791 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},
806 :class => 'changeset', 792 :class => 'changeset',
807 :title => truncate_single_line(h(changeset.comments), :length => 100) 793 :title => truncate_single_line(changeset.comments, :length => 100)
808 end 794 end
809 else 795 else
810 if repository && User.current.allowed_to?(:browse_repository, project) 796 if repository && User.current.allowed_to?(:browse_repository, project)
811 name =~ %r{^[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?$} 797 name =~ %r{^[/\\]*(.*?)(@([^/\\@]+?))?(#(L\d+))?$}
812 path, rev, anchor = $1, $3, $5 798 path, rev, anchor = $1, $3, $5
813 link = link_to h("#{project_prefix}#{prefix}:#{repo_prefix}#{name}"), {:controller => 'repositories', :action => (prefix == 'export' ? 'raw' : 'entry'), :id => project, :repository_id => repository.identifier_param, 799 link = link_to h("#{project_prefix}#{prefix}:#{repo_prefix}#{name}"), {:controller => 'repositories', :action => (prefix == 'export' ? 'raw' : 'entry'), :id => project, :repository_id => repository.identifier_param,
814 :path => to_path_param(path), 800 :path => to_path_param(path),
815 :rev => rev, 801 :rev => rev,
816 :anchor => anchor}, 802 :anchor => anchor},
820 repo_prefix = nil 806 repo_prefix = nil
821 end 807 end
822 when 'attachment' 808 when 'attachment'
823 attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil) 809 attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil)
824 if attachments && attachment = Attachment.latest_attach(attachments, name) 810 if attachments && attachment = Attachment.latest_attach(attachments, name)
825 link = link_to h(attachment.filename), {:only_path => only_path, :controller => 'attachments', :action => 'download', :id => attachment}, 811 link = link_to_attachment(attachment, :only_path => only_path, :download => true, :class => 'attachment')
826 :class => 'attachment'
827 end 812 end
828 when 'project' 813 when 'project'
829 if p = Project.visible.find(:first, :conditions => ["identifier = :s OR LOWER(name) = :s", {:s => name.downcase}]) 814 if p = Project.visible.where("identifier = :s OR LOWER(name) = :s", :s => name.downcase).first
830 link = link_to_project(p, {:only_path => only_path}, :class => 'project') 815 link = link_to_project(p, {:only_path => only_path}, :class => 'project')
831 end 816 end
832 end 817 end
833 end 818 end
834 end 819 end
845 @current_section += 1 830 @current_section += 1
846 if @current_section > 1 831 if @current_section > 1
847 content_tag('div', 832 content_tag('div',
848 link_to(image_tag('edit.png'), options[:edit_section_links].merge(:section => @current_section)), 833 link_to(image_tag('edit.png'), options[:edit_section_links].merge(:section => @current_section)),
849 :class => 'contextual', 834 :class => 'contextual',
850 :title => l(:button_edit_section)) + heading.html_safe 835 :title => l(:button_edit_section),
836 :id => "section-#{@current_section}") + heading.html_safe
851 else 837 else
852 heading 838 heading
853 end 839 end
854 end 840 end
855 end 841 end
1016 html << "<li>#{h error}</li>\n" 1002 html << "<li>#{h error}</li>\n"
1017 end 1003 end
1018 html << "</ul></div>\n" 1004 html << "</ul></div>\n"
1019 end 1005 end
1020 html.html_safe 1006 html.html_safe
1021 end 1007 end
1022 1008
1023 def delete_link(url, options={}) 1009 def delete_link(url, options={})
1024 options = { 1010 options = {
1025 :method => :delete, 1011 :method => :delete,
1026 :data => {:confirm => l(:text_are_you_sure)}, 1012 :data => {:confirm => l(:text_are_you_sure)},
1030 link_to l(:button_delete), url, options 1016 link_to l(:button_delete), url, options
1031 end 1017 end
1032 1018
1033 def preview_link(url, form, target='preview', options={}) 1019 def preview_link(url, form, target='preview', options={})
1034 content_tag 'a', l(:label_preview), { 1020 content_tag 'a', l(:label_preview), {
1035 :href => "#", 1021 :href => "#",
1036 :onclick => %|submitPreview("#{escape_javascript url_for(url)}", "#{escape_javascript form}", "#{escape_javascript target}"); return false;|, 1022 :onclick => %|submitPreview("#{escape_javascript url_for(url)}", "#{escape_javascript form}", "#{escape_javascript target}"); return false;|,
1037 :accesskey => accesskey(:preview) 1023 :accesskey => accesskey(:preview)
1038 }.merge(options) 1024 }.merge(options)
1039 end 1025 end
1040 1026
1041 def link_to_function(name, function, html_options={}) 1027 def link_to_function(name, function, html_options={})
1076 content_tag('table', 1062 content_tag('table',
1077 content_tag('tr', 1063 content_tag('tr',
1078 (pcts[0] > 0 ? content_tag('td', '', :style => "width: #{pcts[0]}%;", :class => 'closed') : ''.html_safe) + 1064 (pcts[0] > 0 ? content_tag('td', '', :style => "width: #{pcts[0]}%;", :class => 'closed') : ''.html_safe) +
1079 (pcts[1] > 0 ? content_tag('td', '', :style => "width: #{pcts[1]}%;", :class => 'done') : ''.html_safe) + 1065 (pcts[1] > 0 ? content_tag('td', '', :style => "width: #{pcts[1]}%;", :class => 'done') : ''.html_safe) +
1080 (pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2]}%;", :class => 'todo') : ''.html_safe) 1066 (pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2]}%;", :class => 'todo') : ''.html_safe)
1081 ), :class => 'progress', :style => "width: #{width};").html_safe + 1067 ), :class => "progress progress-#{pcts[0]}", :style => "width: #{width};").html_safe +
1082 content_tag('p', legend, :class => 'pourcent').html_safe 1068 content_tag('p', legend, :class => 'percent').html_safe
1083 end 1069 end
1084 1070
1085 def checked_image(checked=true) 1071 def checked_image(checked=true)
1086 if checked 1072 if checked
1087 image_tag 'toggle_check.png' 1073 image_tag 'toggle_check.png'
1109 javascript_tag("$(function() { $('##{field_id}').datepicker(datepickerOptions); });") 1095 javascript_tag("$(function() { $('##{field_id}').datepicker(datepickerOptions); });")
1110 end 1096 end
1111 1097
1112 def include_calendar_headers_tags 1098 def include_calendar_headers_tags
1113 unless @calendar_headers_tags_included 1099 unless @calendar_headers_tags_included
1100 tags = javascript_include_tag("datepicker")
1114 @calendar_headers_tags_included = true 1101 @calendar_headers_tags_included = true
1115 content_for :header_tags do 1102 content_for :header_tags do
1116 start_of_week = Setting.start_of_week 1103 start_of_week = Setting.start_of_week
1117 start_of_week = l(:general_first_day_of_week, :default => '1') if start_of_week.blank? 1104 start_of_week = l(:general_first_day_of_week, :default => '1') if start_of_week.blank?
1118 # Redmine uses 1..7 (monday..sunday) in settings and locales 1105 # Redmine uses 1..7 (monday..sunday) in settings and locales
1119 # JQuery uses 0..6 (sunday..saturday), 7 needs to be changed to 0 1106 # JQuery uses 0..6 (sunday..saturday), 7 needs to be changed to 0
1120 start_of_week = start_of_week.to_i % 7 1107 start_of_week = start_of_week.to_i % 7
1121 1108 tags << javascript_tag(
1122 tags = javascript_tag(
1123 "var datepickerOptions={dateFormat: 'yy-mm-dd', firstDay: #{start_of_week}, " + 1109 "var datepickerOptions={dateFormat: 'yy-mm-dd', firstDay: #{start_of_week}, " +
1124 "showOn: 'button', buttonImageOnly: true, buttonImage: '" + 1110 "showOn: 'button', buttonImageOnly: true, buttonImage: '" +
1125 path_to_image('/images/calendar.png') + 1111 path_to_image('/images/calendar.png') +
1126 "', showButtonPanel: true};") 1112 "', showButtonPanel: true, showWeek: true, showOtherMonths: true, " +
1113 "selectOtherMonths: true, changeMonth: true, changeYear: true, " +
1114 "beforeShow: beforeShowDatePicker};")
1127 jquery_locale = l('jquery.locale', :default => current_language.to_s) 1115 jquery_locale = l('jquery.locale', :default => current_language.to_s)
1128 unless jquery_locale == 'en' 1116 unless jquery_locale == 'en'
1129 tags << javascript_include_tag("i18n/jquery.ui.datepicker-#{jquery_locale}.js") 1117 tags << javascript_include_tag("i18n/jquery.ui.datepicker-#{jquery_locale}.js")
1130 end 1118 end
1131 tags 1119 tags
1132 end 1120 end
1133 end 1121 end
1134 end 1122 end
1184 end 1172 end
1185 end 1173 end
1186 super sources, options 1174 super sources, options
1187 end 1175 end
1188 1176
1189 def content_for(name, content = nil, &block) 1177 # TODO: remove this in 2.5.0
1190 @has_content ||= {}
1191 @has_content[name] = true
1192 super(name, content, &block)
1193 end
1194
1195 def has_content?(name) 1178 def has_content?(name)
1196 (@has_content && @has_content[name]) || false 1179 content_for?(name)
1197 end 1180 end
1198 1181
1199 def sidebar_content? 1182 def sidebar_content?
1200 has_content?(:sidebar) || view_layouts_base_sidebar_hook_response.present? 1183 content_for?(:sidebar) || view_layouts_base_sidebar_hook_response.present?
1201 end 1184 end
1202 1185
1203 def view_layouts_base_sidebar_hook_response 1186 def view_layouts_base_sidebar_hook_response
1204 @view_layouts_base_sidebar_hook_response ||= call_hook(:view_layouts_base_sidebar) 1187 @view_layouts_base_sidebar_hook_response ||= call_hook(:view_layouts_base_sidebar)
1205 end 1188 end
1225 end 1208 end
1226 end 1209 end
1227 1210
1228 def sanitize_anchor_name(anchor) 1211 def sanitize_anchor_name(anchor)
1229 if ''.respond_to?(:encoding) || RUBY_PLATFORM == 'java' 1212 if ''.respond_to?(:encoding) || RUBY_PLATFORM == 'java'
1230 anchor.gsub(%r{[^\p{Word}\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-') 1213 anchor.gsub(%r{[^\s\-\p{Word}]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
1231 else 1214 else
1232 # TODO: remove when ruby1.8 is no longer supported 1215 # TODO: remove when ruby1.8 is no longer supported
1233 anchor.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-') 1216 anchor.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
1234 end 1217 end
1235 end 1218 end
1236 1219
1237 # Returns the javascript tags that are included in the html layout head 1220 # Returns the javascript tags that are included in the html layout head
1238 def javascript_heads 1221 def javascript_heads
1239 tags = javascript_include_tag('jquery-1.7.2-ui-1.8.21-ujs-2.0.3', 'application') 1222 tags = javascript_include_tag('jquery-1.8.3-ui-1.9.2-ujs-2.0.3', 'application')
1240 unless User.current.pref.warn_on_leaving_unsaved == '0' 1223 unless User.current.pref.warn_on_leaving_unsaved == '0'
1241 tags << "\n".html_safe + javascript_tag("$(window).load(function(){ warnLeavingUnsaved('#{escape_javascript l(:text_warn_on_leaving_unsaved)}'); });") 1224 tags << "\n".html_safe + javascript_tag("$(window).load(function(){ warnLeavingUnsaved('#{escape_javascript l(:text_warn_on_leaving_unsaved)}'); });")
1242 end 1225 end
1243 tags 1226 tags
1244 end 1227 end