]> source.dussan.org Git - redmine.git/commitdiff
Redmine links can be used to link to documents, versions and attachments.
authorJean-Philippe Lang <jp_lang@yahoo.fr>
Tue, 15 Jan 2008 18:12:12 +0000 (18:12 +0000)
committerJean-Philippe Lang <jp_lang@yahoo.fr>
Tue, 15 Jan 2008 18:12:12 +0000 (18:12 +0000)
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

app/helpers/application_helper.rb
lib/redcloth.rb
test/fixtures/wiki_contents.yml
test/fixtures/wiki_pages.yml
test/fixtures/wikis.yml
test/unit/helpers/application_helper_test.rb

index e3ac2498fd77991a90d3bafadc2615fdfced7845..b34b5b502242b3aec3937da898706defe5cc8b77 100644 (file)
@@ -220,8 +220,9 @@ module ApplicationHelper
     
     project = options[:project] || @project
     
-    # turn wiki links into html links
-    # example:
+    # Wiki links
+    # 
+    # Examples:
     #   [[mypage]]
     #   [[mypage|mytext]]
     # wiki links can refer other project wikis, using project name or identifier:
@@ -229,47 +230,94 @@ module ApplicationHelper
     #   [[project:|mytext]]
     #   [[project:mypage]]
     #   [[project:mypage|mytext]]
-    text = text.gsub(/\[\[([^\]\|]+)(\|([^\]\|]+))?\]\]/) do |m|
+    text = text.gsub(/(!)?(\[\[([^\]\|]+)(\|([^\]\|]+))?\]\])/) do |m|
       link_project = project
-      page = $1
-      title = $3
-      if page =~ /^([^\:]+)\:(.*)$/
-        link_project = Project.find_by_name($1) || Project.find_by_identifier($1)
-        page = title || $2
-        title = $1 if page.blank?
-      end
-      
-      if link_project && link_project.wiki
-        # check if page exists
-        wiki_page = link_project.wiki.find_page(page)
-        link_to((title || page), format_wiki_link.call(link_project, Wiki.titleize(page)),
-                                 :class => ('wiki-page' + (wiki_page ? '' : ' new')))
+      esc, all, page, title = $1, $2, $3, $5
+      if esc.nil?
+        if page =~ /^([^\:]+)\:(.*)$/
+          link_project = Project.find_by_name($1) || Project.find_by_identifier($1)
+          page = $2
+          title ||= $1 if page.blank?
+        end
+        
+        if link_project && link_project.wiki
+          # check if page exists
+          wiki_page = link_project.wiki.find_page(page)
+          link_to((title || page), format_wiki_link.call(link_project, Wiki.titleize(page)),
+                                   :class => ('wiki-page' + (wiki_page ? '' : ' new')))
+        else
+          # project or wiki doesn't exist
+          title || page
+        end
       else
-        # project or wiki doesn't exist
-        title || page
+        all
       end
     end
 
