Revision 441:cbce1fd3b1b7 app/helpers/.svn/text-base
| app/helpers/.svn/text-base/application_helper.rb.svn-base | ||
|---|---|---|
| 1 | 1 |
# Redmine - project management software |
| 2 |
# Copyright (C) 2006-2010 Jean-Philippe Lang
|
|
| 2 |
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
| 3 | 3 |
# |
| 4 | 4 |
# This program is free software; you can redistribute it and/or |
| 5 | 5 |
# modify it under the terms of the GNU General Public License |
| ... | ... | |
| 63 | 63 |
|
| 64 | 64 |
# Displays a link to +issue+ with its subject. |
| 65 | 65 |
# Examples: |
| 66 |
#
|
|
| 66 |
# |
|
| 67 | 67 |
# link_to_issue(issue) # => Defect #6: This is the subject |
| 68 | 68 |
# link_to_issue(issue, :truncate => 6) # => Defect #6: This i... |
| 69 | 69 |
# link_to_issue(issue, :subject => false) # => Defect #6 |
| ... | ... | |
| 80 | 80 |
subject = truncate(subject, :length => options[:truncate]) |
| 81 | 81 |
end |
| 82 | 82 |
end |
| 83 |
s = link_to "#{issue.tracker} ##{issue.id}", {:controller => "issues", :action => "show", :id => issue},
|
|
| 83 |
s = link_to "#{issue.tracker} ##{issue.id}", {:controller => "issues", :action => "show", :id => issue},
|
|
| 84 | 84 |
:class => issue.css_classes, |
| 85 | 85 |
:title => title |
| 86 | 86 |
s << ": #{h subject}" if subject
|
| ... | ... | |
| 109 | 109 |
link_to(text, {:controller => 'repositories', :action => 'revision', :id => project, :rev => rev},
|
| 110 | 110 |
:title => l(:label_revision_id, format_revision(revision))) |
| 111 | 111 |
end |
| 112 |
|
|
| 112 |
|
|
| 113 | 113 |
# Generates a link to a message |
| 114 | 114 |
def link_to_message(message, options={}, html_options = nil)
|
| 115 | 115 |
link_to( |
| ... | ... | |
| 126 | 126 |
|
| 127 | 127 |
# Generates a link to a project if active |
| 128 | 128 |
# Examples: |
| 129 |
#
|
|
| 129 |
# |
|
| 130 | 130 |
# link_to_project(project) # => link to the specified project overview |
| 131 | 131 |
# link_to_project(project, :action=>'settings') # => link to project settings |
| 132 | 132 |
# link_to_project(project, {:only_path => false}, :class => "project") # => 3rd arg adds html options
|
| ... | ... | |
| 160 | 160 |
html_options[:onclick] = "promptToRemote('#{text}', '#{param}', '#{url_for(url)}'); return false;"
|
| 161 | 161 |
link_to name, {}, html_options
|
| 162 | 162 |
end |
| 163 |
|
|
| 163 |
|
|
| 164 | 164 |
def format_activity_title(text) |
| 165 | 165 |
h(truncate_single_line(text, :length => 100)) |
| 166 | 166 |
end |
| 167 |
|
|
| 167 |
|
|
| 168 | 168 |
def format_activity_day(date) |
| 169 | 169 |
date == Date.today ? l(:label_today).titleize : format_date(date) |
| 170 | 170 |
end |
| 171 |
|
|
| 171 |
|
|
| 172 | 172 |
def format_activity_description(text) |
| 173 | 173 |
h(truncate(text.to_s, :length => 120).gsub(%r{[\r\n]*<(pre|code)>.*$}m, '...')).gsub(/[\r\n]+/, "<br />")
|
| 174 | 174 |
end |
| ... | ... | |
| 180 | 180 |
h("#{version.project} - #{version}")
|
| 181 | 181 |
end |
| 182 | 182 |
end |
| 183 |
|
|
| 183 |
|
|
| 184 | 184 |
def due_date_distance_in_words(date) |
| 185 | 185 |
if date |
| 186 | 186 |
l((date < Date.today ? :label_roadmap_overdue : :label_roadmap_due_in), distance_of_date_in_words(Date.today, date)) |
| 187 | 187 |
end |
| 188 | 188 |
end |
| 189 | 189 |
|
| 190 |
def render_page_hierarchy(pages, node=nil) |
|
| 190 |
def render_page_hierarchy(pages, node=nil, options={})
|
|
| 191 | 191 |
content = '' |
| 192 | 192 |
if pages[node] |
| 193 | 193 |
content << "<ul class=\"pages-hierarchy\">\n" |
| 194 | 194 |
pages[node].each do |page| |
| 195 | 195 |
content << "<li>" |
| 196 | 196 |
content << link_to(h(page.pretty_title), {:controller => 'wiki', :action => 'show', :project_id => page.project, :id => page.title},
|
| 197 |
:title => (page.respond_to?(:updated_on) ? l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on)) : nil))
|
|
| 198 |
content << "\n" + render_page_hierarchy(pages, page.id) if pages[page.id] |
|
| 197 |
:title => (options[:timestamp] && page.updated_on ? l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on)) : nil))
|
|
| 198 |
content << "\n" + render_page_hierarchy(pages, page.id, options) if pages[page.id]
|
|
| 199 | 199 |
content << "</li>\n" |
| 200 | 200 |
end |
| 201 | 201 |
content << "</ul>\n" |
| 202 | 202 |
end |
| 203 | 203 |
content |
| 204 | 204 |
end |
| 205 |
|
|
| 205 |
|
|
| 206 | 206 |
# Renders flash messages |
| 207 | 207 |
def render_flash_messages |
| 208 | 208 |
s = '' |
| ... | ... | |
| 211 | 211 |
end |
| 212 | 212 |
s |
| 213 | 213 |
end |
| 214 |
|
|
| 214 |
|
|
| 215 | 215 |
# Renders tabs and their content |
| 216 | 216 |
def render_tabs(tabs) |
| 217 | 217 |
if tabs.any? |
| ... | ... | |
| 220 | 220 |
content_tag 'p', l(:label_no_data), :class => "nodata" |
| 221 | 221 |
end |
| 222 | 222 |
end |
| 223 |
|
|
| 223 |
|
|
| 224 | 224 |
# Renders the project quick-jump box |
| 225 | 225 |
def render_project_jump_box |
| 226 |
# Retrieve them now to avoid a COUNT query
|
|
| 227 |
projects = User.current.projects.all
|
|
| 226 |
return unless User.current.logged?
|
|
| 227 |
projects = User.current.memberships.collect(&:project).compact.uniq
|
|
| 228 | 228 |
if projects.any? |
| 229 | 229 |
s = '<select onchange="if (this.value != \'\') { window.location = this.value; }">' +
|
| 230 | 230 |
"<option value=''>#{ l(:label_jump_to_a_project) }</option>" +
|
| ... | ... | |
| 236 | 236 |
s |
| 237 | 237 |
end |
| 238 | 238 |
end |
| 239 |
|
|
| 239 |
|
|
| 240 | 240 |
def project_tree_options_for_select(projects, options = {})
|
| 241 | 241 |
s = '' |
| 242 | 242 |
project_tree(projects) do |project, level| |
| ... | ... | |
| 252 | 252 |
end |
| 253 | 253 |
s |
| 254 | 254 |
end |
| 255 |
|
|
| 255 |
|
|
| 256 | 256 |
# Yields the given block for each project with its level in the tree |
| 257 | 257 |
# |
| 258 | 258 |
# Wrapper for Project#project_tree |
| 259 | 259 |
def project_tree(projects, &block) |
| 260 | 260 |
Project.project_tree(projects, &block) |
| 261 | 261 |
end |
| 262 |
|
|
| 262 |
|
|
| 263 | 263 |
def project_nested_ul(projects, &block) |
| 264 | 264 |
s = '' |
| 265 | 265 |
if projects.any? |
| ... | ... | |
| 270 | 270 |
else |
| 271 | 271 |
ancestors.pop |
| 272 | 272 |
s << "</li>" |
| 273 |
while (ancestors.any? && !project.is_descendant_of?(ancestors.last))
|
|
| 273 |
while (ancestors.any? && !project.is_descendant_of?(ancestors.last)) |
|
| 274 | 274 |
ancestors.pop |
| 275 | 275 |
s << "</ul></li>\n" |
| 276 | 276 |
end |
| ... | ... | |
| 283 | 283 |
end |
| 284 | 284 |
s |
| 285 | 285 |
end |
| 286 |
|
|
| 286 |
|
|
| 287 | 287 |
def principals_check_box_tags(name, principals) |
| 288 | 288 |
s = '' |
| 289 | 289 |
principals.sort.each do |principal| |
| 290 | 290 |
s << "<label>#{ check_box_tag name, principal.id, false } #{h principal}</label>\n"
|
| 291 | 291 |
end |
| 292 |
s
|
|
| 292 |
s |
|
| 293 | 293 |
end |
| 294 | 294 |
|
| 295 | 295 |
# Truncates and returns the string as a single line |
| 296 | 296 |
def truncate_single_line(string, *args) |
| 297 | 297 |
truncate(string.to_s, *args).gsub(%r{[\r\n]+}m, ' ')
|
| 298 | 298 |
end |
| 299 |
|
|
| 299 |
|
|
| 300 | 300 |
# Truncates at line break after 250 characters or options[:length] |
| 301 | 301 |
def truncate_lines(string, options={})
|
| 302 | 302 |
length = options[:length] || 250 |
| ... | ... | |
| 314 | 314 |
def authoring(created, author, options={})
|
| 315 | 315 |
l(options[:label] || :label_added_time_by, :author => link_to_user(author), :age => time_tag(created)) |
| 316 | 316 |
end |
| 317 |
|
|
| 317 |
|
|
| 318 | 318 |
def time_tag(time) |
| 319 | 319 |
text = distance_of_time_in_words(Time.now, time) |
| 320 | 320 |
if @project |
| ... | ... | |
| 336 | 336 |
page_param = options.delete(:page_param) || :page |
| 337 | 337 |
per_page_links = options.delete(:per_page_links) |
| 338 | 338 |
url_param = params.dup |
| 339 |
# don't reuse query params if filters are present |
|
| 340 |
url_param.merge!(:fields => nil, :values => nil, :operators => nil) if url_param.delete(:set_filter) |
|
| 341 | 339 |
|
| 342 | 340 |
html = '' |
| 343 | 341 |
if paginator.current.previous |
| 344 |
html << link_to_remote_content_update('« ' + l(:label_previous), url_param.merge(page_param => paginator.current.previous)) + ' '
|
|
| 342 |
html << link_to_content_update('« ' + l(:label_previous), url_param.merge(page_param => paginator.current.previous)) + ' '
|
|
| 345 | 343 |
end |
| 346 | 344 |
|
| 347 | 345 |
html << (pagination_links_each(paginator, options) do |n| |
| 348 |
link_to_remote_content_update(n.to_s, url_param.merge(page_param => n))
|
|
| 346 |
link_to_content_update(n.to_s, url_param.merge(page_param => n)) |
|
| 349 | 347 |
end || '') |
| 350 |
|
|
| 348 |
|
|
| 351 | 349 |
if paginator.current.next |
| 352 |
html << ' ' + link_to_remote_content_update((l(:label_next) + ' »'), url_param.merge(page_param => paginator.current.next))
|
|
| 350 |
html << ' ' + link_to_content_update((l(:label_next) + ' »'), url_param.merge(page_param => paginator.current.next)) |
|
| 353 | 351 |
end |
| 354 | 352 |
|
| 355 | 353 |
unless count.nil? |
| ... | ... | |
| 361 | 359 |
|
| 362 | 360 |
html |
| 363 | 361 |
end |
| 364 |
|
|
| 362 |
|
|
| 365 | 363 |
def per_page_links(selected=nil) |
| 366 |
url_param = params.dup |
|
| 367 |
url_param.clear if url_param.has_key?(:set_filter) |
|
| 368 |
|
|
| 369 | 364 |
links = Setting.per_page_options_array.collect do |n| |
| 370 |
n == selected ? n : link_to_remote(n, {:update => "content",
|
|
| 371 |
:url => params.dup.merge(:per_page => n), |
|
| 372 |
:method => :get}, |
|
| 373 |
{:href => url_for(url_param.merge(:per_page => n))})
|
|
| 365 |
n == selected ? n : link_to_content_update(n, params.merge(:per_page => n)) |
|
| 374 | 366 |
end |
| 375 | 367 |
links.size > 1 ? l(:label_display_per_page, links.join(', ')) : nil
|
| 376 | 368 |
end |
| 377 |
|
|
| 369 |
|
|
| 378 | 370 |
def reorder_links(name, url) |
| 379 | 371 |
link_to(image_tag('2uparrow.png', :alt => l(:label_sort_highest)), url.merge({"#{name}[move_to]" => 'highest'}), :method => :post, :title => l(:label_sort_highest)) +
|
| 380 | 372 |
link_to(image_tag('1uparrow.png', :alt => l(:label_sort_higher)), url.merge({"#{name}[move_to]" => 'higher'}), :method => :post, :title => l(:label_sort_higher)) +
|
| ... | ... | |
| 386 | 378 |
elements = args.flatten |
| 387 | 379 |
elements.any? ? content_tag('p', args.join(' » ') + ' » ', :class => 'breadcrumb') : nil
|
| 388 | 380 |
end |
| 389 |
|
|
| 381 |
|
|
| 390 | 382 |
def other_formats_links(&block) |
| 391 | 383 |
concat('<p class="other-formats">' + l(:label_export_to))
|
| 392 | 384 |
yield Redmine::Views::OtherFormatsBuilder.new(self) |
| 393 | 385 |
concat('</p>')
|
| 394 | 386 |
end |
| 395 |
|
|
| 387 |
|
|
| 396 | 388 |
def page_header_title |
| 397 | 389 |
if @project.nil? || @project.new_record? |
| 398 | 390 |
h(Setting.app_title) |
| 399 | 391 |
else |
| 400 | 392 |
b = [] |
| 401 |
ancestors = (@project.root? ? [] : @project.ancestors.visible) |
|
| 393 |
ancestors = (@project.root? ? [] : @project.ancestors.visible.all)
|
|
| 402 | 394 |
if ancestors.any? |
| 403 | 395 |
root = ancestors.shift |
| 404 | 396 |
b << link_to_project(root, {:jump => current_menu_item}, :class => 'root')
|
| ... | ... | |
| 465 | 457 |
only_path = options.delete(:only_path) == false ? false : true |
| 466 | 458 |
|
| 467 | 459 |
text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text, :object => obj, :attribute => attr) { |macro, args| exec_macro(macro, obj, args) }
|
| 468 |
|
|
| 460 |
|
|
| 469 | 461 |
@parsed_headings = [] |
| 470 | 462 |
text = parse_non_pre_blocks(text) do |text| |
| 471 | 463 |
[:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links, :parse_headings].each do |method_name| |
| 472 | 464 |
send method_name, text, project, obj, attr, only_path, options |
| 473 | 465 |
end |
| 474 | 466 |
end |
| 475 |
|
|
| 467 |
|
|
| 476 | 468 |
if @parsed_headings.any? |
| 477 | 469 |
replace_toc(text, @parsed_headings) |
| 478 | 470 |
end |
| 479 |
|
|
| 471 |
|
|
| 480 | 472 |
text |
| 481 | 473 |
end |
| 482 |
|
|
| 474 |
|
|
| 483 | 475 |
def parse_non_pre_blocks(text) |
| 484 | 476 |
s = StringScanner.new(text) |
| 485 | 477 |
tags = [] |
| ... | ... | |
| 508 | 500 |
end |
| 509 | 501 |
parsed |
| 510 | 502 |
end |
| 511 |
|
|
| 503 |
|
|
| 512 | 504 |
def parse_inline_attachments(text, project, obj, attr, only_path, options) |
| 513 | 505 |
# when using an image link, try to use an attachment, if possible |
| 514 | 506 |
if options[:attachments] || (obj && obj.respond_to?(:attachments)) |
| 515 | 507 |
attachments = nil |
| 516 | 508 |
text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m| |
| 517 |
filename, ext, alt, alttext = $1.downcase, $2, $3, $4
|
|
| 509 |
filename, ext, alt, alttext = $1.downcase, $2, $3, $4 |
|
| 518 | 510 |
attachments ||= (options[:attachments] || obj.attachments).sort_by(&:created_on).reverse |
| 519 | 511 |
# search for the picture in attachments |
| 520 | 512 |
if found = attachments.detect { |att| att.filename.downcase == filename }
|
| ... | ... | |
| 577 | 569 |
end |
| 578 | 570 |
end |
| 579 | 571 |
end |
| 580 |
|
|
| 572 |
|
|
| 581 | 573 |
# Redmine links |
| 582 | 574 |
# |
| 583 | 575 |
# Examples: |
| ... | ... | |
| 700 | 692 |
leading + (link || "#{project_prefix}#{prefix}#{sep}#{identifier}")
|
| 701 | 693 |
end |
| 702 | 694 |
end |
| 703 |
|
|
| 695 |
|
|
| 704 | 696 |
HEADING_RE = /<h(1|2|3|4)( [^>]+)?>(.+?)<\/h(1|2|3|4)>/i unless const_defined?(:HEADING_RE) |
| 705 |
|
|
| 697 |
|
|
| 706 | 698 |
# Headings and TOC |
| 707 | 699 |
# Adds ids and links to headings unless options[:headings] is set to false |
| 708 | 700 |
def parse_headings(text, project, obj, attr, only_path, options) |
| 709 | 701 |
return if options[:headings] == false |
| 710 |
|
|
| 702 |
|
|
| 711 | 703 |
text.gsub!(HEADING_RE) do |
| 712 | 704 |
level, attrs, content = $1.to_i, $2, $3 |
| 713 | 705 |
item = strip_tags(content).strip |
| 714 | 706 |
anchor = item.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
|
| 715 | 707 |
@parsed_headings << [level, anchor, item] |
| 716 |
"<h#{level} #{attrs} id=\"#{anchor}\">#{content}<a href=\"##{anchor}\" class=\"wiki-anchor\">¶</a></h#{level}>"
|
|
| 708 |
"<a name=\"#{anchor}\"></a>\n<h#{level} #{attrs}>#{content}<a href=\"##{anchor}\" class=\"wiki-anchor\">¶</a></h#{level}>"
|
|
| 717 | 709 |
end |
| 718 | 710 |
end |
| 719 |
|
|
| 711 |
|
|
| 720 | 712 |
TOC_RE = /<p>\{\{([<>]?)toc\}\}<\/p>/i unless const_defined?(:TOC_RE)
|
| 721 |
|
|
| 713 |
|
|
| 722 | 714 |
# Renders the TOC with given headings |
| 723 | 715 |
def replace_toc(text, headings) |
| 724 | 716 |
text.gsub!(TOC_RE) do |
| ... | ... | |
| 801 | 793 |
), :class => 'progress', :style => "width: #{width};") +
|
| 802 | 794 |
content_tag('p', legend, :class => 'pourcent')
|
| 803 | 795 |
end |
| 804 |
|
|
| 796 |
|
|
| 805 | 797 |
def checked_image(checked=true) |
| 806 | 798 |
if checked |
| 807 | 799 |
image_tag 'toggle_check.png' |
| 808 | 800 |
end |
| 809 | 801 |
end |
| 810 |
|
|
| 802 |
|
|
| 811 | 803 |
def context_menu(url) |
| 812 | 804 |
unless @context_menu_included |
| 813 | 805 |
content_for :header_tags do |
| ... | ... | |
| 855 | 847 |
'Calendar._FD = 1;' # Monday |
| 856 | 848 |
when 7 |
| 857 | 849 |
'Calendar._FD = 0;' # Sunday |
| 850 |
when 6 |
|
| 851 |
'Calendar._FD = 6;' # Saturday |
|
| 858 | 852 |
else |
| 859 | 853 |
'' # use language |
| 860 | 854 |
end |
| 861 |
|
|
| 855 |
|
|
| 862 | 856 |
javascript_include_tag('calendar/calendar') +
|
| 863 | 857 |
javascript_include_tag("calendar/lang/calendar-#{current_language.to_s.downcase}.js") +
|
| 864 |
javascript_tag(start_of_week) +
|
|
| 858 |
javascript_tag(start_of_week) + |
|
| 865 | 859 |
javascript_include_tag('calendar/calendar-setup') +
|
| 866 | 860 |
stylesheet_link_tag('calendar')
|
| 867 | 861 |
end |
| ... | ... | |
| 894 | 888 |
'' |
| 895 | 889 |
end |
| 896 | 890 |
end |
| 897 |
|
|
| 891 |
|
|
| 898 | 892 |
# Returns the javascript tags that are included in the html layout head |
| 899 | 893 |
def javascript_heads |
| 900 | 894 |
tags = javascript_include_tag(:defaults) |
| ... | ... | |
| 907 | 901 |
def favicon |
| 908 | 902 |
"<link rel='shortcut icon' href='#{image_path('/favicon.ico')}' />"
|
| 909 | 903 |
end |
| 910 |
|
|
| 904 |
|
|
| 905 |
def robot_exclusion_tag |
|
| 906 |
'<meta name="robots" content="noindex,follow,noarchive" />' |
|
| 907 |
end |
|
| 908 |
|
|
| 911 | 909 |
# Returns true if arg is expected in the API response |
| 912 | 910 |
def include_in_api_response?(arg) |
| 913 | 911 |
unless @included_in_api_response |
| ... | ... | |
| 929 | 927 |
options |
| 930 | 928 |
end |
| 931 | 929 |
end |
| 932 |
|
|
| 930 |
|
|
| 933 | 931 |
private |
| 934 | 932 |
|
| 935 | 933 |
def wiki_helper |
| ... | ... | |
| 937 | 935 |
extend helper |
| 938 | 936 |
return self |
| 939 | 937 |
end |
| 940 |
|
|
| 941 |
def link_to_remote_content_update(text, url_params) |
|
| 942 |
link_to_remote(text, |
|
| 943 |
{:url => url_params, :method => :get, :update => 'content', :complete => 'window.scrollTo(0,0)'},
|
|
| 944 |
{:href => url_for(:params => url_params)}
|
|
| 945 |
) |
|
| 938 |
|
|
| 939 |
def link_to_content_update(text, url_params = {}, html_options = {})
|
|
| 940 |
link_to(text, url_params, html_options) |
|
| 946 | 941 |
end |
| 947 |
|
|
| 948 | 942 |
end |
| app/helpers/.svn/text-base/attachments_helper.rb.svn-base | ||
|---|---|---|
| 1 |
# redMine - project management software
|
|
| 2 |
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
|
| 1 |
# Redmine - project management software
|
|
| 2 |
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
| 3 | 3 |
# |
| 4 | 4 |
# This program is free software; you can redistribute it and/or |
| 5 | 5 |
# modify it under the terms of the GNU General Public License |
| 6 | 6 |
# as published by the Free Software Foundation; either version 2 |
| 7 | 7 |
# of the License, or (at your option) any later version. |
| 8 |
#
|
|
| 8 |
# |
|
| 9 | 9 |
# This program is distributed in the hope that it will be useful, |
| 10 | 10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | 11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | 12 |
# GNU General Public License for more details. |
| 13 |
#
|
|
| 13 |
# |
|
| 14 | 14 |
# You should have received a copy of the GNU General Public License |
| 15 | 15 |
# along with this program; if not, write to the Free Software |
| 16 | 16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| ... | ... | |
| 21 | 21 |
# :author -- author names are not displayed if set to false |
| 22 | 22 |
def link_to_attachments(container, options = {})
|
| 23 | 23 |
options.assert_valid_keys(:author) |
| 24 |
|
|
| 24 |
|
|
| 25 | 25 |
if container.attachments.any? |
| 26 | 26 |
options = {:deletable => container.attachments_deletable?, :author => true}.merge(options)
|
| 27 | 27 |
render :partial => 'attachments/links', :locals => {:attachments => container.attachments, :options => options}
|
| 28 | 28 |
end |
| 29 | 29 |
end |
| 30 |
|
|
| 30 |
|
|
| 31 | 31 |
def to_utf8(str) |
| 32 | 32 |
if str.respond_to?(:force_encoding) |
| 33 | 33 |
str.force_encoding('UTF-8')
|
| ... | ... | |
| 35 | 35 |
else |
| 36 | 36 |
return str if /\A[\r\n\t\x20-\x7e]*\Z/n.match(str) # for us-ascii |
| 37 | 37 |
end |
| 38 |
|
|
| 38 |
|
|
| 39 | 39 |
begin |
| 40 | 40 |
Iconv.conv('UTF-8//IGNORE', 'UTF-8', str + ' ')[0..-3]
|
| 41 | 41 |
rescue Iconv::InvalidEncoding |
| app/helpers/.svn/text-base/calendars_helper.rb.svn-base | ||
|---|---|---|
| 32 | 32 |
end |
| 33 | 33 |
|
| 34 | 34 |
def link_to_month(link_name, year, month, options={})
|
| 35 |
project_id = options[:project].present? ? options[:project].to_param : nil |
|
| 36 |
|
|
| 37 |
link_target = calendar_path(:year => year, :month => month, :project_id => project_id) |
|
| 38 |
|
|
| 39 |
link_to_remote(link_name, |
|
| 40 |
{:update => "content", :url => link_target, :method => :put},
|
|
| 41 |
{:href => link_target})
|
|
| 42 |
|
|
| 35 |
link_to_content_update(link_name, params.merge(:year => year, :month => month)) |
|
| 43 | 36 |
end |
| 44 |
|
|
| 45 | 37 |
end |
| app/helpers/.svn/text-base/custom_fields_helper.rb.svn-base | ||
|---|---|---|
| 1 |
# redMine - project management software
|
|
| 2 |
# Copyright (C) 2006 Jean-Philippe Lang |
|
| 1 |
# Redmine - project management software
|
|
| 2 |
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
| 3 | 3 |
# |
| 4 | 4 |
# This program is free software; you can redistribute it and/or |
| 5 | 5 |
# modify it under the terms of the GNU General Public License |
| ... | ... | |
| 37 | 37 |
field_id = "#{name}_custom_field_values_#{custom_field.id}"
|
| 38 | 38 |
|
| 39 | 39 |
field_format = Redmine::CustomFieldFormat.find_by_name(custom_field.field_format) |
| 40 |
case field_format.edit_as
|
|
| 40 |
case field_format.try(:edit_as)
|
|
| 41 | 41 |
when "date" |
| 42 | 42 |
text_field_tag(field_name, custom_value.value, :id => field_id, :size => 10) + |
| 43 | 43 |
calendar_for(field_id) |
| ... | ... | |
| 49 | 49 |
blank_option = custom_field.is_required? ? |
| 50 | 50 |
(custom_field.default_value.blank? ? "<option value=\"\">--- #{l(:actionview_instancetag_blank_option)} ---</option>" : '') :
|
| 51 | 51 |
'<option></option>' |
| 52 |
select_tag(field_name, blank_option + options_for_select(custom_field.possible_values, custom_value.value), :id => field_id) |
|
| 52 |
select_tag(field_name, blank_option + options_for_select(custom_field.possible_values_options(custom_value.customized), custom_value.value), :id => field_id)
|
|
| 53 | 53 |
else |
| 54 | 54 |
text_field_tag(field_name, custom_value.value, :id => field_id) |
| 55 | 55 |
end |
| ... | ... | |
| 68 | 68 |
custom_field_label_tag(name, custom_value) + custom_field_tag(name, custom_value) |
| 69 | 69 |
end |
| 70 | 70 |
|
| 71 |
def custom_field_tag_for_bulk_edit(name, custom_field) |
|
| 71 |
def custom_field_tag_for_bulk_edit(name, custom_field, projects=nil)
|
|
| 72 | 72 |
field_name = "#{name}[custom_field_values][#{custom_field.id}]"
|
| 73 | 73 |
field_id = "#{name}_custom_field_values_#{custom_field.id}"
|
| 74 | 74 |
field_format = Redmine::CustomFieldFormat.find_by_name(custom_field.field_format) |
| 75 |
case field_format.edit_as
|
|
| 75 |
case field_format.try(:edit_as)
|
|
| 76 | 76 |
when "date" |
| 77 | 77 |
text_field_tag(field_name, '', :id => field_id, :size => 10) + |
| 78 | 78 |
calendar_for(field_id) |
| ... | ... | |
| 83 | 83 |
[l(:general_text_yes), '1'], |
| 84 | 84 |
[l(:general_text_no), '0']]), :id => field_id) |
| 85 | 85 |
when "list" |
| 86 |
select_tag(field_name, options_for_select([[l(:label_no_change_option), '']] + custom_field.possible_values), :id => field_id) |
|
| 86 |
select_tag(field_name, options_for_select([[l(:label_no_change_option), '']] + custom_field.possible_values_options(projects)), :id => field_id)
|
|
| 87 | 87 |
else |
| 88 | 88 |
text_field_tag(field_name, '', :id => field_id) |
| 89 | 89 |
end |
| ... | ... | |
| 101 | 101 |
end |
| 102 | 102 |
|
| 103 | 103 |
# Return an array of custom field formats which can be used in select_tag |
| 104 |
def custom_field_formats_for_select |
|
| 105 |
Redmine::CustomFieldFormat.as_select |
|
| 104 |
def custom_field_formats_for_select(custom_field)
|
|
| 105 |
Redmine::CustomFieldFormat.as_select(custom_field.class.customized_class.name)
|
|
| 106 | 106 |
end |
| 107 | 107 |
|
| 108 | 108 |
# Renders the custom_values in api views |
| app/helpers/.svn/text-base/gantt_helper.rb.svn-base | ||
|---|---|---|
| 1 |
# redMine - project management software
|
|
| 2 |
# Copyright (C) 2006 Jean-Philippe Lang |
|
| 1 |
# Redmine - project management software
|
|
| 2 |
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
| 3 | 3 |
# |
| 4 | 4 |
# This program is free software; you can redistribute it and/or |
| 5 | 5 |
# modify it under the terms of the GNU General Public License |
| ... | ... | |
| 21 | 21 |
case in_or_out |
| 22 | 22 |
when :in |
| 23 | 23 |
if gantt.zoom < 4 |
| 24 |
link_to_remote(l(:text_zoom_in), |
|
| 25 |
{:url => gantt.params.merge(:zoom => (gantt.zoom+1)), :method => :get, :update => 'content'},
|
|
| 26 |
{:href => url_for(gantt.params.merge(:zoom => (gantt.zoom+1))),
|
|
| 27 |
:class => 'icon icon-zoom-in'}) |
|
| 24 |
link_to_content_update l(:text_zoom_in), |
|
| 25 |
params.merge(gantt.params.merge(:zoom => (gantt.zoom+1))), |
|
| 26 |
:class => 'icon icon-zoom-in' |
|
| 28 | 27 |
else |
| 29 | 28 |
content_tag('span', l(:text_zoom_in), :class => 'icon icon-zoom-in')
|
| 30 | 29 |
end |
| 31 | 30 |
|
| 32 | 31 |
when :out |
| 33 | 32 |
if gantt.zoom > 1 |
| 34 |
link_to_remote(l(:text_zoom_out), |
|
| 35 |
{:url => gantt.params.merge(:zoom => (gantt.zoom-1)), :method => :get, :update => 'content'},
|
|
| 36 |
{:href => url_for(gantt.params.merge(:zoom => (gantt.zoom-1))),
|
|
| 37 |
:class => 'icon icon-zoom-out'}) |
|
| 33 |
link_to_content_update l(:text_zoom_out), |
|
| 34 |
params.merge(gantt.params.merge(:zoom => (gantt.zoom-1))), |
|
| 35 |
:class => 'icon icon-zoom-out' |
|
| 38 | 36 |
else |
| 39 | 37 |
content_tag('span', l(:text_zoom_out), :class => 'icon icon-zoom-out')
|
| 40 | 38 |
end |
| 41 | 39 |
end |
| 42 | 40 |
end |
| 43 |
|
|
| 44 |
def number_of_issues_on_versions(gantt) |
|
| 45 |
versions = gantt.events.collect {|event| (event.is_a? Version) ? event : nil}.compact
|
|
| 46 |
|
|
| 47 |
versions.sum {|v| v.fixed_issues.for_gantt.with_query(@query).count}
|
|
| 48 |
end |
|
| 49 | 41 |
end |
| app/helpers/.svn/text-base/issues_helper.rb.svn-base | ||
|---|---|---|
| 5 | 5 |
# modify it under the terms of the GNU General Public License |
| 6 | 6 |
# as published by the Free Software Foundation; either version 2 |
| 7 | 7 |
# of the License, or (at your option) any later version. |
| 8 |
#
|
|
| 8 |
# |
|
| 9 | 9 |
# This program is distributed in the hope that it will be useful, |
| 10 | 10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | 11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | 12 |
# GNU General Public License for more details. |
| 13 |
#
|
|
| 13 |
# |
|
| 14 | 14 |
# You should have received a copy of the GNU General Public License |
| 15 | 15 |
# along with this program; if not, write to the Free Software |
| 16 | 16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| ... | ... | |
| 54 | 54 |
"<strong>#{@cached_label_assigned_to}</strong>: #{issue.assigned_to}<br />" +
|
| 55 | 55 |
"<strong>#{@cached_label_priority}</strong>: #{issue.priority.name}"
|
| 56 | 56 |
end |
| 57 |
|
|
| 57 |
|
|
| 58 |
def issue_heading(issue) |
|
| 59 |
h("#{issue.tracker} ##{issue.id}")
|
|
| 60 |
end |
|
| 61 |
|
|
| 58 | 62 |
def render_issue_subject_with_tree(issue) |
| 59 | 63 |
s = '' |
| 60 |
issue.ancestors.each do |ancestor| |
|
| 64 |
ancestors = issue.root? ? [] : issue.ancestors.visible.all |
|
| 65 |
ancestors.each do |ancestor| |
|
| 61 | 66 |
s << '<div>' + content_tag('p', link_to_issue(ancestor))
|
| 62 | 67 |
end |
| 63 |
s << '<div>' + content_tag('h3', h(issue.subject))
|
|
| 64 |
s << '</div>' * (issue.ancestors.size + 1) |
|
| 68 |
s << '<div>' |
|
| 69 |
subject = h(issue.subject) |
|
| 70 |
if issue.is_private? |
|
| 71 |
subject = content_tag('span', l(:field_is_private), :class => 'private') + ' ' + subject
|
|
| 72 |
end |
|
| 73 |
s << content_tag('h3', subject)
|
|
| 74 |
s << '</div>' * (ancestors.size + 1) |
|
| 65 | 75 |
s |
| 66 | 76 |
end |
| 67 |
|
|
| 77 |
|
|
| 68 | 78 |
def render_descendants_tree(issue) |
| 69 | 79 |
s = '<form><table class="list issues">' |
| 70 |
issue_list(issue.descendants.sort_by(&:lft)) do |child, level| |
|
| 80 |
issue_list(issue.descendants.visible.sort_by(&:lft)) do |child, level|
|
|
| 71 | 81 |
s << content_tag('tr',
|
| 72 | 82 |
content_tag('td', check_box_tag("ids[]", child.id, false, :id => nil), :class => 'checkbox') +
|
| 73 | 83 |
content_tag('td', link_to_issue(child, :truncate => 60), :class => 'subject') +
|
| ... | ... | |
| 79 | 89 |
s << '</form></table>' |
| 80 | 90 |
s |
| 81 | 91 |
end |
| 82 |
|
|
| 92 |
|
|
| 83 | 93 |
def render_custom_fields_rows(issue) |
| 84 | 94 |
return if issue.custom_field_values.empty? |
| 85 | 95 |
ordered_values = [] |
| ... | ... | |
| 98 | 108 |
s << "</tr>\n" |
| 99 | 109 |
s |
| 100 | 110 |
end |
| 101 |
|
|
| 111 |
|
|
| 112 |
def issues_destroy_confirmation_message(issues) |
|
| 113 |
issues = [issues] unless issues.is_a?(Array) |
|
| 114 |
message = l(:text_issues_destroy_confirmation) |
|
| 115 |
descendant_count = issues.inject(0) {|memo, i| memo += (i.right - i.left - 1)/2}
|
|
| 116 |
if descendant_count > 0 |
|
| 117 |
issues.each do |issue| |
|
| 118 |
next if issue.root? |
|
| 119 |
issues.each do |other_issue| |
|
| 120 |
descendant_count -= 1 if issue.is_descendant_of?(other_issue) |
|
| 121 |
end |
|
| 122 |
end |
|
| 123 |
if descendant_count > 0 |
|
| 124 |
message << "\n" + l(:text_issues_destroy_descendants_confirmation, :count => descendant_count) |
|
| 125 |
end |
|
| 126 |
end |
|
| 127 |
message |
|
| 128 |
end |
|
| 129 |
|
|
| 102 | 130 |
def sidebar_queries |
| 103 | 131 |
unless @sidebar_queries |
| 104 | 132 |
# User can see public queries and his own queries |
| 105 | 133 |
visible = ARCondition.new(["is_public = ? OR user_id = ?", true, (User.current.logged? ? User.current.id : 0)]) |
| 106 | 134 |
# Project specific queries and global queries |
| 107 | 135 |
visible << (@project.nil? ? ["project_id IS NULL"] : ["project_id IS NULL OR project_id = ?", @project.id]) |
| 108 |
@sidebar_queries = Query.find(:all,
|
|
| 136 |
@sidebar_queries = Query.find(:all, |
|
| 109 | 137 |
:select => 'id, name, is_public', |
| 110 | 138 |
:order => "name ASC", |
| 111 | 139 |
:conditions => visible.conditions) |
| ... | ... | |
| 116 | 144 |
def query_links(title, queries) |
| 117 | 145 |
# links to #index on issues/show |
| 118 | 146 |
url_params = controller_name == 'issues' ? {:controller => 'issues', :action => 'index', :project_id => @project} : params
|
| 119 |
|
|
| 147 |
|
|
| 120 | 148 |
content_tag('h3', title) +
|
| 121 | 149 |
queries.collect {|query|
|
| 122 | 150 |
link_to(h(query.name), url_params.merge(:query_id => query)) |
| 123 | 151 |
}.join('<br />')
|
| 124 | 152 |
end |
| 125 |
|
|
| 153 |
|
|
| 126 | 154 |
def render_sidebar_queries |
| 127 | 155 |
out = '' |
| 128 | 156 |
queries = sidebar_queries.select {|q| !q.is_public?}
|
| ... | ... | |
| 154 | 182 |
label = l(:field_parent_issue) |
| 155 | 183 |
value = "##{detail.value}" unless detail.value.blank?
|
| 156 | 184 |
old_value = "##{detail.old_value}" unless detail.old_value.blank?
|
| 185 |
|
|
| 186 |
when detail.prop_key == 'is_private' |
|
| 187 |
value = l(detail.value == "0" ? :general_text_No : :general_text_Yes) unless detail.value.blank? |
|
| 188 |
old_value = l(detail.old_value == "0" ? :general_text_No : :general_text_Yes) unless detail.old_value.blank? |
|
| 157 | 189 |
end |
| 158 | 190 |
when 'cf' |
| 159 | 191 |
custom_field = CustomField.find_by_id(detail.prop_key) |
| ... | ... | |
| 170 | 202 |
label ||= detail.prop_key |
| 171 | 203 |
value ||= detail.value |
| 172 | 204 |
old_value ||= detail.old_value |
| 173 |
|
|
| 205 |
|
|
| 174 | 206 |
unless no_html |
| 175 | 207 |
label = content_tag('strong', label)
|
| 176 | 208 |
old_value = content_tag("i", h(old_value)) if detail.old_value
|
| ... | ... | |
| 182 | 214 |
value = content_tag("i", h(value)) if value
|
| 183 | 215 |
end |
| 184 | 216 |
end |
| 185 |
|
|
| 217 |
|
|
| 186 | 218 |
if detail.property == 'attr' && detail.prop_key == 'description' |
| 187 | 219 |
s = l(:text_journal_changed_no_detail, :label => label) |
| 188 | 220 |
unless no_html |
| 189 |
diff_link = link_to 'diff',
|
|
| 221 |
diff_link = link_to 'diff', |
|
| 190 | 222 |
{:controller => 'journals', :action => 'diff', :id => detail.journal_id, :detail_id => detail.id},
|
| 191 | 223 |
:title => l(:label_view_diff) |
| 192 | 224 |
s << " (#{ diff_link })"
|
| ... | ... | |
| 216 | 248 |
return record.name if record |
| 217 | 249 |
end |
| 218 | 250 |
end |
| 219 |
|
|
| 251 |
|
|
| 220 | 252 |
# Renders issue children recursively |
| 221 | 253 |
def render_api_issue_children(issue, api) |
| 222 | 254 |
return if issue.leaf? |
| ... | ... | |
| 230 | 262 |
end |
| 231 | 263 |
end |
| 232 | 264 |
end |
| 233 |
|
|
| 265 |
|
|
| 234 | 266 |
def issues_to_csv(issues, project = nil) |
| 235 |
ic = Iconv.new(l(:general_csv_encoding), 'UTF-8')
|
|
| 267 |
ic = Iconv.new(l(:general_csv_encoding), 'UTF-8') |
|
| 236 | 268 |
decimal_separator = l(:general_csv_decimal_separator) |
| 237 | 269 |
export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv| |
| 238 | 270 |
# csv header fields |
| 239 | 271 |
headers = [ "#", |
| 240 |
l(:field_status),
|
|
| 272 |
l(:field_status), |
|
| 241 | 273 |
l(:field_project), |
| 242 | 274 |
l(:field_tracker), |
| 243 | 275 |
l(:field_priority), |
| ... | ... | |
| 264 | 296 |
# csv lines |
| 265 | 297 |
issues.each do |issue| |
| 266 | 298 |
fields = [issue.id, |
| 267 |
issue.status.name,
|
|
| 299 |
issue.status.name, |
|
| 268 | 300 |
issue.project.name, |
| 269 |
issue.tracker.name,
|
|
| 301 |
issue.tracker.name, |
|
| 270 | 302 |
issue.priority.name, |
| 271 | 303 |
issue.subject, |
| 272 | 304 |
issue.assigned_to, |
| ... | ... | |
| 278 | 310 |
issue.done_ratio, |
| 279 | 311 |
issue.estimated_hours.to_s.gsub('.', decimal_separator),
|
| 280 | 312 |
issue.parent_id, |
| 281 |
format_time(issue.created_on),
|
|
| 313 |
format_time(issue.created_on), |
|
| 282 | 314 |
format_time(issue.updated_on) |
| 283 | 315 |
] |
| 284 | 316 |
custom_fields.each {|f| fields << show_value(issue.custom_value_for(f)) }
|
| app/helpers/.svn/text-base/projects_helper.rb.svn-base | ||
|---|---|---|
| 1 |
# redMine - project management software
|
|
| 2 |
# Copyright (C) 2006 Jean-Philippe Lang |
|
| 1 |
# Redmine - project management software
|
|
| 2 |
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
| 3 | 3 |
# |
| 4 | 4 |
# This program is free software; you can redistribute it and/or |
| 5 | 5 |
# modify it under the terms of the GNU General Public License |
| 6 | 6 |
# as published by the Free Software Foundation; either version 2 |
| 7 | 7 |
# of the License, or (at your option) any later version. |
| 8 |
#
|
|
| 8 |
# |
|
| 9 | 9 |
# This program is distributed in the hope that it will be useful, |
| 10 | 10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | 11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | 12 |
# GNU General Public License for more details. |
| 13 |
#
|
|
| 13 |
# |
|
| 14 | 14 |
# You should have received a copy of the GNU General Public License |
| 15 | 15 |
# along with this program; if not, write to the Free Software |
| 16 | 16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| ... | ... | |
| 20 | 20 |
return '' unless version && version.is_a?(Version) |
| 21 | 21 |
link_to_if version.visible?, format_version_name(version), { :controller => 'versions', :action => 'show', :id => version }, options
|
| 22 | 22 |
end |
| 23 |
|
|
| 23 |
|
|
| 24 | 24 |
def project_settings_tabs |
| 25 | 25 |
tabs = [{:name => 'info', :action => :edit_project, :partial => 'projects/edit', :label => :label_information_plural},
|
| 26 | 26 |
{:name => 'modules', :action => :select_project_modules, :partial => 'projects/settings/modules', :label => :label_module_plural},
|
| ... | ... | |
| 32 | 32 |
{:name => 'boards', :action => :manage_boards, :partial => 'projects/settings/boards', :label => :label_board_plural},
|
| 33 | 33 |
{:name => 'activities', :action => :manage_project_activities, :partial => 'projects/settings/activities', :label => :enumeration_activities}
|
| 34 | 34 |
] |
| 35 |
tabs.select {|tab| User.current.allowed_to?(tab[:action], @project)}
|
|
| 35 |
tabs.select {|tab| User.current.allowed_to?(tab[:action], @project)}
|
|
| 36 | 36 |
end |
| 37 |
|
|
| 37 |
|
|
| 38 | 38 |
def parent_project_select_tag(project) |
| 39 | 39 |
selected = project.parent |
| 40 | 40 |
# retrieve the requested parent project |
| ... | ... | |
| 42 | 42 |
if parent_id |
| 43 | 43 |
selected = (parent_id.blank? ? nil : Project.find(parent_id)) |
| 44 | 44 |
end |
| 45 |
|
|
| 45 |
|
|
| 46 | 46 |
options = '' |
| 47 | 47 |
options << "<option value=''></option>" if project.allowed_parents.include?(nil) |
| 48 | 48 |
options << project_tree_options_for_select(project.allowed_parents.compact, :selected => selected) |
| 49 | 49 |
content_tag('select', options, :name => 'project[parent_id]', :id => 'project_parent_id')
|
| 50 | 50 |
end |
| 51 |
|
|
| 51 |
|
|
| 52 | 52 |
# Renders a tree of projects as a nested set of unordered lists |
| 53 | 53 |
# The given collection may be a subset of the whole project tree |
| 54 | 54 |
# (eg. some intermediate nodes are private and can not be seen) |
| ... | ... | |
| 65 | 65 |
else |
| 66 | 66 |
ancestors.pop |
| 67 | 67 |
s << "</li>" |
| 68 |
while (ancestors.any? && !project.is_descendant_of?(ancestors.last))
|
|
| 68 |
while (ancestors.any? && !project.is_descendant_of?(ancestors.last)) |
|
| 69 | 69 |
ancestors.pop |
| 70 | 70 |
s << "</ul></li>\n" |
| 71 | 71 |
end |
| ... | ... | |
| 93 | 93 |
if selected && !versions.include?(selected) |
| 94 | 94 |
grouped[selected.project.name] << [selected.name, selected.id] |
| 95 | 95 |
end |
| 96 |
|
|
| 96 |
|
|
| 97 | 97 |
if grouped.keys.size > 1 |
| 98 | 98 |
grouped_options_for_select(grouped, selected && selected.id) |
| 99 | 99 |
else |
| app/helpers/.svn/text-base/queries_helper.rb.svn-base | ||
|---|---|---|
| 1 |
# redMine - project management software
|
|
| 2 |
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
|
| 1 |
# Redmine - project management software
|
|
| 2 |
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
| 3 | 3 |
# |
| 4 | 4 |
# This program is free software; you can redistribute it and/or |
| 5 | 5 |
# modify it under the terms of the GNU General Public License |
| ... | ... | |
| 78 | 78 |
# Give it a name, required to be valid |
| 79 | 79 |
@query = Query.new(:name => "_") |
| 80 | 80 |
@query.project = @project |
| 81 |
if params[:fields] |
|
| 81 |
if params[:fields] || params[:f]
|
|
| 82 | 82 |
@query.filters = {}
|
| 83 |
@query.add_filters(params[:fields], params[:operators], params[:values])
|
|
| 83 |
@query.add_filters(params[:fields] || params[:f], params[:operators] || params[:op], params[:values] || params[:v])
|
|
| 84 | 84 |
else |
| 85 | 85 |
@query.available_filters.keys.each do |field| |
| 86 | 86 |
@query.add_short_filter(field, params[field]) if params[field] |
| 87 | 87 |
end |
| 88 | 88 |
end |
| 89 | 89 |
@query.group_by = params[:group_by] |
| 90 |
@query.column_names = params[:query] && params[:query][:column_names]
|
|
| 90 |
@query.column_names = params[:c] || (params[:query] && params[:query][:column_names])
|
|
| 91 | 91 |
session[:query] = {:project_id => @query.project_id, :filters => @query.filters, :group_by => @query.group_by, :column_names => @query.column_names}
|
| 92 | 92 |
else |
| 93 | 93 |
@query = Query.find_by_id(session[:query][:id]) if session[:query][:id] |
| app/helpers/.svn/text-base/reports_helper.rb.svn-base | ||
|---|---|---|
| 1 |
# redMine - project management software
|
|
| 2 |
# Copyright (C) 2006 Jean-Philippe Lang |
|
| 1 |
# Redmine - project management software
|
|
| 2 |
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
| 3 | 3 |
# |
| 4 | 4 |
# This program is free software; you can redistribute it and/or |
| 5 | 5 |
# modify it under the terms of the GNU General Public License |
| 6 | 6 |
# as published by the Free Software Foundation; either version 2 |
| 7 | 7 |
# of the License, or (at your option) any later version. |
| 8 |
#
|
|
| 8 |
# |
|
| 9 | 9 |
# This program is distributed in the hope that it will be useful, |
| 10 | 10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | 11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | 12 |
# GNU General Public License for more details. |
| 13 |
#
|
|
| 13 |
# |
|
| 14 | 14 |
# You should have received a copy of the GNU General Public License |
| 15 | 15 |
# along with this program; if not, write to the Free Software |
| 16 | 16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| 17 | 17 |
|
| 18 | 18 |
module ReportsHelper |
| 19 |
|
|
| 19 |
|
|
| 20 | 20 |
def aggregate(data, criteria) |
| 21 | 21 |
a = 0 |
| 22 | 22 |
data.each { |row|
|
| ... | ... | |
| 28 | 28 |
} unless data.nil? |
| 29 | 29 |
a |
| 30 | 30 |
end |
| 31 |
|
|
| 31 |
|
|
| 32 | 32 |
def aggregate_link(data, criteria, *args) |
| 33 | 33 |
a = aggregate data, criteria |
| 34 | 34 |
a > 0 ? link_to(a, *args) : '-' |
| 35 |
end
|
|
| 35 |
end |
|
| 36 | 36 |
end |
| app/helpers/.svn/text-base/repositories_helper.rb.svn-base | ||
|---|---|---|
| 1 |
# redMine - project management software
|
|
| 2 |
# Copyright (C) 2006 Jean-Philippe Lang |
|
| 1 |
# Redmine - project management software
|
|
| 2 |
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
| 3 | 3 |
# |
| 4 | 4 |
# This program is free software; you can redistribute it and/or |
| 5 | 5 |
# modify it under the terms of the GNU General Public License |
| 6 | 6 |
# as published by the Free Software Foundation; either version 2 |
| 7 | 7 |
# of the License, or (at your option) any later version. |
| 8 |
#
|
|
| 8 |
# |
|
| 9 | 9 |
# This program is distributed in the hope that it will be useful, |
| 10 | 10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | 11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | 12 |
# GNU General Public License for more details. |
| 13 |
#
|
|
| 13 |
# |
|
| 14 | 14 |
# You should have received a copy of the GNU General Public License |
| 15 | 15 |
# along with this program; if not, write to the Free Software |
| 16 | 16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| 17 | 17 |
|
| 18 | 18 |
require 'iconv' |
| 19 |
require 'redmine/codeset_util' |
|
| 19 | 20 |
|
| 20 | 21 |
module RepositoriesHelper |
| 21 | 22 |
def format_revision(revision) |
| ... | ... | |
| 48 | 49 |
when 'A' |
| 49 | 50 |
# Detects moved/copied files |
| 50 | 51 |
if !change.from_path.blank? |
| 51 |
change.action = @changeset.changes.detect {|c| c.action == 'D' && c.path == change.from_path} ? 'R' : 'C'
|
|
| 52 |
change.action = |
|
| 53 |
@changeset.changes.detect {|c| c.action == 'D' && c.path == change.from_path} ? 'R' : 'C'
|
|
| 52 | 54 |
end |
| 53 | 55 |
change |
| 54 | 56 |
when 'D' |
| ... | ... | |
| 56 | 58 |
else |
| 57 | 59 |
change |
| 58 | 60 |
end |
| 59 |
end.compact |
|
| 60 |
|
|
| 61 |
end.compact
|
|
| 62 |
|
|
| 61 | 63 |
tree = { }
|
| 62 | 64 |
changes.each do |change| |
| 63 | 65 |
p = tree |
| ... | ... | |
| 72 | 74 |
end |
| 73 | 75 |
p[:c] = change |
| 74 | 76 |
end |
| 75 |
|
|
| 76 | 77 |
render_changes_tree(tree[:s]) |
| 77 | 78 |
end |
| 78 | 79 |
|
| 79 | 80 |
def render_changes_tree(tree) |
| 80 | 81 |
return '' if tree.nil? |
| 81 |
|
|
| 82 | 82 |
output = '' |
| 83 | 83 |
output << '<ul>' |
| 84 | 84 |
tree.keys.sort.each do |file| |
| ... | ... | |
| 117 | 117 |
end |
| 118 | 118 |
|
| 119 | 119 |
def to_utf8(str) |
| 120 |
return str if str.blank? |
|
| 120 |
return str if str.nil? |
|
| 121 |
str = to_utf8_internal(str) |
|
| 121 | 122 |
if str.respond_to?(:force_encoding) |
| 122 | 123 |
str.force_encoding('UTF-8')
|
| 123 |
else |
|
| 124 |
# TODO: |
|
| 125 |
# Japanese Shift_JIS(CP932) is not compatible with ASCII. |
|
| 126 |
# UTF-7 and Japanese ISO-2022-JP are 7bits clean. |
|
| 127 |
return str if /\A[\r\n\t\x20-\x7e]*\Z/n.match(str) # for us-ascii |
|
| 128 | 124 |
end |
| 125 |
str |
|
| 126 |
end |
|
| 129 | 127 |
|
| 128 |
def to_utf8_internal(str) |
|
| 129 |
return str if str.nil? |
|
| 130 |
if str.respond_to?(:force_encoding) |
|
| 131 |
str.force_encoding('ASCII-8BIT')
|
|
| 132 |
end |
|
| 133 |
return str if str.empty? |
|
| 134 |
return str if /\A[\r\n\t\x20-\x7e]*\Z/n.match(str) # for us-ascii |
|
| 135 |
if str.respond_to?(:force_encoding) |
|
| 136 |
str.force_encoding('UTF-8')
|
|
| 137 |
end |
|
| 130 | 138 |
@encodings ||= Setting.repositories_encodings.split(',').collect(&:strip)
|
| 131 | 139 |
@encodings.each do |encoding| |
| 132 | 140 |
begin |
| ... | ... | |
| 135 | 143 |
# do nothing here and try the next encoding |
| 136 | 144 |
end |
| 137 | 145 |
end |
| 138 |
str = replace_invalid_utf8(str) |
|
| 146 |
str = Redmine::CodesetUtil.replace_invalid_utf8(str)
|
|
| 139 | 147 |
end |
| 140 |
|
|
| 141 |
def replace_invalid_utf8(str) |
|
| 142 |
if str.respond_to?(:force_encoding) |
|
| 143 |
str.force_encoding('UTF-8')
|
|
| 144 |
if ! str.valid_encoding? |
|
| 145 |
str = str.encode("US-ASCII", :invalid => :replace,
|
|
| 146 |
:undef => :replace, :replace => '?').encode("UTF-8")
|
|
| 147 |
end |
|
| 148 |
end |
|
| 149 |
str |
|
| 150 |
end |
|
| 148 |
private :to_utf8_internal |
|
| 151 | 149 |
|
| 152 | 150 |
def repository_field_tags(form, repository) |
| 153 | 151 |
method = repository.class.name.demodulize.underscore + "_field_tags" |
| ... | ... | |
| 165 | 163 |
scm_options << ["Repository::#{scm}".constantize.scm_name, scm]
|
| 166 | 164 |
end |
| 167 | 165 |
end |
| 168 |
select_tag('repository_scm',
|
|
| 166 |
select_tag('repository_scm',
|
|
| 169 | 167 |
options_for_select(scm_options, repository.class.name.demodulize), |
| 170 | 168 |
:disabled => (repository && !repository.new_record?), |
| 171 | 169 |
:onchange => remote_function( |
| 172 | 170 |
:url => {
|
| 173 | 171 |
:controller => 'repositories', |
| 174 |
:action => 'edit', |
|
| 175 |
:id => @project |
|
| 176 |
},
|
|
| 172 |
:action => 'edit',
|
|
| 173 |
:id => @project
|
|
| 174 |
}, |
|
| 177 | 175 |
:method => :get, |
| 178 |
:with => "Form.serialize(this.form)") |
|
| 179 |
)
|
|
| 176 |
:with => "Form.serialize(this.form)")
|
|
| 177 |
) |
|
| 180 | 178 |
end |
| 181 | 179 |
|
| 182 | 180 |
def with_leading_slash(path) |
| ... | ... | |
| 200 | 198 |
end |
| 201 | 199 |
|
| 202 | 200 |
def darcs_field_tags(form, repository) |
| 203 |
content_tag('p', form.text_field(:url, :label => 'Root directory',
|
|
| 204 |
:size => 60, :required => true, |
|
| 205 |
:disabled => (repository && !repository.new_record?))) + |
|
| 206 |
content_tag('p', form.select(:log_encoding, [nil] + Setting::ENCODINGS,
|
|
| 207 |
:label => 'Commit messages encoding', :required => true)) |
|
| 201 |
content_tag('p', form.text_field(
|
|
| 202 |
:url, :label => l(:field_path_to_repository), |
|
| 203 |
:size => 60, :required => true, |
|
| 204 |
:disabled => (repository && !repository.new_record?))) + |
|
| 205 |
content_tag('p', form.select(
|
|
| 206 |
:log_encoding, [nil] + Setting::ENCODINGS, |
|
| 207 |
:label => l(:field_commit_logs_encoding), :required => true)) |
|
| 208 | 208 |
end |
| 209 | 209 |
|
| 210 | 210 |
def mercurial_field_tags(form, repository) |
| 211 |
content_tag('p', form.text_field(:url, :label => 'Root directory',
|
|
| 211 |
content_tag('p', form.text_field(
|
|
| 212 |
:url, :label => l(:field_path_to_repository), |
|
| 212 | 213 |
:size => 60, :required => true, |
| 213 |
:disabled => (repository && !repository.root_url.blank?)) + |
|
| 214 |
'<br />local repository (e.g. /hgrepo, c:\hgrepo)' ) |
|
| 214 |
:disabled => (repository && !repository.root_url.blank?) |
|
| 215 |
) + |
|
| 216 |
'<br />' + l(:text_mercurial_repository_note)) + |
|
| 217 |
content_tag('p', form.select(
|
|
| 218 |
:path_encoding, [nil] + Setting::ENCODINGS, |
|
| 219 |
:label => l(:field_scm_path_encoding) |
|
| 220 |
) + |
|
| 221 |
'<br />' + l(:text_scm_path_encoding_note)) |
|
| 215 | 222 |
end |
| 216 | 223 |
|
| 217 | 224 |
def git_field_tags(form, repository) |
| 218 |
content_tag('p', form.text_field(:url, :label => 'Path to repository',
|
|
| 225 |
content_tag('p', form.text_field(
|
|
| 226 |
:url, :label => l(:field_path_to_repository), |
|
| 219 | 227 |
:size => 60, :required => true, |
| 220 |
:disabled => (repository && !repository.root_url.blank?)) + |
|
| 221 |
'<br />a bare and local repository (e.g. /gitrepo, c:\gitrepo)') |
|
| 228 |
:disabled => (repository && !repository.root_url.blank?) |
|
| 229 |
) + |
|
| 230 |
'<br />' + l(:text_git_repository_note)) + |
|
| 231 |
content_tag('p', form.select(
|
|
| 232 |
:path_encoding, [nil] + Setting::ENCODINGS, |
|
| 233 |
:label => l(:field_scm_path_encoding) |
|
| 234 |
) + |
|
| 235 |
'<br />' + l(:text_scm_path_encoding_note)) + |
|
| 236 |
content_tag('p', form.check_box(
|
|
| 237 |
:extra_report_last_commit, |
|
| 238 |
:label => l(:label_git_report_last_commit) |
|
| 239 |
)) |
|
| 222 | 240 |
end |
| 223 | 241 |
|
| 224 | 242 |
def cvs_field_tags(form, repository) |
| 225 |
content_tag('p', form.text_field(:root_url,
|
|
| 226 |
:label => 'CVSROOT', :size => 60, :required => true, |
|
| 227 |
:disabled => !repository.new_record?)) + |
|
| 228 |
content_tag('p', form.text_field(:url, :label => 'Module',
|
|
| 229 |
:size => 30, :required => true, |
|
| 230 |
:disabled => !repository.new_record?)) + |
|
| 231 |
content_tag('p', form.select(:log_encoding, [nil] + Setting::ENCODINGS,
|
|
| 232 |
:label => 'Commit messages encoding', :required => true)) |
|
| 243 |
content_tag('p', form.text_field(
|
|
| 244 |
:root_url, |
|
| 245 |
:label => l(:field_cvsroot), |
|
| 246 |
:size => 60, :required => true, |
|
| 247 |
:disabled => !repository.new_record?)) + |
|
| 248 |
content_tag('p', form.text_field(
|
|
| 249 |
:url, |
|
| 250 |
:label => l(:field_cvs_module), |
|
| 251 |
:size => 30, :required => true, |
|
| 252 |
:disabled => !repository.new_record?)) + |
|
| 253 |
content_tag('p', form.select(
|
|
| 254 |
:log_encoding, [nil] + Setting::ENCODINGS, |
|
| 255 |
:label => l(:field_commit_logs_encoding), :required => true)) + |
|
| 256 |
content_tag('p', form.select(
|
|
| 257 |
:path_encoding, [nil] + Setting::ENCODINGS, |
|
| 258 |
:label => l(:field_scm_path_encoding) |
|
| 259 |
) + |
|
| 260 |
'<br />' + l(:text_scm_path_encoding_note)) |
|
| 233 | 261 |
end |
| 234 | 262 |
|
| 235 | 263 |
def bazaar_field_tags(form, repository) |
| 236 |
content_tag('p', form.text_field(:url, :label => 'Root directory',
|
|
| 237 |
:size => 60, :required => true, |
|
| 238 |
:disabled => (repository && !repository.new_record?))) + |
|
| 239 |
content_tag('p', form.select(:log_encoding, [nil] + Setting::ENCODINGS,
|
|
| 240 |
:label => 'Commit messages encoding', :required => true)) |
|
| 264 |
content_tag('p', form.text_field(
|
|
| 265 |
:url, :label => l(:field_path_to_repository), |
|
| 266 |
:size => 60, :required => true, |
|
| 267 |
:disabled => (repository && !repository.new_record?))) + |
|
| 268 |
content_tag('p', form.select(
|
|
| 269 |
:log_encoding, [nil] + Setting::ENCODINGS, |
|
| 270 |
:label => l(:field_commit_logs_encoding), :required => true)) |
|
| 241 | 271 |
end |
| 242 | 272 |
|
| 243 | 273 |
def filesystem_field_tags(form, repository) |
| 244 |
content_tag('p', form.text_field(:url, :label => 'Root directory',
|
|
| 274 |
content_tag('p', form.text_field(
|
|
| 275 |
:url, :label => l(:field_root_directory), |
|
| 245 | 276 |
:size => 60, :required => true, |
| 246 | 277 |
:disabled => (repository && !repository.root_url.blank?))) + |
| 247 | 278 |
content_tag('p', form.select(
|
| 248 | 279 |
:path_encoding, [nil] + Setting::ENCODINGS, |
| 249 |
:label => 'Path encoding') + |
|
| 250 |
'<br />Default: UTF-8') |
|
| 280 |
:label => l(:field_scm_path_encoding) |
|
| 281 |
) + |
|
| 282 |
'<br />' + l(:text_scm_path_encoding_note)) |
|
| 251 | 283 |
end |
| 252 | 284 |
end |
| app/helpers/.svn/text-base/settings_helper.rb.svn-base | ||
|---|---|---|
| 1 | 1 |
# Redmine - project management software |
| 2 |
# Copyright (C) 2006-2009 Jean-Philippe Lang
|
|
| 2 |
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
| 3 | 3 |
# |
| 4 | 4 |
# This program is free software; you can redistribute it and/or |
| 5 | 5 |
# modify it under the terms of the GNU General Public License |
| 6 | 6 |
# as published by the Free Software Foundation; either version 2 |
| 7 | 7 |
# of the License, or (at your option) any later version. |
| 8 |
#
|
|
| 8 |
# |
|
| 9 | 9 |
# This program is distributed in the hope that it will be useful, |
| 10 | 10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | 11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | 12 |
# GNU General Public License for more details. |
| 13 |
#
|
|
| 13 |
# |
|
| 14 | 14 |
# You should have received a copy of the GNU General Public License |
| 15 | 15 |
# along with this program; if not, write to the Free Software |
| 16 | 16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| ... | ... | |
| 27 | 27 |
{:name => 'repositories', :partial => 'settings/repositories', :label => :label_repository_plural}
|
| 28 | 28 |
] |
| 29 | 29 |
end |
| 30 |
|
|
| 30 |
|
|
| 31 | 31 |
def setting_select(setting, choices, options={})
|
| 32 | 32 |
if blank_text = options.delete(:blank) |
| 33 | 33 |
choices = [[blank_text.is_a?(Symbol) ? l(blank_text) : blank_text, '']] + choices |
| 34 | 34 |
end |
| 35 | 35 |
setting_label(setting, options) + |
| 36 |
select_tag("settings[#{setting}]", options_for_select(choices, Setting.send(setting).to_s), options)
|
|
| 36 |
select_tag("settings[#{setting}]",
|
|
| 37 |
options_for_select(choices, Setting.send(setting).to_s), |
|
| 38 |
options) |
|
| 37 | 39 |
end |
| 38 |
|
|
| 40 |
|
|
| 39 | 41 |
def setting_multiselect(setting, choices, options={})
|
| 40 | 42 |
setting_values = Setting.send(setting) |
| 41 | 43 |
setting_values = [] unless setting_values.is_a?(Array) |
| 42 |
|
|
| 44 |
|
|
| 43 | 45 |
setting_label(setting, options) + |
| 44 | 46 |
hidden_field_tag("settings[#{setting}][]", '') +
|
| 45 | 47 |
choices.collect do |choice| |
| 46 |
text, value = (choice.is_a?(Array) ? choice : [choice, choice]) |
|
| 47 |
content_tag('label',
|
|
| 48 |
check_box_tag("settings[#{setting}][]", value, Setting.send(setting).include?(value)) + text.to_s,
|
|
| 48 |
text, value = (choice.is_a?(Array) ? choice : [choice, choice]) |
|
| 49 |
content_tag( |
|
| 50 |
'label', |
|
| 51 |
check_box_tag( |
|
| 52 |
"settings[#{setting}][]",
|
|
| 53 |
value, |
|
| 54 |
Setting.send(setting).include?(value) |
|
| 55 |
) + text.to_s, |
|
| 49 | 56 |
:class => 'block' |
| 50 |
) |
|
| 57 |
)
|
|
| 51 | 58 |
end.join |
| 52 | 59 |
end |
| 53 |
|
|
| 60 |
|
|
| 54 | 61 |
def setting_text_field(setting, options={})
|
| 55 | 62 |
setting_label(setting, options) + |
| 56 | 63 |
text_field_tag("settings[#{setting}]", Setting.send(setting), options)
|
| 57 | 64 |
end |
| 58 |
|
|
| 65 |
|
|
| 59 | 66 |
def setting_text_area(setting, options={})
|
| 60 | 67 |
setting_label(setting, options) + |
| 61 | 68 |
text_area_tag("settings[#{setting}]", Setting.send(setting), options)
|
| 62 | 69 |
end |
| 63 |
|
|
| 70 |
|
|
| 64 | 71 |
def setting_check_box(setting, options={})
|
| 65 | 72 |
setting_label(setting, options) + |
| 66 | 73 |
hidden_field_tag("settings[#{setting}]", 0) +
|
| 67 |
check_box_tag("settings[#{setting}]", 1, Setting.send("#{setting}?"), options)
|
|
| 74 |
check_box_tag("settings[#{setting}]", 1, Setting.send("#{setting}?"), options)
|
|
| 68 | 75 |
end |
| 69 |
|
|
| 76 |
|
|
| 70 | 77 |
def setting_label(setting, options={})
|
| 71 | 78 |
label = options.delete(:label) |
| 72 | 79 |
label != false ? content_tag("label", l(label || "setting_#{setting}")) : ''
|
| app/helpers/.svn/text-base/sort_helper.rb.svn-base | ||
|---|---|---|
| 200 | 200 |
caption = column.to_s.humanize unless caption |
| 201 | 201 |
|
| 202 | 202 |
sort_options = { :sort => @sort_criteria.add(column.to_s, order).to_param }
|
| 203 |
# don't reuse params if filters are present |
|
| 204 |
url_options = params.has_key?(:set_filter) ? sort_options : params.merge(sort_options) |
|
| 203 |
url_options = params.merge(sort_options) |
|
| 205 | 204 |
|
| 206 | 205 |
# Add project_id to url_options |
| 207 | 206 |
url_options = url_options.merge(:project_id => params[:project_id]) if params.has_key?(:project_id) |
| 208 | 207 |
|
| 209 |
link_to_remote(caption, |
|
| 210 |
{:update => "content", :url => url_options, :method => :get},
|
|
| 211 |
{:href => url_for(url_options),
|
|
| 212 |
:class => css}) |
|
| 208 |
link_to_content_update(caption, url_options, :class => css) |
|
| 213 | 209 |
end |
| 214 | 210 |
|
| 215 | 211 |
# Returns a table header <th> tag with a sort link for the named column |
| app/helpers/.svn/text-base/versions_helper.rb.svn-base | ||
|---|---|---|
| 1 |
# redMine - project management software
|
|
| 2 |
# Copyright (C) 2006 Jean-Philippe Lang |
|
| 1 |
# Redmine - project management software
|
|
| 2 |
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
| 3 | 3 |
# |
| 4 | 4 |
# This program is free software; you can redistribute it and/or |
| 5 | 5 |
# modify it under the terms of the GNU General Public License |
| ... | ... | |
| 17 | 17 |
|
| 18 | 18 |
module VersionsHelper |
| 19 | 19 |
|
| 20 |
STATUS_BY_CRITERIAS = %w(category tracker priority author assigned_to) |
|
| 20 |
STATUS_BY_CRITERIAS = %w(category tracker status priority author assigned_to)
|
|
| 21 | 21 |
|
| 22 | 22 |
def render_issue_status_by(version, criteria) |
| 23 |
criteria ||= 'category' |
|
| 24 |
raise 'Unknown criteria' unless STATUS_BY_CRITERIAS.include?(criteria) |
|
| 23 |
criteria = 'category' unless STATUS_BY_CRITERIAS.include?(criteria) |
|
| 25 | 24 |
|
| 26 | 25 |
h = Hash.new {|k,v| k[v] = [0, 0]}
|
| 27 | 26 |
begin |
| app/helpers/.svn/text-base/watchers_helper.rb.svn-base | ||
|---|---|---|
| 1 |
# redMine - project management software
|
|
| 2 |
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
|
| 1 |
# Redmine - project management software
|
|
| 2 |
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
| 3 | 3 |
# |
| 4 | 4 |
# This program is free software; you can redistribute it and/or |
| 5 | 5 |
# modify it under the terms of the GNU General Public License |
| ... | ... | |
| 16 | 16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| 17 | 17 |
|
| 18 | 18 |
module WatchersHelper |
| 19 |
|
|
| 20 |
# Valid options |
|
| 21 |
# * :id - the element id |
|
| 22 |
# * :replace - a string or array of element ids that will be |
|
| 23 |
# replaced |
|
| 24 |
def watcher_tag(object, user, options={:replace => 'watcher'})
|
|
| 25 |
id = options[:id] |
|
| 26 |
id ||= options[:replace] if options[:replace].is_a? String |
|
| 27 |
content_tag("span", watcher_link(object, user, options), :id => id)
|
|
| 19 |
|
|
| 20 |
def watcher_tag(object, user, options={})
|
|
| 21 |
content_tag("span", watcher_link(object, user), :class => watcher_css(object))
|
|
| 28 | 22 |
end |
| 29 | 23 |
|
| 30 |
# Valid options |
|
| 31 |
# * :replace - a string or array of element ids that will be |
|
| 32 |
# replaced |
|
| 33 |
def watcher_link(object, user, options={:replace => 'watcher'})
|
|
| 24 |
def watcher_link(object, user) |
|
| 34 | 25 |
return '' unless user && user.logged? && object.respond_to?('watched_by?')
|
| 35 | 26 |
watched = object.watched_by?(user) |
| 36 | 27 |
url = {:controller => 'watchers',
|
| 37 | 28 |
:action => (watched ? 'unwatch' : 'watch'), |
| 38 | 29 |
:object_type => object.class.to_s.underscore, |
| 39 |
:object_id => object.id, |
|
| 40 |
:replace => options[:replace]} |
|
| 30 |
:object_id => object.id} |
|
| 41 | 31 |
link_to_remote((watched ? l(:button_unwatch) : l(:button_watch)), |
| 42 | 32 |
{:url => url},
|
| 43 | 33 |
:href => url_for(url), |
| ... | ... | |
| 45 | 35 |
|
| 46 | 36 |
end |
| 47 | 37 |
|
| 38 |
# Returns the css class used to identify watch links for a given +object+ |
|
| 39 |
def watcher_css(object) |
|
| 40 |
"#{object.class.to_s.underscore}-#{object.id}-watcher"
|
|
| 41 |
end |
|
| 42 |
|
|
| 48 | 43 |
# Returns a comma separated list of users watching the given object |
| 49 | 44 |
def watchers_list(object) |
| 50 | 45 |
remove_allowed = User.current.allowed_to?("delete_#{object.class.name.underscore}_watchers".to_sym, object.project)
|
| app/helpers/.svn/text-base/wiki_helper.rb.svn-base | ||
|---|---|---|
| 18 | 18 |
module WikiHelper |
| 19 | 19 |
|
| 20 | 20 |
def wiki_page_options_for_select(pages, selected = nil, parent = nil, level = 0) |
| 21 |
pages = pages.group_by(&:parent) unless pages.is_a?(Hash) |
|
| 21 | 22 |
s = '' |
| 22 |
pages.select {|p| p.parent == parent}.each do |page|
|
|
| 23 |
attrs = "value='#{page.id}'"
|
|
| 24 |
attrs << " selected='selected'" if selected == page |
|
| 25 |
indent = (level > 0) ? (' ' * level * 2 + '» ') : nil
|
|
| 26 |
|
|
| 27 |
s << "<option #{attrs}>#{indent}#{h page.pretty_title}</option>\n" +
|
|
| 28 |
wiki_page_options_for_select(pages, selected, page, level + 1) |
|
| 23 |
if pages.has_key?(parent) |
|
| 24 |
pages[parent].each do |page| |
|
| 25 |
attrs = "value='#{page.id}'"
|
|
| 26 |
attrs << " selected='selected'" if selected == page |
|
| 27 |
indent = (level > 0) ? (' ' * level * 2 + '» ') : nil
|
|
| 28 |
|
|
| 29 |
s << "<option #{attrs}>#{indent}#{h page.pretty_title}</option>\n" +
|
|
| 30 |
wiki_page_options_for_select(pages, selected, page, level + 1) |
|
| 31 |
end |
|
| 29 | 32 |
end |
| 30 | 33 |
s |
| 31 | 34 |
end |
Also available in: Unified diff