Redmine links can be used to link to documents, versions and attachments.

For now, attachments of the current object can be referenced only (if you're on an issue, it's possible reference attachments of this issue only).

git-svn-id: http://redmine.rubyforge.org/svn/trunk@1064 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
Jean-Philippe Lang 2008-01-15 18:12:12 +00:00
parent 4e1e5985a1
commit 702b521b45
6 changed files with 153 additions and 44 deletions

View File

@ -220,8 +220,9 @@ module ApplicationHelper
project = options[:project] || @project project = options[:project] || @project
# turn wiki links into html links # Wiki links
# example: #
# Examples:
# [[mypage]] # [[mypage]]
# [[mypage|mytext]] # [[mypage|mytext]]
# wiki links can refer other project wikis, using project name or identifier: # wiki links can refer other project wikis, using project name or identifier:
@ -229,47 +230,94 @@ module ApplicationHelper
# [[project:|mytext]] # [[project:|mytext]]
# [[project:mypage]] # [[project:mypage]]
# [[project:mypage|mytext]] # [[project:mypage|mytext]]
text = text.gsub(/\[\[([^\]\|]+)(\|([^\]\|]+))?\]\]/) do |m| text = text.gsub(/(!)?(\[\[([^\]\|]+)(\|([^\]\|]+))?\]\])/) do |m|
link_project = project link_project = project
page = $1 esc, all, page, title = $1, $2, $3, $5
title = $3 if esc.nil?
if page =~ /^([^\:]+)\:(.*)$/ if page =~ /^([^\:]+)\:(.*)$/
link_project = Project.find_by_name($1) || Project.find_by_identifier($1) link_project = Project.find_by_name($1) || Project.find_by_identifier($1)
page = title || $2 page = $2
title = $1 if page.blank? title ||= $1 if page.blank?
end end
if link_project && link_project.wiki if link_project && link_project.wiki
# check if page exists # check if page exists
wiki_page = link_project.wiki.find_page(page) wiki_page = link_project.wiki.find_page(page)
link_to((title || page), format_wiki_link.call(link_project, Wiki.titleize(page)), link_to((title || page), format_wiki_link.call(link_project, Wiki.titleize(page)),
:class => ('wiki-page' + (wiki_page ? '' : ' new'))) :class => ('wiki-page' + (wiki_page ? '' : ' new')))
else
# project or wiki doesn't exist
title || page
end
else else
# project or wiki doesn't exist all
title || page
end end
end end
# turn issue and revision ids into links # Redmine links
# example: #
# #52 -> <a href="/issues/show/52">#52</a> # Examples:
# r52 -> <a href="/repositories/revision/6?rev=52">r52</a> (project.id is 6) # Issues:
text = text.gsub(%r{([\s\(,-^])(#|r)(\d+)(?=[[:punct:]]|\s|<|$)}) do |m| # #52 -> Link to issue #52
leading, otype, oid = $1, $2, $3 # Changesets:
# r52 -> Link to revision 52
# 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
text = text.gsub(%r{([\s\(,-^])(!)?(attachment|document|version)?((#|r)(\d+)|(:)([^"][^\s<>]+|"[^"]+"))(?=[[:punct:]]|\s|<|$)}) do |m|
leading, esc, prefix, sep, oid = $1, $2, $3, $5 || $7, $6 || $8
link = nil link = nil
if otype == 'r' if esc.nil?
if project && (changeset = project.changesets.find_by_revision(oid)) if prefix.nil? && sep == 'r'
link = link_to("r#{oid}", {:controller => 'repositories', :action => 'revision', :id => project.id, :rev => oid}, :class => 'changeset', if project && (changeset = project.changesets.find_by_revision(oid))
:title => truncate(changeset.comments, 100)) link = link_to("r#{oid}", {:controller => 'repositories', :action => 'revision', :id => project.id, :rev => oid}, :class => 'changeset',
end :title => truncate(changeset.comments, 100))
else end
if issue = Issue.find_by_id(oid.to_i, :include => [:project, :status], :conditions => Project.visible_by(User.current)) elsif sep == '#'
link = link_to("##{oid}", {:controller => 'issues', :action => 'show', :id => oid}, :class => 'issue', oid = oid.to_i
:title => "#{truncate(issue.subject, 100)} (#{issue.status.name})") case prefix
link = content_tag('del', link) if issue.closed? when nil
if issue = Issue.find_by_id(oid, :include => [:project, :status], :conditions => Project.visible_by(User.current))
link = link_to("##{oid}", {:controller => 'issues', :action => 'show', :id => oid}, :class => 'issue',
:title => "#{truncate(issue.subject, 100)} (#{issue.status.name})")
link = content_tag('del', link) if issue.closed?
end
when 'document'
if document = Document.find_by_id(oid, :include => [:project], :conditions => Project.visible_by(User.current))
link = link_to h(document.title), {:controller => 'documents', :action => 'show', :id => document}, :class => 'document'
end
when 'version'
if version = Version.find_by_id(oid, :include => [:project], :conditions => Project.visible_by(User.current))
link = link_to h(version.name), {:controller => 'versions', :action => 'show', :id => version}, :class => 'version'
end
end
elsif sep == ':'
# removes the double quotes if any
name = oid.gsub(%r{^"(.*)"$}, "\\1")
case prefix
when 'document'
if project && document = project.documents.find_by_title(name)
link = link_to h(document.title), {:controller => 'documents', :action => 'show', :id => document}, :class => 'document'
end
when 'version'
if project && version = project.versions.find_by_name(name)
link = link_to h(version.name), {:controller => 'versions', :action => 'show', :id => version}, :class => 'version'
end
when 'attachment'
if attachments && attachment = attachments.detect {|a| a.filename == name }
link = link_to h(attachment.filename), {:controller => 'attachments', :action => 'download', :id => attachment}, :class => 'attachment'
end
end
end end
end end
leading + (link || "#{otype}#{oid}") leading + (link || "#{prefix}#{sep}#{oid}")
end end
text text

View File

@ -395,15 +395,15 @@ class RedCloth < String
# Elements to handle # Elements to handle
GLYPHS = [ GLYPHS = [
# [ /([^\s\[{(>])?\'([dmst]\b|ll\b|ve\b|\s|:|$)/, '\1&#8217;\2' ], # single closing # [ /([^\s\[{(>])?\'([dmst]\b|ll\b|ve\b|\s|:|$)/, '\1&#8217;\2' ], # single closing
[ /([^\s\[{(>#{PUNCT_Q}][#{PUNCT_Q}]*)\'/, '\1&#8217;' ], # single closing # [ /([^\s\[{(>#{PUNCT_Q}][#{PUNCT_Q}]*)\'/, '\1&#8217;' ], # single closing
[ /\'(?=[#{PUNCT_Q}]*(s\b|[\s#{PUNCT_NOQ}]))/, '&#8217;' ], # single closing # [ /\'(?=[#{PUNCT_Q}]*(s\b|[\s#{PUNCT_NOQ}]))/, '&#8217;' ], # single closing
[ /\'/, '&#8216;' ], # single opening # [ /\'/, '&#8216;' ], # single opening
[ /</, '&lt;' ], # less-than [ /</, '&lt;' ], # less-than
[ />/, '&gt;' ], # greater-than [ />/, '&gt;' ], # greater-than
# [ /([^\s\[{(])?"(\s|:|$)/, '\1&#8221;\2' ], # double closing # [ /([^\s\[{(])?"(\s|:|$)/, '\1&#8221;\2' ], # double closing
[ /([^\s\[{(>#{PUNCT_Q}][#{PUNCT_Q}]*)"/, '\1&#8221;' ], # double closing # [ /([^\s\[{(>#{PUNCT_Q}][#{PUNCT_Q}]*)"/, '\1&#8221;' ], # double closing
[ /"(?=[#{PUNCT_Q}]*[\s#{PUNCT_NOQ}])/, '&#8221;' ], # double closing # [ /"(?=[#{PUNCT_Q}]*[\s#{PUNCT_NOQ}])/, '&#8221;' ], # double closing
[ /"/, '&#8220;' ], # double opening # [ /"/, '&#8220;' ], # double opening
[ /\b( )?\.{3}/, '\1&#8230;' ], # ellipsis [ /\b( )?\.{3}/, '\1&#8230;' ], # ellipsis
[ /\b([A-Z][A-Z0-9]{2,})\b(?:[(]([^)]*)[)])/, '<acronym title="\2">\1</acronym>' ], # 3+ uppercase acronym [ /\b([A-Z][A-Z0-9]{2,})\b(?:[(]([^)]*)[)])/, '<acronym title="\2">\1</acronym>' ], # 3+ uppercase acronym
[ /(^|[^"][>\s])([A-Z][A-Z0-9 ]+[A-Z0-9])([^<A-Za-z0-9]|$)/, '\1<span class="caps">\2</span>\3', :no_span_caps ], # 3+ uppercase caps [ /(^|[^"][>\s])([A-Z][A-Z0-9 ]+[A-Z0-9])([^<A-Za-z0-9]|$)/, '\1<span class="caps">\2</span>\3', :no_span_caps ], # 3+ uppercase caps

View File

@ -21,4 +21,14 @@ wiki_contents_002:
version: 1 version: 1
author_id: 1 author_id: 1
comments: comments:
wiki_contents_003:
text: |-
h1. Start page
E-commerce web site start page
updated_on: 2007-03-08 00:18:07 +01:00
page_id: 3
id: 3
version: 1
author_id: 1
comments:

View File

@ -9,4 +9,9 @@ wiki_pages_002:
title: Another_page title: Another_page
id: 2 id: 2
wiki_id: 1 wiki_id: 1
wiki_pages_003:
created_on: 2007-03-08 00:18:07 +01:00
title: Start_page
id: 3
wiki_id: 2

View File

@ -4,3 +4,9 @@ wikis_001:
start_page: CookBook documentation start_page: CookBook documentation
project_id: 1 project_id: 1
id: 1 id: 1
wikis_002:
status: 1
start_page: Start page
project_id: 2
id: 2

View File

@ -20,7 +20,7 @@ require File.dirname(__FILE__) + '/../../test_helper'
class ApplicationHelperTest < HelperTestCase class ApplicationHelperTest < HelperTestCase
include ApplicationHelper include ApplicationHelper
include ActionView::Helpers::TextHelper include ActionView::Helpers::TextHelper
fixtures :projects, :repositories, :changesets, :trackers, :issue_statuses, :issues fixtures :projects, :repositories, :changesets, :trackers, :issue_statuses, :issues, :documents, :versions, :wikis, :wiki_pages, :wiki_contents
def setup def setup
super super
@ -66,12 +66,52 @@ class ApplicationHelperTest < HelperTestCase
def test_redmine_links def test_redmine_links
issue_link = link_to('#3', {:controller => 'issues', :action => 'show', :id => 3}, issue_link = link_to('#3', {:controller => 'issues', :action => 'show', :id => 3},
:class => 'issue', :title => 'Error 281 when updating a recipe (New)') :class => 'issue', :title => 'Error 281 when updating a recipe (New)')
changeset_link = link_to('r1', {:controller => 'repositories', :action => 'revision', :id => 1, :rev => 1}, changeset_link = link_to('r1', {:controller => 'repositories', :action => 'revision', :id => 1, :rev => 1},
:class => 'changeset', :title => 'My very first commit') :class => 'changeset', :title => 'My very first commit')
document_link = link_to('Test document', {:controller => 'documents', :action => 'show', :id => 1},
:class => 'document')
version_link = link_to('1.0', {:controller => 'versions', :action => 'show', :id => 2},
:class => 'version')
to_test = { to_test = {
'#3, #3 and #3.' => "#{issue_link}, #{issue_link} and #{issue_link}.", '#3, #3 and #3.' => "#{issue_link}, #{issue_link} and #{issue_link}.",
'r1' => changeset_link 'r1' => changeset_link,
'document#1' => document_link,
'document:"Test document"' => document_link,
'version#2' => version_link,
'version:1.0' => version_link,
'version:"1.0"' => version_link,
# escaping
'!#3.' => '#3.',
'!r1' => 'r1',
'!document#1' => 'document#1',
'!document:"Test document"' => 'document:"Test document"',
'!version#2' => 'version#2',
'!version:1.0' => 'version:1.0',
'!version:"1.0"' => 'version:"1.0"',
}
@project = Project.find(1)
to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
end
def test_wiki_links
to_test = {
'[[CookBook documentation]]' => '<a href="/wiki/ecookbook/CookBook_documentation" class="wiki-page">CookBook documentation</a>',
'[[Another page|Page]]' => '<a href="/wiki/ecookbook/Another_page" class="wiki-page">Page</a>',
# page that doesn't exist
'[[Unknown page]]' => '<a href="/wiki/ecookbook/Unknown_page" class="wiki-page new">Unknown page</a>',
'[[Unknown page|404]]' => '<a href="/wiki/ecookbook/Unknown_page" class="wiki-page new">404</a>',
# link to another project wiki
'[[onlinestore:]]' => '<a href="/wiki/onlinestore/" class="wiki-page">onlinestore</a>',
'[[onlinestore:|Wiki]]' => '<a href="/wiki/onlinestore/" class="wiki-page">Wiki</a>',
'[[onlinestore:Start page]]' => '<a href="/wiki/onlinestore/Start_page" class="wiki-page">Start page</a>',
'[[onlinestore:Start page|Text]]' => '<a href="/wiki/onlinestore/Start_page" class="wiki-page">Text</a>',
'[[onlinestore:Unknown page]]' => '<a href="/wiki/onlinestore/Unknown_page" class="wiki-page new">Unknown page</a>',
# escaping
'![[Another page|Page]]' => '[[Another page|Page]]',
} }
@project = Project.find(1) @project = Project.find(1)
to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) } to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }