2011-11-13 17:56:20 +04:00
# encoding: utf-8
#
2010-11-06 20:47:27 +03:00
# Redmine - project management software
2011-03-12 21:09:46 +03:00
# Copyright (C) 2006-2011 Jean-Philippe Lang
2007-03-12 20:59:02 +03:00
#
# 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.
2008-11-07 17:35:18 +03:00
#
2007-03-12 20:59:02 +03:00
# 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.
2008-11-07 17:35:18 +03:00
#
2007-03-12 20:59:02 +03:00
# 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.
2008-10-27 14:08:29 +03:00
require 'forwardable'
2008-12-12 19:01:35 +03:00
require 'cgi'
2008-06-09 22:40:59 +04:00
2007-03-12 20:59:02 +03:00
module ApplicationHelper
2007-11-12 17:36:33 +03:00
include Redmine :: WikiFormatting :: Macros :: Definitions
2009-02-21 14:04:50 +03:00
include Redmine :: I18n
2008-11-09 17:52:16 +03:00
include GravatarHelper :: PublicMethods
2007-03-12 20:59:02 +03:00
2008-10-27 14:08:29 +03:00
extend Forwardable
def_delegators :wiki_helper , :wikitoolbar_for , :heads_for_wiki_formatter
2007-03-12 20:59:02 +03:00
# Return true if user is authorized for controller/action, otherwise false
2007-08-29 20:52:35 +04:00
def authorize_for ( controller , action )
User . current . allowed_to? ( { :controller = > controller , :action = > action } , @project )
2007-03-12 20:59:02 +03:00
end
# Display a link if user is authorized
2010-09-06 04:26:08 +04:00
#
# @param [String] name Anchor text (passed to link_to)
2010-10-16 03:11:00 +04:00
# @param [Hash] options Hash params. This will checked by authorize_for to see if the user is authorized
2010-09-06 04:26:08 +04:00
# @param [optional, Hash] html_options Options passed to link_to
# @param [optional, Hash] parameters_for_method_reference Extra parameters for link_to
2007-03-12 20:59:02 +03:00
def link_to_if_authorized ( name , options = { } , html_options = nil , * parameters_for_method_reference )
2010-10-16 03:11:00 +04:00
link_to ( name , options , html_options , * parameters_for_method_reference ) if authorize_for ( options [ :controller ] || params [ :controller ] , options [ :action ] )
2008-08-28 22:56:47 +04:00
end
2008-11-07 17:35:18 +03:00
2008-08-28 22:56:47 +04:00
# Display a link to remote if user is authorized
def link_to_remote_if_authorized ( name , options = { } , html_options = nil )
url = options [ :url ] || { }
link_to_remote ( name , options , html_options ) if authorize_for ( url [ :controller ] || params [ :controller ] , url [ :action ] )
2007-03-12 20:59:02 +03:00
end
2009-11-11 13:48:54 +03:00
# Displays a link to user's account page if active
2008-12-07 16:12:19 +03:00
def link_to_user ( user , options = { } )
2009-09-12 12:36:46 +04:00
if user . is_a? ( User )
2009-11-11 13:48:54 +03:00
name = h ( user . name ( options [ :format ] ) )
if user . active?
link_to name , :controller = > 'users' , :action = > 'show' , :id = > user
else
name
end
2009-09-12 12:36:46 +04:00
else
2009-11-11 13:48:54 +03:00
h ( user . to_s )
2009-09-12 12:36:46 +04:00
end
2007-03-12 20:59:02 +03:00
end
2008-11-07 17:35:18 +03:00
2009-11-14 15:53:50 +03:00
# Displays a link to +issue+ with its subject.
# Examples:
2011-05-18 06:46:24 +04:00
#
2009-11-14 15:53:50 +03:00
# link_to_issue(issue) # => Defect #6: This is the subject
# link_to_issue(issue, :truncate => 6) # => Defect #6: This i...
# link_to_issue(issue, :subject => false) # => Defect #6
2009-12-12 18:33:31 +03:00
# link_to_issue(issue, :project => true) # => Foo - Defect #6
2009-11-14 15:53:50 +03:00
#
2008-03-16 15:21:54 +03:00
def link_to_issue ( issue , options = { } )
2009-11-14 15:53:50 +03:00
title = nil
subject = nil
if options [ :subject ] == false
title = truncate ( issue . subject , :length = > 60 )
else
subject = issue . subject
if options [ :truncate ]
subject = truncate ( subject , :length = > options [ :truncate ] )
end
end
2011-07-30 03:20:36 +04:00
s = link_to " #{ h ( issue . tracker ) } # #{ issue . id } " , { :controller = > " issues " , :action = > " show " , :id = > issue } ,
2009-11-14 15:53:50 +03:00
:class = > issue . css_classes ,
:title = > title
2012-01-02 21:40:03 +04:00
s << h ( " : #{ subject } " ) if subject
s = h ( " #{ issue . project } - " ) + s if options [ :project ]
2009-11-14 15:53:50 +03:00
s
2007-04-07 22:30:01 +04:00
end
2008-11-07 17:35:18 +03:00
2008-07-22 21:55:19 +04:00
# Generates a link to an attachment.
# Options:
# * :text - Link text (default to attachment filename)
# * :download - Force download (default: false)
def link_to_attachment ( attachment , options = { } )
text = options . delete ( :text ) || attachment . filename
action = options . delete ( :download ) ? 'download' : 'show'
2011-11-20 04:10:18 +04:00
link_to ( h ( text ) ,
{ :controller = > 'attachments' , :action = > action ,
:id = > attachment , :filename = > attachment . filename } ,
options )
2008-07-22 21:55:19 +04:00
end
2008-11-07 17:35:18 +03:00
2009-12-23 02:23:54 +03:00
# Generates a link to a SCM revision
# Options:
# * :text - Link text (default to the formatted revision)
2012-01-15 22:19:19 +04:00
def link_to_revision ( revision , repository , options = { } )
if repository . is_a? ( Project )
repository = repository . repository
end
2009-12-23 02:23:54 +03:00
text = options . delete ( :text ) || format_revision ( revision )
2011-01-02 12:45:05 +03:00
rev = revision . respond_to? ( :identifier ) ? revision . identifier : revision
2011-12-03 10:14:19 +04:00
link_to (
h ( text ) ,
2012-01-15 22:19:19 +04:00
{ :controller = > 'repositories' , :action = > 'revision' , :id = > repository . project , :repository_id = > repository . identifier_param , :rev = > rev } ,
2011-12-03 10:14:19 +04:00
:title = > l ( :label_revision_id , format_revision ( revision ) )
)
2009-12-23 02:23:54 +03:00
end
2011-05-18 06:46:24 +04:00
2011-01-23 20:02:10 +03:00
# Generates a link to a message
def link_to_message ( message , options = { } , html_options = nil )
link_to (
h ( truncate ( message . subject , :length = > 60 ) ) ,
{ :controller = > 'messages' , :action = > 'show' ,
:board_id = > message . board_id ,
:id = > message . root ,
:r = > ( message . parent_id && message . id ) ,
:anchor = > ( message . parent_id ? " message- #{ message . id } " : nil )
} . merge ( options ) ,
html_options
)
end
2009-12-23 02:23:54 +03:00
2010-08-08 11:07:20 +04:00
# Generates a link to a project if active
# Examples:
2011-05-18 06:46:24 +04:00
#
2010-08-08 11:07:20 +04:00
# link_to_project(project) # => link to the specified project overview
# link_to_project(project, :action=>'settings') # => link to project settings
# link_to_project(project, {:only_path => false}, :class => "project") # => 3rd arg adds html options
# link_to_project(project, {}, :class => "project") # => html options with default url (project overview)
#
def link_to_project ( project , options = { } , html_options = nil )
if project . active?
url = { :controller = > 'projects' , :action = > 'show' , :id = > project } . merge ( options )
link_to ( h ( project ) , url , html_options )
else
h ( project )
end
end
2007-04-07 22:56:12 +04:00
def toggle_link ( name , id , options = { } )
onclick = " Element.toggle(' #{ id } '); "
onclick << ( options [ :focus ] ? " Form.Element.focus(' #{ options [ :focus ] } '); " : " this.blur(); " )
onclick << " return false; "
link_to ( name , " # " , :onclick = > onclick )
end
2008-11-07 17:35:18 +03:00
2007-03-12 20:59:02 +03:00
def image_to_function ( name , function , html_options = { } )
html_options . symbolize_keys!
2008-11-07 17:35:18 +03:00
tag ( :input , html_options . merge ( {
:type = > " image " , :src = > image_path ( name ) ,
:onclick = > ( html_options [ :onclick ] ? " #{ html_options [ :onclick ] } ; " : " " ) + " #{ function } ; "
2007-03-12 20:59:02 +03:00
} ) )
end
2008-11-07 17:35:18 +03:00
2007-08-16 20:45:06 +04:00
def prompt_to_remote ( name , text , param , url , html_options = { } )
html_options [ :onclick ] = " promptToRemote(' #{ text } ', ' #{ param } ', ' #{ url_for ( url ) } '); return false; "
link_to name , { } , html_options
end
2011-05-18 06:46:24 +04:00
2008-11-30 14:18:22 +03:00
def format_activity_title ( text )
2009-02-21 14:04:50 +03:00
h ( truncate_single_line ( text , :length = > 100 ) )
2008-11-30 14:18:22 +03:00
end
2011-05-18 06:46:24 +04:00
2008-11-30 14:18:22 +03:00
def format_activity_day ( date )
date == Date . today ? l ( :label_today ) . titleize : format_date ( date )
end
2011-05-18 06:46:24 +04:00
2008-11-30 14:18:22 +03:00
def format_activity_description ( text )
2011-12-03 10:15:55 +04:00
h ( truncate ( text . to_s , :length = > 120 ) . gsub ( %r{ [ \ r \ n]*<(pre|code)>.*$ }m , '...' )
) . gsub ( / [ \ r \ n]+ / , " <br /> " ) . html_safe
2008-09-20 18:07:52 +04:00
end
2008-11-07 17:35:18 +03:00
2009-12-06 13:28:20 +03:00
def format_version_name ( version )
if version . project == @project
h ( version )
else
h ( " #{ version . project } - #{ version } " )
end
end
2011-05-18 06:46:24 +04:00
2008-09-20 18:07:52 +04:00
def due_date_distance_in_words ( date )
if date
l ( ( date < Date . today ? :label_roadmap_overdue : :label_roadmap_due_in ) , distance_of_date_in_words ( Date . today , date ) )
end
end
2008-11-07 17:35:18 +03:00
2011-03-12 21:27:02 +03:00
def render_page_hierarchy ( pages , node = nil , options = { } )
2008-11-22 14:44:07 +03:00
content = ''
if pages [ node ]
content << " <ul class= \" pages-hierarchy \" > \n "
pages [ node ] . each do | page |
content << " <li> "
2010-10-27 20:27:06 +04:00
content << link_to ( h ( page . pretty_title ) , { :controller = > 'wiki' , :action = > 'show' , :project_id = > page . project , :id = > page . title } ,
2011-03-12 21:27:02 +03:00
:title = > ( options [ :timestamp ] && page . updated_on ? l ( :label_updated_time , distance_of_time_in_words ( Time . now , page . updated_on ) ) : nil ) )
content << " \n " + render_page_hierarchy ( pages , page . id , options ) if pages [ page . id ]
2008-11-22 14:44:07 +03:00
content << " </li> \n "
end
content << " </ul> \n "
end
2011-10-06 15:03:29 +04:00
content . html_safe
2008-11-22 14:44:07 +03:00
end
2011-05-18 06:46:24 +04:00
2009-01-03 17:11:44 +03:00
# Renders flash messages
def render_flash_messages
s = ''
flash . each do | k , v |
2011-12-08 03:53:20 +04:00
s << ( content_tag ( 'div' , v . html_safe , :class = > " flash #{ k } " ) )
2009-01-03 17:11:44 +03:00
end
2011-08-20 14:51:38 +04:00
s . html_safe
2009-01-03 17:11:44 +03:00
end
2011-05-18 06:46:24 +04:00
2009-09-12 13:13:13 +04:00
# Renders tabs and their content
def render_tabs ( tabs )
if tabs . any?
render :partial = > 'common/tabs' , :locals = > { :tabs = > tabs }
else
content_tag 'p' , l ( :label_no_data ) , :class = > " nodata "
end
end
2011-05-18 06:46:24 +04:00
2009-01-24 14:31:15 +03:00
# Renders the project quick-jump box
def render_project_jump_box
2011-04-14 20:32:03 +04:00
return unless User . current . logged?
2011-03-16 22:26:07 +03:00
projects = User . current . memberships . collect ( & :project ) . compact . uniq
2009-01-24 14:31:15 +03:00
if projects . any?
s = '<select onchange="if (this.value != \'\') { window.location = this.value; }">' +
2009-10-24 15:29:49 +04:00
" <option value=''> #{ l ( :label_jump_to_a_project ) } </option> " +
2009-10-11 12:20:39 +04:00
'<option value="" disabled="disabled">---</option>'
2009-10-24 15:29:49 +04:00
s << project_tree_options_for_select ( projects , :selected = > @project ) do | p |
2009-01-25 15:13:27 +03:00
{ :value = > url_for ( :controller = > 'projects' , :action = > 'show' , :id = > p , :jump = > current_menu_item ) }
2009-01-24 14:31:15 +03:00
end
s << '</select>'
2011-08-20 14:52:14 +04:00
s . html_safe
2009-01-24 14:31:15 +03:00
end
end
2011-05-18 06:46:24 +04:00
2009-01-24 14:31:15 +03:00
def project_tree_options_for_select ( projects , options = { } )
s = ''
project_tree ( projects ) do | project , level |
name_prefix = ( level > 0 ? ( ' ' * 2 * level + '» ' ) : '' )
2010-03-03 06:37:40 +03:00
tag_options = { :value = > project . id }
if project == options [ :selected ] || ( options [ :selected ] . respond_to? ( :include? ) && options [ :selected ] . include? ( project ) )
tag_options [ :selected ] = 'selected'
else
tag_options [ :selected ] = nil
end
2009-01-24 14:31:15 +03:00
tag_options . merge! ( yield ( project ) ) if block_given?
s << content_tag ( 'option' , name_prefix + h ( project ) , tag_options )
end
2011-08-20 14:52:52 +04:00
s . html_safe
2009-01-24 14:31:15 +03:00
end
2011-05-18 06:46:24 +04:00
2009-01-24 14:31:15 +03:00
# Yields the given block for each project with its level in the tree
2010-10-23 02:38:45 +04:00
#
# Wrapper for Project#project_tree
2009-01-24 14:31:15 +03:00
def project_tree ( projects , & block )
2010-10-23 02:38:45 +04:00
Project . project_tree ( projects , & block )
2009-01-24 14:31:15 +03:00
end
2011-05-18 06:46:24 +04:00
2009-01-29 17:22:56 +03:00
def project_nested_ul ( projects , & block )
s = ''
if projects . any?
ancestors = [ ]
projects . sort_by ( & :lft ) . each do | project |
if ( ancestors . empty? || project . is_descendant_of? ( ancestors . last ) )
s << " <ul> \n "
else
ancestors . pop
s << " </li> "
2011-05-18 06:46:24 +04:00
while ( ancestors . any? && ! project . is_descendant_of? ( ancestors . last ) )
2009-01-29 17:22:56 +03:00
ancestors . pop
s << " </ul></li> \n "
end
end
s << " <li> "
s << yield ( project ) . to_s
ancestors << project
end
s << ( " </li></ul> \n " * ancestors . size )
end
2011-08-20 14:53:25 +04:00
s . html_safe
2009-01-29 17:22:56 +03:00
end
2011-05-18 06:46:24 +04:00
2009-09-12 12:36:46 +04:00
def principals_check_box_tags ( name , principals )
s = ''
2009-11-04 14:17:55 +03:00
principals . sort . each do | principal |
2009-09-12 12:36:46 +04:00
s << " <label> #{ check_box_tag name , principal . id , false } #{ h principal } </label> \n "
end
2011-08-20 14:53:50 +04:00
s . html_safe
2009-09-12 12:36:46 +04:00
end
2011-08-20 09:57:14 +04:00
2011-07-23 23:05:22 +04:00
# Returns a string for users/groups option tags
def principals_options_for_select ( collection , selected = nil )
s = ''
2012-01-21 15:06:59 +04:00
if collection . include? ( User . current )
s << content_tag ( 'option' , " << #{ l ( :label_me ) } >> " , :value = > User . current . id )
end
2011-07-23 23:05:22 +04:00
groups = ''
collection . sort . each do | element |
selected_attribute = ' selected="selected"' if option_value_selected? ( element , selected )
( element . is_a? ( Group ) ? groups : s ) << %( <option value=" #{ element . id } " #{ selected_attribute } > #{ h element . name } </option> )
end
unless groups . empty?
s << %( <optgroup label=" #{ h ( l ( :label_group_plural ) ) } "> #{ groups } </optgroup> )
end
s
end
2008-11-22 14:44:07 +03:00
2008-06-04 22:13:14 +04:00
# Truncates and returns the string as a single line
def truncate_single_line ( string , * args )
2009-10-29 20:55:59 +03:00
truncate ( string . to_s , * args ) . gsub ( %r{ [ \ r \ n]+ }m , ' ' )
2008-06-04 22:13:14 +04:00
end
2011-05-18 06:46:24 +04:00
2010-03-18 23:02:17 +03:00
# Truncates at line break after 250 characters or options[:length]
def truncate_lines ( string , options = { } )
length = options [ :length ] || 250
if string . to_s =~ / \ A(.{ #{ length } }.*?)$ /m
" #{ $1 } ... "
else
string
end
end
2008-11-07 17:35:18 +03:00
2012-01-08 21:14:17 +04:00
def anchor ( text )
text . to_s . gsub ( ' ' , '_' )
end
2008-02-26 21:15:58 +03:00
def html_hours ( text )
2011-08-20 14:54:18 +04:00
text . gsub ( %r{ ( \ d+) \ .( \ d+) } , '<span class="hours hours-int">\1</span><span class="hours hours-dec">.\2</span>' ) . html_safe
2008-02-26 21:15:58 +03:00
end
2008-11-07 17:35:18 +03:00
2008-12-06 14:21:10 +03:00
def authoring ( created , author , options = { } )
2011-08-20 14:54:41 +04:00
l ( options [ :label ] || :label_added_time_by , :author = > link_to_user ( author ) , :age = > time_tag ( created ) ) . html_safe
2009-07-04 16:36:26 +04:00
end
2011-05-18 06:46:24 +04:00
2009-07-04 16:36:26 +04:00
def time_tag ( time )
text = distance_of_time_in_words ( Time . now , time )
if @project
2010-09-17 01:26:30 +04:00
link_to ( text , { :controller = > 'activities' , :action = > 'index' , :id = > @project , :from = > time . to_date } , :title = > format_time ( time ) )
2009-07-04 16:36:26 +04:00
else
content_tag ( 'acronym' , text , :title = > format_time ( time ) )
end
2007-03-12 20:59:02 +03:00
end
2008-06-09 22:40:59 +04:00
def syntax_highlight ( name , content )
2010-03-14 15:57:08 +03:00
Redmine :: SyntaxHighlighting . highlight_by_filename ( content , name )
2008-06-09 22:40:59 +04:00
end
2008-11-07 17:35:18 +03:00
2008-07-06 16:43:51 +04:00
def to_path_param ( path )
path . to_s . split ( %r{ [/ \\ ] } ) . select { | p | ! p . blank? }
end
2007-12-29 14:36:30 +03:00
def pagination_links_full ( paginator , count = nil , options = { } )
2007-06-23 22:53:45 +04:00
page_param = options . delete ( :page_param ) || :page
2010-02-06 15:54:13 +03:00
per_page_links = options . delete ( :per_page_links )
2007-12-29 14:36:30 +03:00
url_param = params . dup
2008-11-07 17:35:18 +03:00
html = ''
2009-01-26 04:47:51 +03:00
if paginator . current . previous
2011-08-06 04:49:52 +04:00
# \xc2\xab(utf-8) = «
html << link_to_content_update (
" \xc2 \xab " + l ( :label_previous ) ,
url_param . merge ( page_param = > paginator . current . previous ) ) + ' '
2009-01-26 04:47:51 +03:00
end
2008-11-07 17:35:18 +03:00
2007-03-12 20:59:02 +03:00
html << ( pagination_links_each ( paginator , options ) do | n |
2011-04-03 18:01:32 +04:00
link_to_content_update ( n . to_s , url_param . merge ( page_param = > n ) )
2007-03-12 20:59:02 +03:00
end || '' )
2011-05-18 06:46:24 +04:00
2009-01-26 04:47:51 +03:00
if paginator . current . next
2011-08-06 04:49:52 +04:00
# \xc2\xbb(utf-8) = »
html << ' ' + link_to_content_update (
( l ( :label_next ) + " \xc2 \xbb " ) ,
url_param . merge ( page_param = > paginator . current . next ) )
2009-01-26 04:47:51 +03:00
end
2008-11-07 17:35:18 +03:00
2007-12-29 14:36:30 +03:00
unless count . nil?
2010-02-06 15:54:13 +03:00
html << " ( #{ paginator . current . first_item } - #{ paginator . current . last_item } / #{ count } ) "
if per_page_links != false && links = per_page_links ( paginator . items_per_page )
html << " | #{ links } "
end
2007-12-29 14:36:30 +03:00
end
2008-11-07 17:35:18 +03:00
2011-08-20 14:55:02 +04:00
html . html_safe
2007-03-12 20:59:02 +03:00
end
2011-05-18 06:46:24 +04:00
2007-12-29 14:36:30 +03:00
def per_page_links ( selected = nil )
links = Setting . per_page_options_array . collect do | n |
2011-04-03 18:01:32 +04:00
n == selected ? n : link_to_content_update ( n , params . merge ( :per_page = > n ) )
2007-12-29 14:36:30 +03:00
end
links . size > 1 ? l ( :label_display_per_page , links . join ( ', ' ) ) : nil
end
2011-05-18 06:46:24 +04:00
2011-11-23 01:32:45 +04:00
def reorder_links ( name , url , method = :post )
2011-10-06 15:04:32 +04:00
link_to ( image_tag ( '2uparrow.png' , :alt = > l ( :label_sort_highest ) ) ,
url . merge ( { " #{ name } [move_to] " = > 'highest' } ) ,
2011-11-23 01:32:45 +04:00
:method = > method , :title = > l ( :label_sort_highest ) ) +
2011-10-06 15:04:32 +04:00
link_to ( image_tag ( '1uparrow.png' , :alt = > l ( :label_sort_higher ) ) ,
url . merge ( { " #{ name } [move_to] " = > 'higher' } ) ,
2011-11-23 01:32:45 +04:00
:method = > method , :title = > l ( :label_sort_higher ) ) +
2011-10-06 15:04:32 +04:00
link_to ( image_tag ( '1downarrow.png' , :alt = > l ( :label_sort_lower ) ) ,
url . merge ( { " #{ name } [move_to] " = > 'lower' } ) ,
2011-11-23 01:32:45 +04:00
:method = > method , :title = > l ( :label_sort_lower ) ) +
2011-10-06 15:04:32 +04:00
link_to ( image_tag ( '2downarrow.png' , :alt = > l ( :label_sort_lowest ) ) ,
url . merge ( { " #{ name } [move_to] " = > 'lowest' } ) ,
2011-11-23 01:32:45 +04:00
:method = > method , :title = > l ( :label_sort_lowest ) )
2009-02-26 12:21:41 +03:00
end
2008-11-07 17:35:18 +03:00
2008-03-27 21:41:42 +03:00
def breadcrumb ( * args )
2008-07-26 15:46:24 +04:00
elements = args . flatten
2011-08-21 15:11:25 +04:00
elements . any? ? content_tag ( 'p' , ( args . join ( " \xc2 \xbb " ) + " \xc2 \xbb " ) . html_safe , :class = > 'breadcrumb' ) : nil
2008-03-27 21:41:42 +03:00
end
2011-05-18 06:46:24 +04:00
2009-01-29 16:53:17 +03:00
def other_formats_links ( & block )
2011-11-23 00:57:20 +04:00
concat ( '<p class="other-formats">' . html_safe + l ( :label_export_to ) )
2009-01-29 16:53:17 +03:00
yield Redmine :: Views :: OtherFormatsBuilder . new ( self )
2011-11-23 00:57:20 +04:00
concat ( '</p>' . html_safe )
2009-01-29 16:53:17 +03:00
end
2011-05-18 06:46:24 +04:00
2009-02-20 21:34:57 +03:00
def page_header_title
if @project . nil? || @project . new_record?
h ( Setting . app_title )
else
b = [ ]
2011-04-14 20:29:51 +04:00
ancestors = ( @project . root? ? [ ] : @project . ancestors . visible . all )
2009-02-20 21:34:57 +03:00
if ancestors . any?
root = ancestors . shift
2010-08-08 11:07:20 +04:00
b << link_to_project ( root , { :jump = > current_menu_item } , :class = > 'root' )
2009-02-20 21:34:57 +03:00
if ancestors . size > 2
2011-10-06 15:02:24 +04:00
b << " \xe2 \x80 \xa6 "
2009-02-20 21:34:57 +03:00
ancestors = ancestors [ - 2 , 2 ]
end
2010-08-08 11:07:20 +04:00
b += ancestors . collect { | p | link_to_project ( p , { :jump = > current_menu_item } , :class = > 'ancestor' ) }
2009-02-20 21:34:57 +03:00
end
b << h ( @project )
2011-10-06 19:02:14 +04:00
b . join ( " \xc2 \xbb " ) . html_safe
2009-02-20 21:34:57 +03:00
end
end
2008-11-07 17:35:18 +03:00
2008-01-03 01:41:53 +03:00
def html_title ( * args )
if args . empty?
2011-11-19 15:43:11 +04:00
title = @html_title || [ ]
2011-09-16 05:50:33 +04:00
title << @project . name if @project
2011-11-19 15:43:11 +04:00
title << Setting . app_title unless Setting . app_title == title . last
2009-10-24 16:33:08 +04:00
title . select { | t | ! t . blank? } . join ( ' - ' )
2008-01-03 01:41:53 +03:00
else
@html_title || = [ ]
@html_title += args
end
2007-09-08 00:52:45 +04:00
end
2007-10-05 22:05:41 +04:00
2010-08-04 05:17:45 +04:00
# Returns the theme, controller name, and action as css classes for the
# HTML body.
def body_css_classes
css = [ ]
if theme = Redmine :: Themes . theme ( Setting . ui_theme )
css << 'theme-' + theme . name
end
css << 'controller-' + params [ :controller ]
css << 'action-' + params [ :action ]
css . join ( ' ' )
end
2007-10-05 22:05:41 +04:00
def accesskey ( s )
2008-01-20 16:07:19 +03:00
Redmine :: AccessKeys . key_for s
2007-10-05 22:05:41 +04:00
end
2007-11-12 17:36:33 +03:00
# Formats text according to system settings.
# 2 ways to call this method:
# * with a String: textilizable(text, options)
# * with an object and one of its attribute: textilizable(issue, :description, options)
def textilizable ( * args )
options = args . last . is_a? ( Hash ) ? args . pop : { }
case args . size
when 1
2008-07-26 16:54:54 +04:00
obj = options [ :object ]
2008-02-17 17:17:20 +03:00
text = args . shift
2007-11-12 17:36:33 +03:00
when 2
obj = args . shift
2010-02-06 13:40:21 +03:00
attr = args . shift
text = obj . send ( attr ) . to_s
2007-11-12 17:36:33 +03:00
else
raise ArgumentError , 'invalid arguments to textilizable'
end
2008-02-17 17:17:20 +03:00
return '' if text . blank?
2010-03-15 22:37:01 +03:00
project = options [ :project ] || @project || ( obj && obj . respond_to? ( :project ) ? obj . project : nil )
only_path = options . delete ( :only_path ) == false ? false : true
2008-11-07 17:35:18 +03:00
2011-11-18 20:25:00 +04:00
text = Redmine :: WikiFormatting . to_html ( Setting . text_formatting , text , :object = > obj , :attribute = > attr )
2011-05-18 06:46:24 +04:00
2010-12-29 21:21:22 +03:00
@parsed_headings = [ ]
2012-02-14 12:09:23 +04:00
@heading_anchors = { }
2011-11-18 22:22:41 +04:00
@current_section = 0 if options [ :edit_section_links ]
2012-02-11 14:02:24 +04:00
parse_sections ( text , project , obj , attr , only_path , options )
2010-12-29 21:21:22 +03:00
text = parse_non_pre_blocks ( text ) do | text |
2012-02-11 14:02:24 +04:00
[ :parse_inline_attachments , :parse_wiki_links , :parse_redmine_links , :parse_macros ] . each do | method_name |
2010-03-15 22:54:50 +03:00
send method_name , text , project , obj , attr , only_path , options
end
2010-03-15 22:37:01 +03:00
end
2012-02-11 14:02:24 +04:00
parse_headings ( text , project , obj , attr , only_path , options )
2011-05-18 06:46:24 +04:00
2010-12-29 21:21:22 +03:00
if @parsed_headings . any?
replace_toc ( text , @parsed_headings )
end
2011-05-18 06:46:24 +04:00
2011-12-18 02:15:36 +04:00
text . html_safe
2010-03-15 22:54:50 +03:00
end
2011-05-18 06:46:24 +04:00
2010-03-15 22:54:50 +03:00
def parse_non_pre_blocks ( text )
s = StringScanner . new ( text )
tags = [ ]
parsed = ''
while ! s . eos?
s . scan ( / (.*?)(<( \/ )?(pre|code)(.*?)>| \ z) /im )
text , full_tag , closing , tag = s [ 1 ] , s [ 2 ] , s [ 3 ] , s [ 4 ]
if tags . empty?
yield text
end
parsed << text
if tag
if closing
if tags . last == tag . downcase
tags . pop
end
else
tags << tag . downcase
end
parsed << full_tag
end
end
2010-03-15 22:57:35 +03:00
# Close any non closing tags
while tag = tags . pop
parsed << " </ #{ tag } > "
end
2011-08-20 15:14:29 +04:00
parsed . html_safe
2010-03-15 22:37:01 +03:00
end
2011-05-18 06:46:24 +04:00
2010-03-15 22:37:01 +03:00
def parse_inline_attachments ( text , project , obj , attr , only_path , options )
2007-09-03 00:41:47 +04:00
# when using an image link, try to use an attachment, if possible
2010-03-14 11:33:53 +03:00
if options [ :attachments ] || ( obj && obj . respond_to? ( :attachments ) )
2011-11-24 09:31:29 +04:00
attachments = options [ :attachments ] || obj . attachments
2011-11-23 09:30:53 +04:00
text . gsub! ( / src="([^ \/ "]+ \ .(bmp|gif|jpg|jpe|jpeg|png))"( \ s+alt="([^"]*)")? /i ) do | m |
2011-05-18 06:46:24 +04:00
filename , ext , alt , alttext = $1 . downcase , $2 , $3 , $4
2007-09-03 00:41:47 +04:00
# search for the picture in attachments
2011-11-24 09:31:29 +04:00
if found = Attachment . latest_attach ( attachments , filename )
image_url = url_for :only_path = > only_path , :controller = > 'attachments' ,
:action = > 'download' , :id = > found
2009-12-27 13:52:02 +03:00
desc = found . description . to_s . gsub ( '"' , '' )
if ! desc . blank? && alttext . blank?
alt = " title= \" #{ desc } \" alt= \" #{ desc } \" "
end
2011-08-20 15:14:58 +04:00
" src= \" #{ image_url } \" #{ alt } " . html_safe
2007-09-03 00:41:47 +04:00
else
2011-08-20 15:14:58 +04:00
m . html_safe
2007-09-03 00:41:47 +04:00
end
end
end
2010-03-15 22:37:01 +03:00
end
2008-11-07 17:35:18 +03:00
2010-03-15 22:37:01 +03:00
# Wiki links
#
# Examples:
# [[mypage]]
# [[mypage|mytext]]
# wiki links can refer other project wikis, using project name or identifier:
# [[project:]] -> wiki starting page
# [[project:|mytext]]
# [[project:mypage]]
# [[project:mypage|mytext]]
def parse_wiki_links ( text , project , obj , attr , only_path , options )
text . gsub! ( / (!)?( \ [ \ [([^ \ ] \ n \ |]+)( \ |([^ \ ] \ n \ |]+))? \ ] \ ]) / ) do | m |
2007-08-17 15:21:58 +04:00
link_project = project
2008-01-15 21:12:12 +03:00
esc , all , page , title = $1 , $2 , $3 , $5
if esc . nil?
if page =~ / ^([^ \ :]+) \ :(.*)$ /
2010-11-11 16:39:14 +03:00
link_project = Project . find_by_identifier ( $1 ) || Project . find_by_name ( $1 )
2008-01-15 21:12:12 +03:00
page = $2
title || = $1 if page . blank?
end
2008-11-07 17:35:18 +03:00
2008-01-15 21:12:12 +03:00
if link_project && link_project . wiki
2008-07-28 21:20:31 +04:00
# extract anchor
anchor = nil
if page =~ / ^(.+?) \ # (.+)$ /
page , anchor = $1 , $2
end
2011-10-02 21:25:29 +04:00
anchor = sanitize_anchor_name ( anchor ) if anchor . present?
2008-01-15 21:12:12 +03:00
# check if page exists
wiki_page = link_project . wiki . find_page ( page )
2011-10-02 18:44:07 +04:00
url = if anchor . present? && wiki_page . present? && ( obj . is_a? ( WikiContent ) || obj . is_a? ( WikiContent :: Version ) ) && obj . page == wiki_page
" # #{ anchor } "
else
case options [ :wiki_links ]
2011-10-02 19:32:34 +04:00
when :local ; " #{ page . present? ? Wiki . titleize ( page ) : '' } .html " + ( anchor . present? ? " # #{ anchor } " : '' )
2011-10-02 19:57:17 +04:00
when :anchor ; " # #{ page . present? ? Wiki . titleize ( page ) : title } " + ( anchor . present? ? " _ #{ anchor } " : '' ) # used for single-file wiki export
2010-03-15 22:37:01 +03:00
else
2010-10-29 01:25:38 +04:00
wiki_page_id = page . present? ? Wiki . titleize ( page ) : nil
2011-12-17 15:44:04 +04:00
parent = wiki_page . nil? && obj . is_a? ( WikiContent ) && obj . page && project == link_project ? obj . page . title : nil
url_for ( :only_path = > only_path , :controller = > 'wiki' , :action = > 'show' , :project_id = > link_project ,
:id = > wiki_page_id , :anchor = > anchor , :parent = > parent )
2010-03-15 22:37:01 +03:00
end
2011-10-02 18:44:07 +04:00
end
2011-11-24 23:47:36 +04:00
link_to ( title . present? ? title . html_safe : h ( page ) , url , :class = > ( 'wiki-page' + ( wiki_page ? '' : ' new' ) ) )
2008-01-15 21:12:12 +03:00
else
# project or wiki doesn't exist
2011-08-20 15:15:35 +04:00
all . html_safe
2008-01-15 21:12:12 +03:00
end
2007-09-08 00:07:54 +04:00
else
2011-08-20 15:15:35 +04:00
all . html_safe
2007-09-08 00:07:54 +04:00
end
2007-08-15 21:31:01 +04:00
end
2010-03-15 22:37:01 +03:00
end
2011-05-18 06:46:24 +04:00
2010-03-15 22:37:01 +03:00
# Redmine links
#
# Examples:
# Issues:
# #52 -> Link to issue #52
# Changesets:
# r52 -> Link to revision 52
# commit:a85130f -> Link to scmid starting with a85130f
# Documents:
# document#17 -> Link to document with id 17
# document:Greetings -> Link to the document with title "Greetings"
# document:"Some document" -> Link to the document with title "Some document"
# Versions:
# version#3 -> Link to version with id 3
# version:1.0.0 -> Link to version named "1.0.0"
# version:"1.0 beta 2" -> Link to version named "1.0 beta 2"
# Attachments:
# attachment:file.zip -> Link to the attachment of the current object named file.zip
# Source files:
# source:some/file -> Link to the file located at /some/file in the project's repository
# source:some/file@52 -> Link to the file's revision 52
# source:some/file#L120 -> Link to line 120 of the file
# source:some/file@52#L120 -> Link to line 120 of the file's revision 52
# export:some/file -> Force the download of the file
2011-01-23 19:12:38 +03:00
# Forum messages:
2010-03-15 22:37:01 +03:00
# message#1218 -> Link to message with id 1218
2011-01-23 19:12:38 +03:00
#
# Links can refer other objects from other projects, using project identifier:
# identifier:r52
# identifier:document:"Some document"
# identifier:version:1.0.0
# identifier:source:some/file
2010-03-15 22:37:01 +03:00
def parse_redmine_links ( text , project , obj , attr , only_path , options )
2012-02-15 21:49:31 +04:00
text . gsub! ( %r{ ([ \ s \ (, \ - \ [ \ >]|^)(!)?(([a-z0-9 \ -_]+):)?(attachment|document|version|forum|news|message|project|commit|source|export)?((( # )|((([a-z0-9 \ -]+) \ |)?(r)))(( \ d+)(( # note)?-( \ d+))?)|(:)([^" \ s<>][^ \ s<>]*?|"[^"]+?"))(?=(?=[[:punct:]][^A-Za-z0-9_/])|,| \ s| \ ]|<|$) } ) do | m |
leading , esc , project_prefix , project_identifier , prefix , repo_prefix , repo_identifier , sep , identifier , comment_suffix , comment_id = $1 , $2 , $3 , $4 , $5 , $10 , $11 , $8 || $12 || $18 , $14 || $19 , $15 , $17
2007-09-03 00:41:47 +04:00
link = nil
2011-01-23 19:12:38 +03:00
if project_identifier
project = Project . visible . find_by_identifier ( project_identifier )
end
2008-01-15 21:12:12 +03:00
if esc . nil?
if prefix . nil? && sep == 'r'
2012-01-22 18:23:10 +04:00
if project
repository = nil
if repo_identifier
repository = project . repositories . detect { | repo | repo . identifier == repo_identifier }
else
repository = project . repository
end
# project.changesets.visible raises an SQL error because of a double join on repositories
if repository && ( changeset = Changeset . visible . find_by_repository_id_and_revision ( repository . id , identifier ) )
link = link_to ( h ( " #{ project_prefix } #{ repo_prefix } r #{ identifier } " ) , { :only_path = > only_path , :controller = > 'repositories' , :action = > 'revision' , :id = > project , :repository_id = > repository . identifier_param , :rev = > changeset . revision } ,
:class = > 'changeset' ,
:title = > truncate_single_line ( changeset . comments , :length = > 100 ) )
end
2008-01-15 21:12:12 +03:00
end
elsif sep == '#'
2010-02-18 21:53:30 +03:00
oid = identifier . to_i
2008-01-15 21:12:12 +03:00
case prefix
when nil
2009-11-14 15:08:47 +03:00
if issue = Issue . visible . find_by_id ( oid , :include = > :status )
2012-02-15 21:49:31 +04:00
anchor = comment_id ? " note- #{ comment_id } " : nil
link = link_to ( " # #{ oid } " , { :only_path = > only_path , :controller = > 'issues' , :action = > 'show' , :id = > oid , :anchor = > anchor } ,
2009-11-14 15:59:32 +03:00
:class = > issue . css_classes ,
2009-02-21 14:04:50 +03:00
:title = > " #{ truncate ( issue . subject , :length = > 100 ) } ( #{ issue . status . name } ) " )
2008-01-15 21:12:12 +03:00
end
when 'document'
2011-01-23 19:47:59 +03:00
if document = Document . visible . find_by_id ( oid )
2008-02-17 17:17:20 +03:00
link = link_to h ( document . title ) , { :only_path = > only_path , :controller = > 'documents' , :action = > 'show' , :id = > document } ,
:class = > 'document'
2008-01-15 21:12:12 +03:00
end
when 'version'
2011-01-23 19:47:59 +03:00
if version = Version . visible . find_by_id ( oid )
2008-02-17 17:17:20 +03:00
link = link_to h ( version . name ) , { :only_path = > only_path , :controller = > 'versions' , :action = > 'show' , :id = > version } ,
:class = > 'version'
2008-01-15 21:12:12 +03:00
end
2008-08-11 02:18:23 +04:00
when 'message'
2011-01-23 19:47:59 +03:00
if message = Message . visible . find_by_id ( oid , :include = > :parent )
2011-01-23 20:02:10 +03:00
link = link_to_message ( message , { :only_path = > only_path } , :class = > 'message' )
2008-08-11 02:18:23 +04:00
end
2011-11-19 15:16:23 +04:00
when 'forum'
if board = Board . visible . find_by_id ( oid )
link = link_to h ( board . name ) , { :only_path = > only_path , :controller = > 'boards' , :action = > 'show' , :id = > board , :project_id = > board . project } ,
:class = > 'board'
end
when 'news'
if news = News . visible . find_by_id ( oid )
link = link_to h ( news . title ) , { :only_path = > only_path , :controller = > 'news' , :action = > 'show' , :id = > news } ,
:class = > 'news'
end
2010-02-13 13:32:06 +03:00
when 'project'
if p = Project . visible . find_by_id ( oid )
2010-08-08 11:07:20 +04:00
link = link_to_project ( p , { :only_path = > only_path } , :class = > 'project' )
2010-02-13 13:32:06 +03:00
end
2008-01-15 21:12:12 +03:00
end
elsif sep == ':'
# removes the double quotes if any
2010-02-18 21:53:30 +03:00
name = identifier . gsub ( %r{ ^"(.*)"$ } , " \\ 1 " )
2008-01-15 21:12:12 +03:00
case prefix
when 'document'
2011-01-23 19:47:59 +03:00
if project && document = project . documents . visible . find_by_title ( name )
2008-02-17 17:17:20 +03:00
link = link_to h ( document . title ) , { :only_path = > only_path , :controller = > 'documents' , :action = > 'show' , :id = > document } ,
:class = > 'document'
2008-01-15 21:12:12 +03:00
end
when 'version'
2011-01-23 19:47:59 +03:00
if project && version = project . versions . visible . find_by_name ( name )
2008-02-17 17:17:20 +03:00
link = link_to h ( version . name ) , { :only_path = > only_path , :controller = > 'versions' , :action = > 'show' , :id = > version } ,
:class = > 'version'
2008-01-15 21:12:12 +03:00
end
2011-11-19 15:16:23 +04:00
when 'forum'
if project && board = project . boards . visible . find_by_name ( name )
link = link_to h ( board . name ) , { :only_path = > only_path , :controller = > 'boards' , :action = > 'show' , :id = > board , :project_id = > board . project } ,
:class = > 'board'
end
when 'news'
if project && news = project . news . visible . find_by_title ( name )
link = link_to h ( news . title ) , { :only_path = > only_path , :controller = > 'news' , :action = > 'show' , :id = > news } ,
:class = > 'news'
end
2012-01-22 18:23:10 +04:00
when 'commit' , 'source' , 'export'
if project
repository = nil
if name =~ %r{ ^(([a-z0-9 \ -]+) \ |)(.+)$ }
repo_prefix , repo_identifier , name = $1 , $2 , $3
repository = project . repositories . detect { | repo | repo . identifier == repo_identifier }
else
repository = project . repository
end
if prefix == 'commit'
if repository && ( changeset = Changeset . visible . find ( :first , :conditions = > [ " repository_id = ? AND scmid LIKE ? " , repository . id , " #{ name } % " ] ) )
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 } ,
:class = > 'changeset' ,
:title = > truncate_single_line ( h ( changeset . comments ) , :length = > 100 )
end
else
if repository && User . current . allowed_to? ( :browse_repository , project )
name =~ %r{ ^[/ \\ ]*(.*?)(@([0-9a-f]+))?( # (L \ d+))?$ }
path , rev , anchor = $1 , $3 , $5
link = link_to h ( " #{ project_prefix } #{ prefix } : #{ repo_prefix } #{ name } " ) , { :controller = > 'repositories' , :action = > 'entry' , :id = > project , :repository_id = > repository . identifier_param ,
:path = > to_path_param ( path ) ,
:rev = > rev ,
:anchor = > anchor ,
:format = > ( prefix == 'export' ? 'raw' : nil ) } ,
:class = > ( prefix == 'export' ? 'source download' : 'source' )
end
end
repo_prefix = nil
2008-03-12 23:28:49 +03:00
end
2008-01-15 21:12:12 +03:00
when 'attachment'
2010-03-14 11:33:53 +03:00
attachments = options [ :attachments ] || ( obj && obj . respond_to? ( :attachments ) ? obj . attachments : nil )
2008-01-15 21:12:12 +03:00
if attachments && attachment = attachments . detect { | a | a . filename == name }
2008-02-17 17:17:20 +03:00
link = link_to h ( attachment . filename ) , { :only_path = > only_path , :controller = > 'attachments' , :action = > 'download' , :id = > attachment } ,
:class = > 'attachment'
2008-01-15 21:12:12 +03:00
end
2010-02-13 13:32:06 +03:00
when 'project'
if p = Project . visible . find ( :first , :conditions = > [ " identifier = :s OR LOWER(name) = :s " , { :s = > name . downcase } ] )
2010-08-08 11:07:20 +04:00
link = link_to_project ( p , { :only_path = > only_path } , :class = > 'project' )
2010-02-13 13:32:06 +03:00
end
2008-01-15 21:12:12 +03:00
end
2007-09-08 00:07:54 +04:00
end
2007-05-26 19:42:37 +04:00
end
2012-02-15 21:49:31 +04:00
( leading + ( link || " #{ project_prefix } #{ prefix } #{ repo_prefix } #{ sep } #{ identifier } #{ comment_suffix } " ) ) . html_safe
2007-05-26 19:42:37 +04:00
end
2007-03-12 20:59:02 +03:00
end
2011-05-18 06:46:24 +04:00
2011-11-18 20:25:00 +04:00
HEADING_RE = / (<h(1|2|3|4)( [^>]+)?>(.+?)< \/ h(1|2|3|4)>) /i unless const_defined? ( :HEADING_RE )
def parse_sections ( text , project , obj , attr , only_path , options )
return unless options [ :edit_section_links ]
text . gsub! ( HEADING_RE ) do
2011-11-18 22:22:41 +04:00
@current_section += 1
if @current_section > 1
2011-11-18 20:25:00 +04:00
content_tag ( 'div' ,
2011-11-18 22:22:41 +04:00
link_to ( image_tag ( 'edit.png' ) , options [ :edit_section_links ] . merge ( :section = > @current_section ) ) ,
2011-11-18 20:25:00 +04:00
:class = > 'contextual' ,
:title = > l ( :button_edit_section ) ) + $1
else
$1
end
end
end
2011-05-18 06:46:24 +04:00
2010-11-06 20:47:27 +03:00
# Headings and TOC
2010-12-29 21:21:22 +03:00
# Adds ids and links to headings unless options[:headings] is set to false
2010-11-06 20:47:27 +03:00
def parse_headings ( text , project , obj , attr , only_path , options )
2010-12-29 21:21:22 +03:00
return if options [ :headings ] == false
2011-05-18 06:46:24 +04:00
2010-11-06 20:47:27 +03:00
text . gsub! ( HEADING_RE ) do
2011-11-18 20:25:00 +04:00
level , attrs , content = $2 . to_i , $3 , $4
2010-11-06 20:47:27 +03:00
item = strip_tags ( content ) . strip
2011-10-02 21:25:29 +04:00
anchor = sanitize_anchor_name ( item )
2011-10-02 19:57:17 +04:00
# used for single-file wiki export
anchor = " #{ obj . page . title } _ #{ anchor } " if options [ :wiki_links ] == :anchor && ( obj . is_a? ( WikiContent ) || obj . is_a? ( WikiContent :: Version ) )
2012-02-14 12:09:23 +04:00
@heading_anchors [ anchor ] || = 0
idx = ( @heading_anchors [ anchor ] += 1 )
if idx > 1
anchor = " #{ anchor } - #{ idx } "
end
2010-12-29 21:21:22 +03:00
@parsed_headings << [ level , anchor , item ]
2011-03-15 01:01:43 +03:00
" <a name= \" #{ anchor } \" ></a> \n <h #{ level } #{ attrs } > #{ content } <a href= \" # #{ anchor } \" class= \" wiki-anchor \" >¶</a></h #{ level } > "
2010-12-29 21:21:22 +03:00
end
end
2011-05-18 06:46:24 +04:00
2011-11-18 20:25:00 +04:00
MACROS_RE = /
( ! ) ? # escaping
(
\ { \ { # opening tag
( [ \ w ] + ) # macro name
( \ ( ( [ ^ \ } ] * ) \ ) ) ? # optional arguments
\ } \ } # closing tag
)
/ x unless const_defined?(:MACROS_RE)
# Macros substitution
def parse_macros ( text , project , obj , attr , only_path , options )
text . gsub! ( MACROS_RE ) do
esc , all , macro = $1 , $2 , $3 . downcase
args = ( $5 || '' ) . split ( ',' ) . each ( & :strip )
if esc . nil?
begin
exec_macro ( macro , obj , args )
rescue = > e
" <div class= \" flash error \" >Error executing the <strong> #{ macro } </strong> macro ( #{ e } )</div> "
end || all
else
all
end
end
end
2010-12-29 21:21:22 +03:00
TOC_RE = / <p> \ { \ {([<>]?)toc \ } \ }< \/ p> /i unless const_defined? ( :TOC_RE )
2011-05-18 06:46:24 +04:00
2010-12-29 21:21:22 +03:00
# Renders the TOC with given headings
def replace_toc ( text , headings )
2010-11-06 20:47:27 +03:00
text . gsub! ( TOC_RE ) do
if headings . empty?
''
else
div_class = 'toc'
div_class << ' right' if $1 == '>'
div_class << ' left' if $1 == '<'
2010-11-06 21:52:07 +03:00
out = " <ul class= \" #{ div_class } \" ><li> "
root = headings . map ( & :first ) . min
current = root
started = false
2010-11-06 20:47:27 +03:00
headings . each do | level , anchor , item |
2010-11-06 21:52:07 +03:00
if level > current
out << '<ul><li>' * ( level - current )
elsif level < current
out << " </li></ul> \n " * ( current - level ) + " </li><li> "
elsif started
out << '</li><li>'
end
out << " <a href= \" # #{ anchor } \" > #{ item } </a> "
current = level
started = true
2010-11-06 20:47:27 +03:00
end
2010-11-06 21:52:07 +03:00
out << '</li></ul>' * ( current - root )
out << '</li></ul>'
2010-11-06 20:47:27 +03:00
end
end
end
2008-11-07 17:35:18 +03:00
2007-07-14 15:25:03 +04:00
# Same as Rails' simple_format helper without using paragraphs
def simple_format_without_paragraph ( text )
text . to_s .
gsub ( / \ r \ n? / , " \n " ) . # \r\n and \r -> \n
gsub ( / \ n \ n+ / , " <br /><br /> " ) . # 2+ newline -> 2 br
2011-10-06 15:03:58 +04:00
gsub ( / ([^ \ n] \ n)(?=[^ \ n]) / , '\1<br />' ) . # 1 newline -> br
html_safe
2007-07-14 15:25:03 +04:00
end
2008-11-07 17:35:18 +03:00
2007-03-12 20:59:02 +03:00
def lang_options_for_select ( blank = true )
2008-11-07 17:35:18 +03:00
( blank ? [ [ " (auto) " , " " ] ] : [ ] ) +
2009-02-21 14:04:50 +03:00
valid_languages . collect { | lang | [ ll ( lang . to_s , :general_lang_name ) , lang . to_s ] } . sort { | x , y | x . last < = > y . last }
2007-03-12 20:59:02 +03:00
end
2008-11-07 17:35:18 +03:00
2007-03-12 20:59:02 +03:00
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
2008-11-07 17:35:18 +03:00
2011-11-23 23:44:46 +04:00
def labelled_tabular_form_for ( * args , & proc )
2011-12-09 22:15:55 +04:00
ActiveSupport :: Deprecation . warn " ApplicationHelper # labelled_tabular_form_for is deprecated and will be removed in Redmine 1.5. Use # labelled_form_for instead. "
2011-11-23 23:44:46 +04:00
args << { } unless args . last . is_a? ( Hash )
options = args . last
2007-03-12 20:59:02 +03:00
options [ :html ] || = { }
2008-02-29 22:46:58 +03:00
options [ :html ] [ :class ] = 'tabular' unless options [ :html ] . has_key? ( :class )
2011-12-09 22:45:38 +04:00
options . merge! ( { :builder = > Redmine :: Views :: LabelledFormBuilder } )
2011-11-23 23:44:46 +04:00
form_for ( * args , & proc )
2007-03-12 20:59:02 +03:00
end
2008-11-07 17:35:18 +03:00
2011-11-26 21:56:52 +04:00
def labelled_form_for ( * args , & proc )
args << { } unless args . last . is_a? ( Hash )
options = args . last
2011-12-09 22:45:38 +04:00
options . merge! ( { :builder = > Redmine :: Views :: LabelledFormBuilder } )
2011-11-26 21:56:52 +04:00
form_for ( * args , & proc )
end
2011-12-09 22:40:28 +04:00
def labelled_fields_for ( * args , & proc )
args << { } unless args . last . is_a? ( Hash )
options = args . last
2011-12-09 22:45:38 +04:00
options . merge! ( { :builder = > Redmine :: Views :: LabelledFormBuilder } )
2011-12-09 22:40:28 +04:00
fields_for ( * args , & proc )
end
def labelled_remote_form_for ( * args , & proc )
args << { } unless args . last . is_a? ( Hash )
options = args . last
2011-12-09 22:45:38 +04:00
options . merge! ( { :builder = > Redmine :: Views :: LabelledFormBuilder } )
2011-12-09 22:40:28 +04:00
remote_form_for ( * args , & proc )
end
2008-04-16 21:27:53 +04:00
def back_url_hidden_field_tag
2008-07-26 12:46:33 +04:00
back_url = params [ :back_url ] || request . env [ 'HTTP_REFERER' ]
2008-12-31 13:39:33 +03:00
back_url = CGI . unescape ( back_url . to_s )
2008-12-12 19:01:35 +03:00
hidden_field_tag ( 'back_url' , CGI . escape ( back_url ) ) unless back_url . blank?
2008-04-16 21:27:53 +04:00
end
2008-11-07 17:35:18 +03:00
2007-03-12 20:59:02 +03:00
def check_all_links ( form_name )
link_to_function ( l ( :button_check_all ) , " checkAll(' #{ form_name } ', true) " ) +
2011-08-20 15:51:26 +04:00
" | " . html_safe +
2008-11-07 17:35:18 +03:00
link_to_function ( l ( :button_uncheck_all ) , " checkAll(' #{ form_name } ', false) " )
2007-03-12 20:59:02 +03:00
end
2008-11-07 17:35:18 +03:00
2007-12-05 22:21:25 +03:00
def progress_bar ( pcts , options = { } )
pcts = [ pcts , pcts ] unless pcts . is_a? ( Array )
2009-11-21 13:50:36 +03:00
pcts = pcts . collect ( & :round )
2007-12-05 22:21:25 +03:00
pcts [ 1 ] = pcts [ 1 ] - pcts [ 0 ]
pcts << ( 100 - pcts [ 1 ] - pcts [ 0 ] )
2007-11-17 18:34:10 +03:00
width = options [ :width ] || '100px;'
legend = options [ :legend ] || ''
content_tag ( 'table' ,
content_tag ( 'tr' ,
2011-08-20 15:51:49 +04:00
( pcts [ 0 ] > 0 ? content_tag ( 'td' , '' , :style = > " width: #{ pcts [ 0 ] } %; " , :class = > 'closed' ) : '' . html_safe ) +
( pcts [ 1 ] > 0 ? content_tag ( 'td' , '' , :style = > " width: #{ pcts [ 1 ] } %; " , :class = > 'done' ) : '' . html_safe ) +
( pcts [ 2 ] > 0 ? content_tag ( 'td' , '' , :style = > " width: #{ pcts [ 2 ] } %; " , :class = > 'todo' ) : '' . html_safe )
) , :class = > 'progress' , :style = > " width: #{ width } ; " ) . html_safe +
content_tag ( 'p' , legend , :class = > 'pourcent' ) . html_safe
2007-11-17 18:34:10 +03:00
end
2011-05-18 06:46:24 +04:00
2010-03-17 23:46:22 +03:00
def checked_image ( checked = true )
if checked
image_tag 'toggle_check.png'
end
end
2011-05-18 06:46:24 +04:00
2010-03-04 22:02:57 +03:00
def context_menu ( url )
unless @context_menu_included
content_for :header_tags do
javascript_include_tag ( 'context_menu' ) +
stylesheet_link_tag ( 'context_menu' )
end
2010-08-22 23:12:21 +04:00
if l ( :direction ) == 'rtl'
content_for :header_tags do
stylesheet_link_tag ( 'context_menu_rtl' )
end
end
2010-03-04 22:02:57 +03:00
@context_menu_included = true
end
javascript_tag " new ContextMenu(' #{ url_for ( url ) } ') "
end
2008-11-07 17:35:18 +03:00
2007-03-12 20:59:02 +03:00
def calendar_for ( field_id )
2008-04-01 01:48:01 +04:00
include_calendar_headers_tags
2007-03-12 20:59:02 +03:00
image_tag ( " calendar.png " , { :id = > " #{ field_id } _trigger " , :class = > " calendar-trigger " } ) +
javascript_tag ( " Calendar.setup({inputField : ' #{ field_id } ', ifFormat : '%Y-%m-%d', button : ' #{ field_id } _trigger' }); " )
end
2008-04-01 01:48:01 +04:00
def include_calendar_headers_tags
unless @calendar_headers_tags_included
@calendar_headers_tags_included = true
content_for :header_tags do
2009-12-13 07:06:55 +03:00
start_of_week = case Setting . start_of_week . to_i
when 1
'Calendar._FD = 1;' # Monday
when 7
'Calendar._FD = 0;' # Sunday
2011-03-27 19:43:26 +04:00
when 6
'Calendar._FD = 6;' # Saturday
2009-12-13 07:06:55 +03:00
else
'' # use language
end
2011-05-18 06:46:24 +04:00
2008-04-01 01:48:01 +04:00
javascript_include_tag ( 'calendar/calendar' ) +
2009-04-24 21:00:25 +04:00
javascript_include_tag ( " calendar/lang/calendar- #{ current_language . to_s . downcase } .js " ) +
2011-05-18 06:46:24 +04:00
javascript_tag ( start_of_week ) +
2008-04-01 01:48:01 +04:00
javascript_include_tag ( 'calendar/calendar-setup' ) +
stylesheet_link_tag ( 'calendar' )
end
end
end
2008-11-07 17:35:18 +03:00
2007-09-22 17:17:49 +04:00
def content_for ( name , content = nil , & block )
@has_content || = { }
@has_content [ name ] = true
super ( name , content , & block )
end
2008-11-07 17:35:18 +03:00
2007-09-22 17:17:49 +04:00
def has_content? ( name )
( @has_content && @has_content [ name ] ) || false
end
2011-08-20 09:57:14 +04:00
2011-07-03 16:28:54 +04:00
def email_delivery_enabled?
! ! ActionMailer :: Base . perform_deliveries
end
2008-10-27 14:08:29 +03:00
2008-11-09 17:52:16 +03:00
# Returns the avatar image tag for the given +user+ if avatars are enabled
# +user+ can be a User or a string that will be scanned for an email address (eg. 'joe <joe@foo.bar>')
def avatar ( user , options = { } )
2008-10-31 03:41:28 +03:00
if Setting . gravatar_enabled?
2010-09-20 06:55:14 +04:00
options . merge! ( { :ssl = > ( defined? ( request ) && request . ssl? ) , :default = > Setting . gravatar_default } )
2008-11-09 17:52:16 +03:00
email = nil
if user . respond_to? ( :mail )
email = user . mail
elsif user . to_s =~ %r{ <(.+?)> }
email = $1
end
return gravatar ( email . to_s . downcase , options ) unless email . blank? rescue nil
2010-09-10 07:09:02 +04:00
else
''
2008-10-31 03:41:28 +03:00
end
end
2011-05-18 06:46:24 +04:00
2011-10-02 21:25:29 +04:00
def sanitize_anchor_name ( anchor )
anchor . gsub ( %r{ [^ \ w \ s \ -] } , '' ) . gsub ( %r{ \ s+( \ -+ \ s*)? } , '-' )
end
2011-02-21 12:53:29 +03:00
# Returns the javascript tags that are included in the html layout head
def javascript_heads
tags = javascript_include_tag ( :defaults )
unless User . current . pref . warn_on_leaving_unsaved == '0'
2011-08-21 02:53:24 +04:00
tags << " \n " . html_safe + javascript_tag ( " Event.observe(window, 'load', function(){ new WarnLeavingUnsaved(' #{ escape_javascript ( l ( :text_warn_on_leaving_unsaved ) ) } '); }); " )
2011-02-21 12:53:29 +03:00
end
tags
end
2008-10-31 03:41:28 +03:00
2010-07-29 18:58:33 +04:00
def favicon
2011-08-20 09:05:26 +04:00
" <link rel='shortcut icon' href=' #{ image_path ( '/favicon.ico' ) } ' /> " . html_safe
2010-07-29 18:58:33 +04:00
end
2011-04-12 23:22:44 +04:00
def robot_exclusion_tag
2011-11-28 16:20:37 +04:00
'<meta name="robots" content="noindex,follow,noarchive" />' . html_safe
2011-04-12 23:22:44 +04:00
end
2011-05-18 06:46:24 +04:00
2010-12-11 13:19:11 +03:00
# Returns true if arg is expected in the API response
def include_in_api_response? ( arg )
unless @included_in_api_response
param = params [ :include ]
@included_in_api_response = param . is_a? ( Array ) ? param . collect ( & :to_s ) : param . to_s . split ( ',' )
@included_in_api_response . collect! ( & :strip )
end
@included_in_api_response . include? ( arg . to_s )
end
2010-07-29 18:58:33 +04:00
2010-12-11 16:13:49 +03:00
# Returns options or nil if nometa param or X-Redmine-Nometa header
# was set in the request
def api_meta ( options )
if params [ :nometa ] . present? || request . headers [ 'X-Redmine-Nometa' ]
# compatibility mode for activeresource clients that raise
# an error when unserializing an array with attributes
nil
else
options
end
end
2011-05-18 06:46:24 +04:00
2008-10-27 14:08:29 +03:00
private
2008-11-07 17:35:18 +03:00
2008-10-27 14:08:29 +03:00
def wiki_helper
helper = Redmine :: WikiFormatting . helper_for ( Setting . text_formatting )
extend helper
return self
end
2011-05-18 06:46:24 +04:00
2011-04-03 18:01:32 +04:00
def link_to_content_update ( text , url_params = { } , html_options = { } )
2011-04-03 18:06:53 +04:00
link_to ( text , url_params , html_options )
2009-01-26 04:47:51 +03:00
end
2006-06-28 22:11:03 +04:00
end