comparison app/helpers/application_helper.rb @ 1295:622f24f53b42 redmine-2.3

Update to Redmine SVN revision 11972 on 2.3-stable branch
author Chris Cannam
date Fri, 14 Jun 2013 09:02:21 +0100
parents 3e4c3460b6ca
children 4f746d8966dd
comparison
equal deleted inserted replaced
1294:3e4c3460b6ca 1295:622f24f53b42
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
88 # Options: 89 # Options:
89 # * :text - Link text (default to attachment filename) 90 # * :text - Link text (default to attachment filename)
90 # * :download - Force download (default: false) 91 # * :download - Force download (default: false)
91 def link_to_attachment(attachment, options={}) 92 def link_to_attachment(attachment, options={})
92 text = options.delete(:text) || attachment.filename 93 text = options.delete(:text) || attachment.filename
93 action = options.delete(:download) ? 'download' : 'show' 94 route_method = options.delete(:download) ? :download_named_attachment_path : :named_attachment_path
94 opt_only_path = {} 95 html_options = options.slice!(:only_path)
95 opt_only_path[:only_path] = (options[:only_path] == false ? false : true) 96 url = send(route_method, attachment, attachment.filename, options)
96 options.delete(:only_path) 97 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 98 end
102 99
103 # Generates a link to a SCM revision 100 # Generates a link to a SCM revision
104 # Options: 101 # Options:
105 # * :text - Link text (default to the formatted revision) 102 # * :text - Link text (default to the formatted revision)
117 end 114 end
118 115
119 # Generates a link to a message 116 # Generates a link to a message
120 def link_to_message(message, options={}, html_options = nil) 117 def link_to_message(message, options={}, html_options = nil)
121 link_to( 118 link_to(
122 h(truncate(message.subject, :length => 60)), 119 truncate(message.subject, :length => 60),
123 { :controller => 'messages', :action => 'show', 120 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), 121 :r => (message.parent_id && message.id),
127 :anchor => (message.parent_id ? "message-#{message.id}" : nil) 122 :anchor => (message.parent_id ? "message-#{message.id}" : nil)
128 }.merge(options), 123 }.merge(options)),
129 html_options 124 html_options
130 ) 125 )
131 end 126 end
132 127
133 # Generates a link to a project if active 128 # Generates a link to a project if active
134 # Examples: 129 # Examples:
135 # 130 #
136 # link_to_project(project) # => link to the specified project overview 131 # 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 132 # 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) 133 # link_to_project(project, {}, :class => "project") # => html options with default url (project overview)
140 # 134 #
141 def link_to_project(project, options={}, html_options = nil) 135 def link_to_project(project, options={}, html_options = nil)
142 if project.archived? 136 if project.archived?
143 h(project) 137 h(project.name)
144 else 138 elsif options.key?(:action)
139 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) 140 url = {:controller => 'projects', :action => 'show', :id => project}.merge(options)
146 link_to(h(project), url, html_options) 141 link_to project.name, url, html_options
142 else
143 link_to project.name, project_path(project, options), html_options
144 end
145 end
146
147 # Generates a link to a project settings if active
148 def link_to_project_settings(project, options={}, html_options=nil)
149 if project.active?
150 link_to project.name, settings_project_path(project, options), html_options
151 elsif project.archived?
152 h(project.name)
153 else
154 link_to project.name, project_path(project, options), html_options
147 end 155 end
148 end 156 end
149 157
150 def wiki_page_path(page, options={}) 158 def wiki_page_path(page, options={})
151 url_for({:controller => 'wiki', :action => 'show', :project_id => page.project, :id => page.title}.merge(options)) 159 url_for({:controller => 'wiki', :action => 'show', :project_id => page.project, :id => page.title}.merge(options))
152 end 160 end
153 161
154 def thumbnail_tag(attachment) 162 def thumbnail_tag(attachment)
155 link_to image_tag(url_for(:controller => 'attachments', :action => 'thumbnail', :id => attachment)), 163 link_to image_tag(thumbnail_path(attachment)),
156 {:controller => 'attachments', :action => 'show', :id => attachment, :filename => attachment.filename}, 164 named_attachment_path(attachment, attachment.filename),
157 :title => attachment.filename 165 :title => attachment.filename
158 end 166 end
159 167
160 def toggle_link(name, id, options={}) 168 def toggle_link(name, id, options={})
161 onclick = "$('##{id}').toggle(); " 169 onclick = "$('##{id}').toggle(); "
185 ).gsub(/[\r\n]+/, "<br />").html_safe 193 ).gsub(/[\r\n]+/, "<br />").html_safe
186 end 194 end
187 195
188 def format_version_name(version) 196 def format_version_name(version)
189 if version.project == @project 197 if version.project == @project
190 h(version) 198 h(version)
191 else 199 else
192 h("#{version.project} - #{version}") 200 h("#{version.project} - #{version}")
193 end 201 end
194 end 202 end
195 203
306 Project.project_tree(projects, &block) 314 Project.project_tree(projects, &block)
307 end 315 end
308 316
309 def principals_check_box_tags(name, principals) 317 def principals_check_box_tags(name, principals)
310 s = '' 318 s = ''
311 principals.sort.each do |principal| 319 principals.each do |principal|
312 s << "<label>#{ check_box_tag name, principal.id, false } #{h principal}</label>\n" 320 s << "<label>#{ check_box_tag name, principal.id, false, :id => nil } #{h principal}</label>\n"
313 end 321 end
314 s.html_safe 322 s.html_safe
315 end 323 end
316 324
317 # Returns a string for users/groups option tags 325 # Returns a string for users/groups option tags
333 341
334 # Options for the new membership projects combo-box 342 # Options for the new membership projects combo-box
335 def options_for_membership_project_select(principal, projects) 343 def options_for_membership_project_select(principal, projects)
336 options = content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---") 344 options = content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---")
337 options << project_tree_options_for_select(projects) do |p| 345 options << project_tree_options_for_select(projects) do |p|
338 {:disabled => principal.projects.include?(p)} 346 {:disabled => principal.projects.to_a.include?(p)}
339 end 347 end
340 options 348 options
341 end 349 end
342 350
343 # Truncates and returns the string as a single line 351 # Truncates and returns the string as a single line
387 end 395 end
388 396
389 def to_path_param(path) 397 def to_path_param(path)
390 str = path.to_s.split(%r{[/\\]}).select{|p| !p.blank?}.join("/") 398 str = path.to_s.split(%r{[/\\]}).select{|p| !p.blank?}.join("/")
391 str.blank? ? nil : str 399 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 400 end
446 401
447 def reorder_links(name, url, method = :post) 402 def reorder_links(name, url, method = :post)
448 link_to(image_tag('2uparrow.png', :alt => l(:label_sort_highest)), 403 link_to(image_tag('2uparrow.png', :alt => l(:label_sort_highest)),
449 url.merge({"#{name}[move_to]" => 'highest'}), 404 url.merge({"#{name}[move_to]" => 'highest'}),
514 css << 'action-' + action_name 469 css << 'action-' + action_name
515 css.join(' ') 470 css.join(' ')
516 end 471 end
517 472
518 def accesskey(s) 473 def accesskey(s)
519 Redmine::AccessKeys.key_for s 474 @used_accesskeys ||= []
475 key = Redmine::AccessKeys.key_for(s)
476 return nil if @used_accesskeys.include?(key)
477 @used_accesskeys << key
478 key
520 end 479 end
521 480
522 # Formats text according to system settings. 481 # Formats text according to system settings.
523 # 2 ways to call this method: 482 # 2 ways to call this method:
524 # * with a String: textilizable(text, options) 483 # * with a String: textilizable(text, options)
602 if attachments.present? 561 if attachments.present?
603 text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpe|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m| 562 text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpe|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m|
604 filename, ext, alt, alttext = $1.downcase, $2, $3, $4 563 filename, ext, alt, alttext = $1.downcase, $2, $3, $4
605 # search for the picture in attachments 564 # search for the picture in attachments
606 if found = Attachment.latest_attach(attachments, filename) 565 if found = Attachment.latest_attach(attachments, filename)
607 image_url = url_for :only_path => only_path, :controller => 'attachments', 566 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('"', '') 567 desc = found.description.to_s.gsub('"', '')
610 if !desc.blank? && alttext.blank? 568 if !desc.blank? && alttext.blank?
611 alt = " title=\"#{desc}\" alt=\"#{desc}\"" 569 alt = " title=\"#{desc}\" alt=\"#{desc}\""
612 end 570 end
613 "src=\"#{image_url}\"#{alt}" 571 "src=\"#{image_url}\"#{alt}"
632 text.gsub!(/(!)?(\[\[([^\]\n\|]+)(\|([^\]\n\|]+))?\]\])/) do |m| 590 text.gsub!(/(!)?(\[\[([^\]\n\|]+)(\|([^\]\n\|]+))?\]\])/) do |m|
633 link_project = project 591 link_project = project
634 esc, all, page, title = $1, $2, $3, $5 592 esc, all, page, title = $1, $2, $3, $5
635 if esc.nil? 593 if esc.nil?
636 if page =~ /^([^\:]+)\:(.*)$/ 594 if page =~ /^([^\:]+)\:(.*)$/
637 link_project = Project.find_by_identifier($1) || Project.find_by_name($1) 595 identifier, page = $1, $2
638 page = $2 596 link_project = Project.find_by_identifier(identifier) || Project.find_by_name(identifier)
639 title ||= $1 if page.blank? 597 title ||= identifier if page.blank?
640 end 598 end
641 599
642 if link_project && link_project.wiki 600 if link_project && link_project.wiki
643 # extract anchor 601 # extract anchor
644 anchor = nil 602 anchor = nil
799 repository = project.repositories.detect {|repo| repo.identifier == repo_identifier} 757 repository = project.repositories.detect {|repo| repo.identifier == repo_identifier}
800 else 758 else
801 repository = project.repository 759 repository = project.repository
802 end 760 end
803 if prefix == 'commit' 761 if prefix == 'commit'
804 if repository && (changeset = Changeset.visible.find(:first, :conditions => ["repository_id = ? AND scmid LIKE ?", repository.id, "#{name}%"])) 762 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}, 763 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', 764 :class => 'changeset',
807 :title => truncate_single_line(h(changeset.comments), :length => 100) 765 :title => truncate_single_line(changeset.comments, :length => 100)
808 end 766 end
809 else 767 else
810 if repository && User.current.allowed_to?(:browse_repository, project) 768 if repository && User.current.allowed_to?(:browse_repository, project)
811 name =~ %r{^[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?$} 769 name =~ %r{^[/\\]*(.*?)(@([^/\\@]+?))?(#(L\d+))?$}
812 path, rev, anchor = $1, $3, $5 770 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, 771 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), 772 :path => to_path_param(path),
815 :rev => rev, 773 :rev => rev,
816 :anchor => anchor}, 774 :anchor => anchor},
820 repo_prefix = nil 778 repo_prefix = nil
821 end 779 end
822 when 'attachment' 780 when 'attachment'
823 attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil) 781 attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil)
824 if attachments && attachment = Attachment.latest_attach(attachments, name) 782 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}, 783 link = link_to_attachment(attachment, :only_path => only_path, :download => true, :class => 'attachment')
826 :class => 'attachment'
827 end 784 end
828 when 'project' 785 when 'project'
829 if p = Project.visible.find(:first, :conditions => ["identifier = :s OR LOWER(name) = :s", {:s => name.downcase}]) 786 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') 787 link = link_to_project(p, {:only_path => only_path}, :class => 'project')
831 end 788 end
832 end 789 end
833 end 790 end
834 end 791 end
1077 content_tag('tr', 1034 content_tag('tr',
1078 (pcts[0] > 0 ? content_tag('td', '', :style => "width: #{pcts[0]}%;", :class => 'closed') : ''.html_safe) + 1035 (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) + 1036 (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) 1037 (pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2]}%;", :class => 'todo') : ''.html_safe)
1081 ), :class => 'progress', :style => "width: #{width};").html_safe + 1038 ), :class => 'progress', :style => "width: #{width};").html_safe +
1082 content_tag('p', legend, :class => 'pourcent').html_safe 1039 content_tag('p', legend, :class => 'percent').html_safe
1083 end 1040 end
1084 1041
1085 def checked_image(checked=true) 1042 def checked_image(checked=true)
1086 if checked 1043 if checked
1087 image_tag 'toggle_check.png' 1044 image_tag 'toggle_check.png'
1121 1078
1122 tags = javascript_tag( 1079 tags = javascript_tag(
1123 "var datepickerOptions={dateFormat: 'yy-mm-dd', firstDay: #{start_of_week}, " + 1080 "var datepickerOptions={dateFormat: 'yy-mm-dd', firstDay: #{start_of_week}, " +
1124 "showOn: 'button', buttonImageOnly: true, buttonImage: '" + 1081 "showOn: 'button', buttonImageOnly: true, buttonImage: '" +
1125 path_to_image('/images/calendar.png') + 1082 path_to_image('/images/calendar.png') +
1126 "', showButtonPanel: true};") 1083 "', showButtonPanel: true, showWeek: true, showOtherMonths: true, selectOtherMonths: true};")
1127 jquery_locale = l('jquery.locale', :default => current_language.to_s) 1084 jquery_locale = l('jquery.locale', :default => current_language.to_s)
1128 unless jquery_locale == 'en' 1085 unless jquery_locale == 'en'
1129 tags << javascript_include_tag("i18n/jquery.ui.datepicker-#{jquery_locale}.js") 1086 tags << javascript_include_tag("i18n/jquery.ui.datepicker-#{jquery_locale}.js")
1130 end 1087 end
1131 tags 1088 tags
1225 end 1182 end
1226 end 1183 end
1227 1184
1228 def sanitize_anchor_name(anchor) 1185 def sanitize_anchor_name(anchor)
1229 if ''.respond_to?(:encoding) || RUBY_PLATFORM == 'java' 1186 if ''.respond_to?(:encoding) || RUBY_PLATFORM == 'java'
1230 anchor.gsub(%r{[^\p{Word}\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-') 1187 anchor.gsub(%r{[^\s\-\p{Word}]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
1231 else 1188 else
1232 # TODO: remove when ruby1.8 is no longer supported 1189 # TODO: remove when ruby1.8 is no longer supported
1233 anchor.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-') 1190 anchor.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
1234 end 1191 end
1235 end 1192 end
1236 1193
1237 # Returns the javascript tags that are included in the html layout head 1194 # Returns the javascript tags that are included in the html layout head
1238 def javascript_heads 1195 def javascript_heads
1239 tags = javascript_include_tag('jquery-1.7.2-ui-1.8.21-ujs-2.0.3', 'application') 1196 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' 1197 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)}'); });") 1198 tags << "\n".html_safe + javascript_tag("$(window).load(function(){ warnLeavingUnsaved('#{escape_javascript l(:text_warn_on_leaving_unsaved)}'); });")
1242 end 1199 end
1243 tags 1200 tags
1244 end 1201 end