Mercurial > hg > soundsoftware-site
comparison app/helpers/application_helper.rb @ 1298:4f746d8966dd redmine_2.3_integration
Merge from redmine-2.3 branch to create new branch redmine-2.3-integration
author | Chris Cannam |
---|---|
date | Fri, 14 Jun 2013 09:28:30 +0100 |
parents | 0a574315af3e 622f24f53b42 |
children |
comparison
equal
deleted
inserted
replaced
1297:0a574315af3e | 1298:4f746d8966dd |
---|---|
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 |
339 | 347 |
340 # Options for the new membership projects combo-box | 348 # Options for the new membership projects combo-box |
341 def options_for_membership_project_select(principal, projects) | 349 def options_for_membership_project_select(principal, projects) |
342 options = content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---") | 350 options = content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---") |
343 options << project_tree_options_for_select(projects) do |p| | 351 options << project_tree_options_for_select(projects) do |p| |
344 {:disabled => principal.projects.include?(p)} | 352 {:disabled => principal.projects.to_a.include?(p)} |
345 end | 353 end |
346 options | 354 options |
347 end | 355 end |
348 | 356 |
349 # Truncates and returns the string as a single line | 357 # Truncates and returns the string as a single line |
393 end | 401 end |
394 | 402 |
395 def to_path_param(path) | 403 def to_path_param(path) |
396 str = path.to_s.split(%r{[/\\]}).select{|p| !p.blank?}.join("/") | 404 str = path.to_s.split(%r{[/\\]}).select{|p| !p.blank?}.join("/") |
397 str.blank? ? nil : str | 405 str.blank? ? nil : str |
398 end | |
399 | |
400 def pagination_links_full(paginator, count=nil, options={}) | |
401 page_param = options.delete(:page_param) || :page | |
402 per_page_links = options.delete(:per_page_links) | |
403 url_param = params.dup | |
404 | |
405 html = '' | |
406 if paginator.current.previous | |
407 # \xc2\xab(utf-8) = « | |
408 html << link_to_content_update( | |
409 "\xc2\xab " + l(:label_previous), | |
410 url_param.merge(page_param => paginator.current.previous)) + ' ' | |
411 end | |
412 | |
413 html << (pagination_links_each(paginator, options) do |n| | |
414 link_to_content_update(n.to_s, url_param.merge(page_param => n)) | |
415 end || '') | |
416 | |
417 if paginator.current.next | |
418 # \xc2\xbb(utf-8) = » | |
419 html << ' ' + link_to_content_update( | |
420 (l(:label_next) + " \xc2\xbb"), | |
421 url_param.merge(page_param => paginator.current.next)) | |
422 end | |
423 | |
424 unless count.nil? | |
425 html << " (#{paginator.current.first_item}-#{paginator.current.last_item}/#{count})" | |
426 if per_page_links != false && links = per_page_links(paginator.items_per_page, count) | |
427 html << " | #{links}" | |
428 end | |
429 end | |
430 | |
431 html.html_safe | |
432 end | |
433 | |
434 def per_page_links(selected=nil, item_count=nil) | |
435 values = Setting.per_page_options_array | |
436 if item_count && values.any? | |
437 if item_count > values.first | |
438 max = values.detect {|value| value >= item_count} || item_count | |
439 else | |
440 max = item_count | |
441 end | |
442 values = values.select {|value| value <= max || value == selected} | |
443 end | |
444 if values.empty? || (values.size == 1 && values.first == selected) | |
445 return nil | |
446 end | |
447 links = values.collect do |n| | |
448 n == selected ? n : link_to_content_update(n, params.merge(:per_page => n)) | |
449 end | |
450 l(:label_display_per_page, links.join(', ')) | |
451 end | 406 end |
452 | 407 |
453 def reorder_links(name, url, method = :post) | 408 def reorder_links(name, url, method = :post) |
454 link_to(image_tag('2uparrow.png', :alt => l(:label_sort_highest)), | 409 link_to(image_tag('2uparrow.png', :alt => l(:label_sort_highest)), |
455 url.merge({"#{name}[move_to]" => 'highest'}), | 410 url.merge({"#{name}[move_to]" => 'highest'}), |
527 css << 'action-' + action_name | 482 css << 'action-' + action_name |
528 css.join(' ') | 483 css.join(' ') |
529 end | 484 end |
530 | 485 |
531 def accesskey(s) | 486 def accesskey(s) |
532 Redmine::AccessKeys.key_for s | 487 @used_accesskeys ||= [] |
488 key = Redmine::AccessKeys.key_for(s) | |
489 return nil if @used_accesskeys.include?(key) | |
490 @used_accesskeys << key | |
491 key | |
533 end | 492 end |
534 | 493 |
535 # Formats text according to system settings. | 494 # Formats text according to system settings. |
536 # 2 ways to call this method: | 495 # 2 ways to call this method: |
537 # * with a String: textilizable(text, options) | 496 # * with a String: textilizable(text, options) |
615 if attachments.present? | 574 if attachments.present? |
616 text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpe|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m| | 575 text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpe|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m| |
617 filename, ext, alt, alttext = $1.downcase, $2, $3, $4 | 576 filename, ext, alt, alttext = $1.downcase, $2, $3, $4 |
618 # search for the picture in attachments | 577 # search for the picture in attachments |
619 if found = Attachment.latest_attach(attachments, filename) | 578 if found = Attachment.latest_attach(attachments, filename) |
620 image_url = url_for :only_path => only_path, :controller => 'attachments', | 579 image_url = download_named_attachment_path(found, found.filename, :only_path => only_path) |
621 :action => 'download', :id => found | |
622 desc = found.description.to_s.gsub('"', '') | 580 desc = found.description.to_s.gsub('"', '') |
623 if !desc.blank? && alttext.blank? | 581 if !desc.blank? && alttext.blank? |
624 alt = " title=\"#{desc}\" alt=\"#{desc}\"" | 582 alt = " title=\"#{desc}\" alt=\"#{desc}\"" |
625 end | 583 end |
626 "src=\"#{image_url}\"#{alt}" | 584 "src=\"#{image_url}\"#{alt}" |
645 text.gsub!(/(!)?(\[\[([^\]\n\|]+)(\|([^\]\n\|]+))?\]\])/) do |m| | 603 text.gsub!(/(!)?(\[\[([^\]\n\|]+)(\|([^\]\n\|]+))?\]\])/) do |m| |
646 link_project = project | 604 link_project = project |
647 esc, all, page, title = $1, $2, $3, $5 | 605 esc, all, page, title = $1, $2, $3, $5 |
648 if esc.nil? | 606 if esc.nil? |
649 if page =~ /^([^\:]+)\:(.*)$/ | 607 if page =~ /^([^\:]+)\:(.*)$/ |
650 link_project = Project.find_by_identifier($1) || Project.find_by_name($1) | 608 identifier, page = $1, $2 |
651 page = $2 | 609 link_project = Project.find_by_identifier(identifier) || Project.find_by_name(identifier) |
652 title ||= $1 if page.blank? | 610 title ||= identifier if page.blank? |
653 end | 611 end |
654 | 612 |
655 if link_project && link_project.wiki | 613 if link_project && link_project.wiki |
656 # extract anchor | 614 # extract anchor |
657 anchor = nil | 615 anchor = nil |
812 repository = project.repositories.detect {|repo| repo.identifier == repo_identifier} | 770 repository = project.repositories.detect {|repo| repo.identifier == repo_identifier} |
813 else | 771 else |
814 repository = project.repository | 772 repository = project.repository |
815 end | 773 end |
816 if prefix == 'commit' | 774 if prefix == 'commit' |
817 if repository && (changeset = Changeset.visible.find(:first, :conditions => ["repository_id = ? AND scmid LIKE ?", repository.id, "#{name}%"])) | 775 if repository && (changeset = Changeset.visible.where("repository_id = ? AND scmid LIKE ?", repository.id, "#{name}%").first) |
818 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}, | 776 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}, |
819 :class => 'changeset', | 777 :class => 'changeset', |
820 :title => truncate_single_line(h(changeset.comments), :length => 100) | 778 :title => truncate_single_line(changeset.comments, :length => 100) |
821 end | 779 end |
822 else | 780 else |
823 if repository && User.current.allowed_to?(:browse_repository, project) | 781 if repository && User.current.allowed_to?(:browse_repository, project) |
824 name =~ %r{^[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?$} | 782 name =~ %r{^[/\\]*(.*?)(@([^/\\@]+?))?(#(L\d+))?$} |
825 path, rev, anchor = $1, $3, $5 | 783 path, rev, anchor = $1, $3, $5 |
826 link = link_to h("#{project_prefix}#{prefix}:#{repo_prefix}#{name}"), {:controller => 'repositories', :action => (prefix == 'export' ? 'raw' : 'entry'), :id => project, :repository_id => repository.identifier_param, | 784 link = link_to h("#{project_prefix}#{prefix}:#{repo_prefix}#{name}"), {:controller => 'repositories', :action => (prefix == 'export' ? 'raw' : 'entry'), :id => project, :repository_id => repository.identifier_param, |
827 :path => to_path_param(path), | 785 :path => to_path_param(path), |
828 :rev => rev, | 786 :rev => rev, |
829 :anchor => anchor}, | 787 :anchor => anchor}, |
833 repo_prefix = nil | 791 repo_prefix = nil |
834 end | 792 end |
835 when 'attachment' | 793 when 'attachment' |
836 attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil) | 794 attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil) |
837 if attachments && attachment = Attachment.latest_attach(attachments, name) | 795 if attachments && attachment = Attachment.latest_attach(attachments, name) |
838 link = link_to h(attachment.filename), {:only_path => only_path, :controller => 'attachments', :action => 'download', :id => attachment}, | 796 link = link_to_attachment(attachment, :only_path => only_path, :download => true, :class => 'attachment') |
839 :class => 'attachment' | |
840 end | 797 end |
841 when 'project' | 798 when 'project' |
842 if p = Project.visible.find(:first, :conditions => ["identifier = :s OR LOWER(name) = :s", {:s => name.downcase}]) | 799 if p = Project.visible.where("identifier = :s OR LOWER(name) = :s", :s => name.downcase).first |
843 link = link_to_project(p, {:only_path => only_path}, :class => 'project') | 800 link = link_to_project(p, {:only_path => only_path}, :class => 'project') |
844 end | 801 end |
845 end | 802 end |
846 end | 803 end |
847 end | 804 end |
1090 content_tag('tr', | 1047 content_tag('tr', |
1091 (pcts[0] > 0 ? content_tag('td', '', :style => "width: #{pcts[0]}%;", :class => 'closed') : ''.html_safe) + | 1048 (pcts[0] > 0 ? content_tag('td', '', :style => "width: #{pcts[0]}%;", :class => 'closed') : ''.html_safe) + |
1092 (pcts[1] > 0 ? content_tag('td', '', :style => "width: #{pcts[1]}%;", :class => 'done') : ''.html_safe) + | 1049 (pcts[1] > 0 ? content_tag('td', '', :style => "width: #{pcts[1]}%;", :class => 'done') : ''.html_safe) + |
1093 (pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2]}%;", :class => 'todo') : ''.html_safe) | 1050 (pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2]}%;", :class => 'todo') : ''.html_safe) |
1094 ), :class => 'progress', :style => "width: #{width};").html_safe + | 1051 ), :class => 'progress', :style => "width: #{width};").html_safe + |
1095 content_tag('p', legend, :class => 'pourcent').html_safe | 1052 content_tag('p', legend, :class => 'percent').html_safe |
1096 end | 1053 end |
1097 | 1054 |
1098 def checked_image(checked=true) | 1055 def checked_image(checked=true) |
1099 if checked | 1056 if checked |
1100 image_tag 'toggle_check.png' | 1057 image_tag 'toggle_check.png' |
1134 | 1091 |
1135 tags = javascript_tag( | 1092 tags = javascript_tag( |
1136 "var datepickerOptions={dateFormat: 'yy-mm-dd', firstDay: #{start_of_week}, " + | 1093 "var datepickerOptions={dateFormat: 'yy-mm-dd', firstDay: #{start_of_week}, " + |
1137 "showOn: 'button', buttonImageOnly: true, buttonImage: '" + | 1094 "showOn: 'button', buttonImageOnly: true, buttonImage: '" + |
1138 path_to_image('/images/calendar.png') + | 1095 path_to_image('/images/calendar.png') + |
1139 "', showButtonPanel: true};") | 1096 "', showButtonPanel: true, showWeek: true, showOtherMonths: true, selectOtherMonths: true};") |
1140 jquery_locale = l('jquery.locale', :default => current_language.to_s) | 1097 jquery_locale = l('jquery.locale', :default => current_language.to_s) |
1141 unless jquery_locale == 'en' | 1098 unless jquery_locale == 'en' |
1142 tags << javascript_include_tag("i18n/jquery.ui.datepicker-#{jquery_locale}.js") | 1099 tags << javascript_include_tag("i18n/jquery.ui.datepicker-#{jquery_locale}.js") |
1143 end | 1100 end |
1144 tags | 1101 tags |
1238 end | 1195 end |
1239 end | 1196 end |
1240 | 1197 |
1241 def sanitize_anchor_name(anchor) | 1198 def sanitize_anchor_name(anchor) |
1242 if ''.respond_to?(:encoding) || RUBY_PLATFORM == 'java' | 1199 if ''.respond_to?(:encoding) || RUBY_PLATFORM == 'java' |
1243 anchor.gsub(%r{[^\p{Word}\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-') | 1200 anchor.gsub(%r{[^\s\-\p{Word}]}, '').gsub(%r{\s+(\-+\s*)?}, '-') |
1244 else | 1201 else |
1245 # TODO: remove when ruby1.8 is no longer supported | 1202 # TODO: remove when ruby1.8 is no longer supported |
1246 anchor.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-') | 1203 anchor.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-') |
1247 end | 1204 end |
1248 end | 1205 end |
1249 | 1206 |
1250 # Returns the javascript tags that are included in the html layout head | 1207 # Returns the javascript tags that are included in the html layout head |
1251 def javascript_heads | 1208 def javascript_heads |
1252 tags = javascript_include_tag('jquery-1.7.2-ui-1.8.21-ujs-2.0.3', 'application') | 1209 tags = javascript_include_tag('jquery-1.8.3-ui-1.9.2-ujs-2.0.3', 'application') |
1253 unless User.current.pref.warn_on_leaving_unsaved == '0' | 1210 unless User.current.pref.warn_on_leaving_unsaved == '0' |
1254 tags << "\n".html_safe + javascript_tag("$(window).load(function(){ warnLeavingUnsaved('#{escape_javascript l(:text_warn_on_leaving_unsaved)}'); });") | 1211 tags << "\n".html_safe + javascript_tag("$(window).load(function(){ warnLeavingUnsaved('#{escape_javascript l(:text_warn_on_leaving_unsaved)}'); });") |
1255 end | 1212 end |
1256 tags | 1213 tags |
1257 end | 1214 end |