-    # turn issue and revision ids into links
-    # example:
-    #   #52 -> <a href="/issues/show/52">#52</a>
-    #   r52 -> <a href="/repositories/revision/6?rev=52">r52</a> (project.id is 6)
-    text = text.gsub(%r{([\s\(,-^])(#|r)(\d+)(?=[[:punct:]]|\s|<|$)}) do |m|
-      leading, otype, oid = $1, $2, $3
+    # Redmine links
+    # 
+    # Examples:
+    #   Issues:
+    #     #52 -> Link to issue #52
+    #   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
-      if otype == 'r'
-        if project && (changeset = project.changesets.find_by_revision(oid))
-          link = link_to("r#{oid}", {:controller => 'repositories', :action => 'revision', :id => project.id, :rev => oid}, :class => 'changeset',
-                                    :title => truncate(changeset.comments, 100))
-        end
-      else
-        if issue = Issue.find_by_id(oid.to_i, :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?
+      if esc.nil?
+        if prefix.nil? && sep == 'r'
+          if project && (changeset = project.changesets.find_by_revision(oid))
+            link = link_to("r#{oid}", {:controller => 'repositories', :action => 'revision', :id => project.id, :rev => oid}, :class => 'changeset',
+                                      :title => truncate(changeset.comments, 100))
+          end
+        elsif sep == '#'
+          oid = oid.to_i
+          case prefix
+          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
-      leading + (link || "#{otype}#{oid}")
+      leading + (link || "#{prefix}#{sep}#{oid}")
     end
     
     text
index ae70db747868e1b915fa7fb3becf8babd17a9d2b..904701c9e31c7980faf9466db0dec65930b50477 100644 (file)
@@ -395,15 +395,15 @@ class RedCloth < String
     # Elements to handle
     GLYPHS = [
     #   [ /([^\s\[{(>])?\'([dmst]\b|ll\b|ve\b|\s|:|$)/, '\1&#8217;\2' ], # single closing
-        [ /([^\s\[{(>#{PUNCT_Q}][#{PUNCT_Q}]*)\'/, '\1&#8217;' ], # single closing
-        [ /\'(?=[#{PUNCT_Q}]*(s\b|[\s#{PUNCT_NOQ}]))/, '&#8217;' ], # single closing
-        [ /\'/, '&#8216;' ], # single opening
+    #   [ /([^\s\[{(>#{PUNCT_Q}][#{PUNCT_Q}]*)\'/, '\1&#8217;' ], # single closing
+    #   [ /\'(?=[#{PUNCT_Q}]*(s\b|[\s#{PUNCT_NOQ}]))/, '&#8217;' ], # single closing
+    #   [ /\'/, '&#8216;' ], # single opening
         [ /</, '&lt;' ], # less-than
         [ />/, '&gt;' ], # greater-than
     #   [ /([^\s\[{(])?"(\s|:|$)/, '\1&#8221;\2' ], # double closing
-        [ /([^\s\[{(>#{PUNCT_Q}][#{PUNCT_Q}]*)"/, '\1&#8221;' ], # double closing
-        [ /"(?=[#{PUNCT_Q}]*[\s#{PUNCT_NOQ}])/, '&#8221;' ], # double closing
-        [ /"/, '&#8220;' ], # double opening
+    #   [ /([^\s\[{(>#{PUNCT_Q}][#{PUNCT_Q}]*)"/, '\1&#8221;' ], # double closing
+    #   [ /"(?=[#{PUNCT_Q}]*[\s#{PUNCT_NOQ}])/, '&#8221;' ], # double closing
+    #   [ /"/, '&#8220;' ], # double opening
         [ /\b( )?\.{3}/, '\1&#8230;' ], # ellipsis
         [ /\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
index a230b9c081adba7cb8bb106ce2cc6563cfacc8f5..6937dbd14814630166424de19ea2bc9e0636e381 100644 (file)
@@ -21,4 +21,14 @@ wiki_contents_002:
   version: 1\r
   author_id: 1\r
   comments: \r
-  
\ No newline at end of file
+wiki_contents_003: \r
+  text: |-\r
+    h1. Start page\r
+    \r
+    E-commerce web site start page\r
+  updated_on: 2007-03-08 00:18:07 +01:00\r
+  page_id: 3\r
+  id: 3\r
+  version: 1\r
+  author_id: 1\r
+  comments: \r
index ca9d6f5dc403c387f2cc5d9baee0e36eb13a36eb..ee260291d8f42c5f7537ddc3f456894be3386e92 100644 (file)
@@ -9,4 +9,9 @@ wiki_pages_002:
   title: Another_page\r
   id: 2\r
   wiki_id: 1\r
+wiki_pages_003: \r
+  created_on: 2007-03-08 00:18:07 +01:00\r
+  title: Start_page\r
+  id: 3\r
+  wiki_id: 2\r
   
\ No newline at end of file
index ff7b4a1ae99e29bf25c3bbcb2dce5ffeb8e29b6d..dd1c55ceaba5c54ddbd7982f49f20e11765144a7 100644 (file)
@@ -4,3 +4,9 @@ wikis_001:
   start_page: CookBook documentation\r
   project_id: 1\r
   id: 1\r
+wikis_002: \r
+  status: 1\r
+  start_page: Start page\r
+  project_id: 2\r
+  id: 2\r
+  
\ No newline at end of file
index 2af6c55994ff86b5529e7d743b73e0246bc22d5c..33509cfc02e5233ed09e8d83f98b728998ec3f50 100644 (file)
@@ -20,7 +20,7 @@ require File.dirname(__FILE__) + '/../../test_helper'
 class ApplicationHelperTest < HelperTestCase
   include ApplicationHelper
   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
     super
@@ -66,12 +66,52 @@ class ApplicationHelperTest < HelperTestCase
   def test_redmine_links
     issue_link = link_to('#3', {:controller => 'issues', :action => 'show', :id => 3}, 
                                :class => 'issue', :title => 'Error 281 when updating a recipe (New)')
+    
     changeset_link = link_to('r1', {:controller => 'repositories', :action => 'revision', :id => 1, :rev => 1},
                                    :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 = {
       '#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)
     to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }