/
red_cloth_formatters_plain.rb
237 lines (214 loc) · 5.5 KB
/
red_cloth_formatters_plain.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# encoding: UTF-8
require "cgi"
module RedCloth
module Formatters
module Plain
class Sanitizer
def self.strip_tags(text)
# use Rails Sanitizer if available
begin
text = ActionController::Base.helpers.strip_tags(text)
rescue
# otherwise, use custom method inspired from:
# RedCloth::Formatters::HTML.clean_html
# not very secure, but it's ok as output is still
# meant to be escaped if it needs to be shown
text.gsub!( /<!\[CDATA\[/, '' )
text.gsub!( /<(\/*)([A-Za-z]\w*)([^>]*?)(\s?\/?)>/ ){|m| block_given? ? yield(m) : ""}
end
CGI.unescapeHTML(text)
end
end
include RedCloth::Formatters::Base
[:h1, :h2, :h3, :h4, :h5, :h6, :p, :pre, :div].each do |m|
define_method(m) do |opts|
"#{opts[:text]}\n\n"
end
end
[:strong, :code, :em, :i, :b, :ins, :sup, :sub, :span, :cite].each do |m|
define_method(m) do |opts|
opts[:block] = true
"#{opts[:text]}"
end
end
def hr(opts)
"\n"
end
def acronym(opts)
opts[:block] = true
opts[:title] ? "#{opts[:text]}(#{opts[:title]})" : "#{opts[:text]}"
end
def caps(opts)
"#{opts[:text]}"
end
# don't render deleted text
def del(opts)
""
end
# simple list with dashes
[:ol, :ul].each do |m|
define_method("#{m}_open") do |opts|
opts[:block] = true
opts[:nest] > 1 ? "\n" : ""
end
define_method("#{m}_close") do |opts|
""
end
end
def li_open(opts)
@li_need_closing = true
num = opts[:nest] - 1
"#{" " * (num > 0 ? num : 0)}- #{opts[:text]}"
end
def li_close(opts=nil)
# avoid multiple line breaks when closing multiple list items
output = @li_need_closing ? "\n" : ""
@li_need_closing = false
output
end
def dl_open(opts)
opts[:block] = true
""
end
def dl_close(opts=nil)
""
end
def dt(opts)
"#{opts[:text]}:\n"
end
def dd(opts)
" #{opts[:text]}\n"
end
# don't render tables
[:td, :tr_open, :tr_close, :table_open, :table_close].each do |m|
define_method(m) do |opts|
""
end
end
# just add newlines before blockquotes
[:bc_open, :bq_open].each do |m|
define_method(m) do |opts|
opts[:block] = true
""
end
end
def bc_close(opts)
"\n"
end
def bq_close(opts)
""
end
# render link name followed by <url>
# uses !LINK_OPEN_TAG! and !LINK_CLOSE_TAG! as a way to identify
# the < > otherwise they will be stripped when all html tags are stripped
#
def link(opts)
"#{opts[:name]} !LINK_OPEN_TAG!#{opts[:href]}!LINK_CLOSE_TAG!"
end
# render image alternative text or title if not available
def image(opts)
"#{opts[:alt] || opts[:title]}"
end
# don't render footnotes
[:footno, :fn].each do |m|
define_method(m) do |opts|
""
end
end
def snip(opts)
opts[:text] + "\n"
end
# render unescaped quotes and special chars
def quote1(opts)
"'#{opts[:text]}'"
end
def quote2(opts)
"\"#{opts[:text]}\""
end
def multi_paragraph_quote(opts)
"\"#{opts[:text]}"
end
def ellipsis(opts)
"#{opts[:text]}..."
end
{
:emdash => "-",
:endash => " - ",
:arrow => "->",
:trademark => "™",
:registered => "®",
:copyright => "©",
:amp => "&",
:gt => ">",
:lt => "<",
:br => "\n",
:quot => "\"",
:squot => "'",
:apos => "'",
}.each do |method, output|
define_method(method) do |opts|
output
end
end
def dim(opts)
opts[:text]
end
def entity(opts)
unescape("&#{opts[:text]};")
end
# strip HTML tags
def html(opts)
strip_tags(opts[:text]) + "\n"
end
def html_block(opts)
strip_tags(opts[:text])
end
def notextile(opts)
if filter_html
"#{opts[:text]}"
else
strip_tags(opts[:text])
end
end
def inline_html(opts)
if filter_html
"#{opts[:text]}"
else
strip_tags(opts[:text])
end
end
# unchanged
def ignored_line(opts)
opts[:text] + "\n"
end
private
def strip_tags(text)
Sanitizer.strip_tags(text)
end
def unescape(str)
CGI.unescapeHTML(str.to_s)
end
# no escaping
[:escape, :escape_pre, :escape_attribute].each do |m|
define_method(m) do |text|
text
end
end
def after_transform(text)
text.chomp!
end
def before_transform(text)
end
end
end
class TextileDoc
def to_plain(*rules)
apply_rules(rules)
output = to(Formatters::Plain)
output = Formatters::Plain::Sanitizer.strip_tags(output)
# replace special link hooks with < and >
# See #RedCloth::Formatters::Plain#link above
output.gsub("!LINK_OPEN_TAG!", "<").gsub("!LINK_CLOSE_TAG!", ">")
end
end
end