Better handling of external link style assignment.
[gitredmine.git] / lib / redmine / wiki_formatting.rb
blobda04dd932facd752cd53151376139fc9e60fe401
1 require 'redcloth'
2 require 'coderay'
3 require 'pp'
4 module Redmine
5   module WikiFormatting
6   
7   private
8   
9     class TextileFormatter < RedCloth      
10       RULES = [:inline_auto_link, :inline_auto_mailto, :textile, :inline_toc]
11       
12       def initialize(*args)
13         super
14         self.hard_breaks=true
15         self.no_span_caps=true
16       end
17       
18       def to_html
19         @toc = []
20         super(*RULES).to_s
21       end
23     private
25       # Patch for RedCloth.  Fixed in RedCloth r128 but _why hasn't released it yet.
26       # <a href="http://code.whytheluckystiff.net/redcloth/changeset/128">http://code.whytheluckystiff.net/redcloth/changeset/128</a>
27       def hard_break( text ) 
28         text.gsub!( /(.)\n(?!\n|\Z| *([#*=]+(\s|$)|[{|]))/, "\\1<br />" ) if hard_breaks 
29       end
30       
31       # Patch to add code highlighting support to RedCloth
32       def smooth_offtags( text )
33         unless @pre_list.empty?
34           ## replace <pre> content
35           text.gsub!(/<redpre#(\d+)>/) do
36             content = @pre_list[$1.to_i]
37             if content.match(/<code\s+class="(\w+)">\s?(.+)/m)
38               content = "<code class=\"#{$1} CodeRay\">" + 
39                 CodeRay.scan($2, $1).html(:escape => false, :line_numbers => :inline)
40             end
41             content
42           end
43         end
44       end
45       
46       # Patch to add 'table of content' support to RedCloth
47       def textile_p_withtoc(tag, atts, cite, content)
48         if tag =~ /^h(\d)$/
49           @toc << [$1.to_i, content]
50         end
51         content = "<a name=\"#{@toc.length}\" class=\"wiki-page\"></a>" + content
52         textile_p(tag, atts, cite, content)
53       end
55       alias :textile_h1 :textile_p_withtoc
56       alias :textile_h2 :textile_p_withtoc
57       alias :textile_h3 :textile_p_withtoc
58       
59       def inline_toc(text)
60         text.gsub!(/<p>\{\{([<>]?)toc\}\}<\/p>/i) do
61           div_class = 'toc'
62           div_class << ' right' if $1 == '>'
63           div_class << ' left' if $1 == '<'
64           out = "<div class=\"#{div_class}\">"
65           @toc.each_with_index do |heading, index|
66             # remove wiki links from the item
67             toc_item = heading.last.gsub(/(\[\[|\]\])/, '')
68             out << "<a href=\"##{index+1}\" class=\"heading#{heading.first}\">#{toc_item}</a>"
69           end
70           out << '</div>'
71           out
72         end
73       end
74       
75       AUTO_LINK_RE = %r{
76                         (                          # leading text
77                           <\w+.*?>|                # leading HTML tag, or
78                           [^=<>!:'"/]|             # leading punctuation, or 
79                           ^                        # beginning of line
80                         )
81                         (
82                           (?:https?://)|           # protocol spec, or
83                           (?:www\.)                # www.*
84                         )
85                         (
86                           (\S+?)                   # url
87                           (\/)?                    # slash
88                         )
89                         ([^\w\=\/;]*?)               # post
90                         (?=<|\s|$)
91                        }x unless const_defined?(:AUTO_LINK_RE)
93       # Turns all urls into clickable links (code from Rails).
94       def inline_auto_link(text)
95         text.gsub!(AUTO_LINK_RE) do
96           all, leading, proto, url, post = $&, $1, $2, $3, $6
97           if leading =~ /<a\s/i || leading =~ /![<>=]?/
98             # don't replace URL's that are already linked
99             # and URL's prefixed with ! !> !< != (textile images)
100             all
101           else            
102             %(#{leading}<a class="external" href="#{proto=="www."?"http://www.":proto}#{url}">#{proto + url}</a>#{post})
103           end
104         end
105       end
106       
107       # Turns all email addresses into clickable links (code from Rails).
108       def inline_auto_mailto(text)
109         text.gsub!(/([\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do
110           text = $1
111           %{<a href="mailto:#{$1}" class="email">#{text}</a>}
112         end
113       end
114     end
115     
116   public
117   
118     def self.to_html(text, options = {})
119       TextileFormatter.new(text).to_html    
120     end
121   end