application_helper.rb 9.58 KB
Newer Older
jplang's avatar
jplang committed
1
# redMine - project management software
2
# Copyright (C) 2006-2007  Jean-Philippe Lang
jplang's avatar
jplang committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

module ApplicationHelper

jplang's avatar
jplang committed
20
  # Return current logged in user or nil
jplang's avatar
jplang committed
21 22 23 24
  def loggedin?
    @logged_in_user
  end
  
jplang's avatar
jplang committed
25
  # Return true if user is logged in and is admin, otherwise false
jplang's avatar
jplang committed
26 27 28
  def admin_loggedin?
    @logged_in_user and @logged_in_user.admin?
  end
jplang's avatar
jplang committed
29

jplang's avatar
jplang committed
30
  # Return true if user is authorized for controller/action, otherwise false
jplang's avatar
jplang committed
31
  def authorize_for(controller, action)  
jplang's avatar
jplang committed
32
    # check if action is allowed on public projects
jplang's avatar
jplang committed
33
    if @project.is_public? and Permission.allowed_to_public "%s/%s" % [ controller, action ]
jplang's avatar
jplang committed
34
      return true
jplang's avatar
jplang committed
35
    end
jplang's avatar
jplang committed
36
    # check if user is authorized    
jplang's avatar
jplang committed
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
    if @logged_in_user and (@logged_in_user.admin? or Permission.allowed_to_role( "%s/%s" % [ controller, action ], @logged_in_user.role_for_project(@project.id)  )  )
      return true
    end
    return false
  end

  # Display a link if user is authorized
  def link_to_if_authorized(name, options = {}, html_options = nil, *parameters_for_method_reference)
    link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for(options[:controller], options[:action])
  end

  # Display a link to user's account page
  def link_to_user(user)
    link_to user.display_name, :controller => 'account', :action => 'show', :id => user
  end
52
  
53 54 55 56 57 58 59 60
  def image_to_function(name, function, html_options = {})
    html_options.symbolize_keys!
    tag(:input, html_options.merge({ 
        :type => "image", :src => image_path(name), 
        :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};" 
        }))
  end
  
jplang's avatar
jplang committed
61
  def format_date(date)
62
    l_date(date) if date
jplang's avatar
jplang committed
63 64 65
  end
  
  def format_time(time)
jplang's avatar
jplang committed
66
    l_datetime((time.is_a? String) ? time.to_time : time) if time
jplang's avatar
jplang committed
67
  end
jplang's avatar
jplang committed
68 69 70 71
  
  def day_name(day)
    l(:general_day_names).split(',')[day-1]
  end
72 73 74 75
  
  def month_name(month)
    l(:actionview_datehelper_select_month_names).split(',')[month-1]
  end
76

jplang's avatar
jplang committed
77
  def pagination_links_full(paginator, options={}, html_options={})
jplang's avatar
jplang committed
78 79 80
    html = ''    
    html << link_to_remote(('&#171; ' + l(:label_previous)), 
                            {:update => "content", :url => { :page => paginator.current.previous }},
81
                            {:href => url_for(:action => 'list', :params => params.merge({:page => paginator.current.previous}))}) + ' ' if paginator.current.previous
jplang's avatar
jplang committed
82 83 84
                            
    html << (pagination_links_each(paginator, options) do |n|
      link_to_remote(n.to_s, 
85 86
                      {:url => {:action => 'list', :params => params.merge({:page => n})}, :update => 'content'},
                      {:href => url_for(:action => 'list', :params => params.merge({:page => n}))})
jplang's avatar
jplang committed
87 88 89 90
    end || '')
    
    html << ' ' + link_to_remote((l(:label_next) + ' &#187;'), 
                                 {:update => "content", :url => { :page => paginator.current.next }},
91
                                 {:href => url_for(:action => 'list', :params => params.merge({:page => paginator.current.next}))}) if paginator.current.next
jplang's avatar
jplang committed
92 93
    html  
  end
jplang's avatar
jplang committed
94
  
jplang's avatar
jplang committed
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
  # textilize text according to system settings and RedCloth availability
  def textilizable(text, options = {})
    # different methods for formatting wiki links
    case options[:wiki_links]
    when :local
      # used for local links to html files
      format_wiki_link = Proc.new {|title| "#{title}.html" }
    when :anchor
      # used for single-file wiki export
      format_wiki_link = Proc.new {|title| "##{title}" }
    else
      if @project
        format_wiki_link = Proc.new {|title| url_for :controller => 'wiki', :action => 'index', :id => @project, :page => title }
      else
        format_wiki_link = Proc.new {|title| title }
      end
    end
    
    # turn wiki links into textile links: 
    # example:
    #   [[link]] -> "link":link
    #   [[link|title]] -> "title":link
    text = text.gsub(/\[\[([^\]\|]+)(\|([^\]\|]+))?\]\]/) {|m| "\"#{$3 || $1}\":" + format_wiki_link.call(Wiki.titleize($1)) }

    # turn issue ids to textile links
    # example:
    #   #52 -> "#52":/issues/show/52
    text = text.gsub(/#(\d+)([\s\.\(\)\-,:;])/) {|m| "\"##{$1}\":" + url_for(:controller => 'issues', :action => 'show', :id => $1) + $2 }
       
    # turn revision ids to textile links (@project needed)
    # example:
    #   r52 -> "r52":/repositories/revision/6?rev=52 (@project.id is 6)
    text = text.gsub(/r(\d+)([\s\.\(\)\-,:;])/) {|m| "\"r#{$1}\":" + url_for(:controller => 'repositories', :action => 'revision', :id => @project.id, :rev => $1) + $2 } if @project
   
    # finally textilize text
    text = (Setting.text_formatting == 'textile') && (ActionView::Helpers::TextHelper.method_defined? "textilize") ? auto_link(RedCloth.new(text, [:filter_html]).to_html) : simple_format(auto_link(h(text)))
jplang's avatar
jplang committed
131 132
  end
  
jplang's avatar
jplang committed
133 134 135 136 137 138 139 140
  def error_messages_for(object_name, options = {})
    options = options.symbolize_keys
    object = instance_variable_get("@#{object_name}")
    if object && !object.errors.empty?
      # build full_messages here with controller current language
      full_messages = []
      object.errors.each do |attr, msg|
        next if msg.nil?
141
        msg = msg.first if msg.is_a? Array
jplang's avatar
jplang committed
142 143 144
        if attr == "base"
          full_messages << l(msg)
        else
jplang's avatar
jplang committed
145
          full_messages << "&#171; " + (l_has_string?("field_" + attr) ? l("field_" + attr) : object.class.human_attribute_name(attr)) + " &#187; " + l(msg) unless attr == "custom_values"
jplang's avatar
jplang committed
146
        end
jplang's avatar
jplang committed
147 148 149 150 151 152
      end
      # retrieve custom values error messages
      if object.errors[:custom_values]
        object.custom_values.each do |v| 
          v.errors.each do |attr, msg|
            next if msg.nil?
153
            msg = msg.first if msg.is_a? Array
jplang's avatar
jplang committed
154 155 156 157
            full_messages << "&#171; " + v.custom_field.name + " &#187; " + l(msg)
          end
        end
      end      
jplang's avatar
jplang committed
158 159
      content_tag("div",
        content_tag(
jplang's avatar
jplang committed
160
          options[:header_tag] || "h2", lwr(:gui_validation_error, full_messages.length) + " :"
jplang's avatar
jplang committed
161 162 163 164 165 166 167 168
        ) +
        content_tag("ul", full_messages.collect { |msg| content_tag("li", msg) }),
        "id" => options[:id] || "errorExplanation", "class" => options[:class] || "errorExplanation"
      )
    else
      ""
    end
  end
169
  
170 171 172
  def lang_options_for_select(blank=true)
    (blank ? [["(auto)", ""]] : []) + 
      (GLoc.valid_languages.sort {|x,y| x.to_s <=> y.to_s }).collect {|lang| [ l_lang_name(lang.to_s, lang), lang.to_s]}
173
  end
jplang's avatar
jplang committed
174 175 176 177 178 179 180 181 182 183 184
  
  def label_tag_for(name, option_tags = nil, options = {})
    label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "")
    content_tag("label", label_text)
  end
  
  def labelled_tabular_form_for(name, object, options, &proc)
    options[:html] ||= {}
    options[:html].store :class, "tabular"
    form_for(name, object, options.merge({ :builder => TabularFormBuilder, :lang => current_language}), &proc)
  end
jplang's avatar
jplang committed
185 186 187 188 189 190
  
  def check_all_links(form_name)
    link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") +
    " | " +
    link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)")   
  end
jplang's avatar
jplang committed
191 192
  
  def calendar_for(field_id)
193
    image_tag("calendar.png", {:id => "#{field_id}_trigger",:class => "calendar-trigger"}) +
jplang's avatar
jplang committed
194 195
    javascript_tag("Calendar.setup({inputField : '#{field_id}', ifFormat : '%Y-%m-%d', button : '#{field_id}_trigger' });")
  end
jplang's avatar
jplang committed
196
end
jplang's avatar
jplang committed
197 198 199 200 201 202 203 204 205

class TabularFormBuilder < ActionView::Helpers::FormBuilder
  include GLoc
  
  def initialize(object_name, object, template, options, proc)
    set_language_if_valid options.delete(:lang)
    @object_name, @object, @template, @options, @proc = object_name, object, template, options, proc        
  end      
      
jplang's avatar
jplang committed
206
  (field_helpers - %w(radio_button hidden_field) + %w(date_select)).each do |selector|
jplang's avatar
jplang committed
207 208
    src = <<-END_SRC
    def #{selector}(field, options = {}) 
jplang's avatar
jplang committed
209
      return super if options.delete :no_label
jplang's avatar
jplang committed
210 211
      label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "")
      label = @template.content_tag("label", label_text, 
jplang's avatar
jplang committed
212
                    :class => (@object && @object.errors[field] ? "error" : nil), 
jplang's avatar
jplang committed
213 214 215 216 217 218 219
                    :for => (@object_name.to_s + "_" + field.to_s))
      label + super
    end
    END_SRC
    class_eval src, __FILE__, __LINE__
  end
  
jplang's avatar
jplang committed
220
  def select(field, choices, options = {}, html_options = {}) 
jplang's avatar
jplang committed
221 222
    label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "")
    label = @template.content_tag("label", label_text, 
jplang's avatar
jplang committed
223
                  :class => (@object && @object.errors[field] ? "error" : nil), 
jplang's avatar
jplang committed
224 225 226 227 228 229
                  :for => (@object_name.to_s + "_" + field.to_s))
    label + super
  end

end