Allow redcarpet to add nofollow to links
[rails.git] / lib / rich_text.rb
1 module RichText
2   def self.new(format, text)
3     case format
4     when "html" then HTML.new(text || "")
5     when "markdown" then Markdown.new(text || "")
6     when "text" then Text.new(text || "")
7     end
8   end
9
10   class SimpleFormat
11     include ActionView::Helpers::TextHelper
12     include ActionView::Helpers::OutputSafetyHelper
13
14     def sanitize(text)
15       Sanitize.clean(text, Sanitize::Config::OSM).html_safe
16     end
17   end
18
19   class Base < String
20     include ActionView::Helpers::TagHelper
21
22     def spam_score
23       link_count = 0
24       link_size = 0
25
26       doc = Nokogiri::HTML(to_html)
27
28       if doc.content.empty?
29         link_proportion = 0
30       else
31         doc.xpath("//a").each do |link|
32           link_count += 1
33           link_size += link.content.length
34         end
35
36         link_proportion = link_size.to_f / doc.content.length.to_f
37       end
38
39       [link_proportion - 0.2, 0.0].max * 200 + link_count * 40
40     end
41
42     protected
43
44     def simple_format(text)
45       SimpleFormat.new.simple_format(text)
46     end
47
48     def linkify(text)
49       if text.html_safe?
50         Rinku.auto_link(text, :urls, tag_options(:rel => "nofollow")).html_safe
51       else
52         Rinku.auto_link(text, :urls, tag_options(:rel => "nofollow"))
53       end
54     end
55   end
56
57   class HTML < Base
58     def to_html
59       linkify(sanitize(simple_format(self)))
60     end
61
62     def to_text
63       to_s
64     end
65
66     private
67
68     def sanitize(text)
69       Sanitize.clean(text, Sanitize::Config::OSM).html_safe
70     end
71   end
72
73   class Markdown < Base
74     def to_html
75       Markdown.html_parser.render(self).html_safe
76     end
77
78     def to_text
79       to_s
80     end
81
82     def self.html_renderer
83       @html_renderer ||= Redcarpet::Render::XHTML.new(:filter_html => true, :safe_links_only => true, :link_attributes => { :rel => "nofollow" })
84     end
85
86     def self.html_parser
87       @html_parser ||= Redcarpet::Markdown.new(html_renderer, :no_intra_emphasis => true, :autolink => true, :space_after_headers => true)
88     end
89   end
90
91   class Text < Base
92     def to_html
93       linkify(simple_format(ERB::Util.html_escape(self)))
94     end
95
96     def to_text
97       to_s
98     end
99   end
100 end