Drop iconv which is deprecated and only needed for ruby 1.8 support
[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.length > 0
29         doc.xpath("//a").each do |link|
30           link_count += 1
31           link_size += link.content.length
32         end
33
34         link_proportion = link_size.to_f / doc.content.length.to_f
35       else
36         link_proportion = 0
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       html_parser.render(self).html_safe
76     end
77
78     def to_text
79       to_s
80     end
81
82     private
83
84     def html_parser
85       @@html_renderer ||= Renderer.new(:filter_html => true, :safe_links_only => true)
86       @@html_parser ||= Redcarpet::Markdown.new(@@html_renderer,         :no_intra_emphasis => true, :autolink => true, :space_after_headers => true)
87     end
88
89     class Renderer < Redcarpet::Render::XHTML
90       def link(link, _title, alt_text)
91         "<a rel=\"nofollow\" href=\"#{link}\">#{alt_text}</a>"
92       end
93
94       def autolink(link, link_type)
95         if link_type == :email
96           "<a rel=\"nofollow\" href=\"mailto:#{link}\">#{link}</a>"
97         else
98           "<a rel=\"nofollow\" href=\"#{link}\">#{link}</a>"
99         end
100       end
101     end
102   end
103
104   class Text < Base
105     def to_html
106       linkify(simple_format(ERB::Util.html_escape(self)))
107     end
108
109     def to_text
110       to_s
111     end
112   end
113 end