BBRedCloth 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/BBRedCloth.gemspec +36 -0
- data/CHANGELOG +123 -0
- data/COPYING +18 -0
- data/Manifest +45 -0
- data/README.textile +149 -0
- data/Rakefile +247 -0
- data/bin/bbredcloth +34 -0
- data/ext/mingw-rbconfig.rb +176 -0
- data/ext/redcloth_scan/extconf.rb +9 -0
- data/ext/redcloth_scan/redcloth.h +196 -0
- data/ext/redcloth_scan/redcloth_attributes.c +655 -0
- data/ext/redcloth_scan/redcloth_bbcode.c +2457 -0
- data/ext/redcloth_scan/redcloth_bbcode_inline.c +1890 -0
- data/ext/redcloth_scan/redcloth_inline.c +12387 -0
- data/ext/redcloth_scan/redcloth_scan.c +10848 -0
- data/extras/ragel_profiler.rb +73 -0
- data/lib/case_sensitive_require/RedCloth.rb +6 -0
- data/lib/redcloth/erb_extension.rb +27 -0
- data/lib/redcloth/formatters/base.rb +57 -0
- data/lib/redcloth/formatters/html.rb +487 -0
- data/lib/redcloth/formatters/latex.rb +249 -0
- data/lib/redcloth/formatters/latex_entities.yml +2414 -0
- data/lib/redcloth/textile_doc.rb +196 -0
- data/lib/redcloth/version.rb +28 -0
- data/lib/redcloth.rb +37 -0
- data/setup.rb +1585 -0
- data/test/basic.yml +933 -0
- data/test/code.yml +229 -0
- data/test/definitions.yml +82 -0
- data/test/extra_whitespace.yml +64 -0
- data/test/filter_html.yml +177 -0
- data/test/filter_pba.yml +20 -0
- data/test/helper.rb +109 -0
- data/test/html.yml +313 -0
- data/test/images.yml +254 -0
- data/test/instiki.yml +38 -0
- data/test/links.yml +275 -0
- data/test/lists.yml +283 -0
- data/test/poignant.yml +89 -0
- data/test/sanitize_html.yml +42 -0
- data/test/table.yml +267 -0
- data/test/test_custom_tags.rb +46 -0
- data/test/test_erb.rb +13 -0
- data/test/test_extensions.rb +31 -0
- data/test/test_formatters.rb +24 -0
- data/test/test_parser.rb +73 -0
- data/test/test_restrictions.rb +61 -0
- data/test/textism.yml +484 -0
- data/test/threshold.yml +772 -0
- data/test/validate_fixtures.rb +74 -0
- metadata +139 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
class RagelProfiler
|
|
2
|
+
MEM_CONVERSION = 1024
|
|
3
|
+
|
|
4
|
+
COMMANDS = { :compile => %w(ragel rlgen-cd gcc-4.0 gnumake cc1),
|
|
5
|
+
:test => %w(ruby) }
|
|
6
|
+
|
|
7
|
+
FIELDS = %w(compile_time compile_max_rss test_time test_max_rss ext_so_size)
|
|
8
|
+
|
|
9
|
+
@@results = {}
|
|
10
|
+
|
|
11
|
+
def initialize(name)
|
|
12
|
+
@name = name
|
|
13
|
+
@@results[name] = []
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def measure(type)
|
|
17
|
+
raise "not a valid type" unless COMMANDS.keys.include?(type)
|
|
18
|
+
regex = COMMANDS[type].map {|c| Regexp.escape(c) }.join("|")
|
|
19
|
+
t = Thread.new do
|
|
20
|
+
Thread.current[:max] = 0
|
|
21
|
+
loop do
|
|
22
|
+
Thread.current[:max] = [run(regex), Thread.current[:max]].max
|
|
23
|
+
sleep 0.5
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
begin_time = Time.now
|
|
27
|
+
yield
|
|
28
|
+
total_time = Time.now - begin_time
|
|
29
|
+
|
|
30
|
+
t.kill
|
|
31
|
+
store_result(type, "time", total_time)
|
|
32
|
+
store_result(type, "max_rss", t[:max])
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def ext_size(ext_so)
|
|
36
|
+
store_result(:ext_so, "size", File.size(ext_so) / MEM_CONVERSION)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def self.results
|
|
40
|
+
out = []
|
|
41
|
+
out << "name\t" + FIELDS.join("\t")
|
|
42
|
+
@@results.each do |name, results|
|
|
43
|
+
out << [name, results ].flatten.join("\t")
|
|
44
|
+
end
|
|
45
|
+
out.join("\n")
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def store_result(type, metric, value)
|
|
51
|
+
index = FIELDS.index("#{type.to_s}_#{metric}")
|
|
52
|
+
@@results[@name][index] = "%.2f" % value
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def run(ps_regex)
|
|
56
|
+
ps_command = "ps axucww"
|
|
57
|
+
ps_output = `#{ps_command}`
|
|
58
|
+
fields = ps_output.to_a.first.downcase.split
|
|
59
|
+
memory_index = fields.index("rss")
|
|
60
|
+
pid_index = fields.index("pid")
|
|
61
|
+
ppid_index = fields.index("ppid")
|
|
62
|
+
total = ps_output.grep(/(#{ps_regex})\s+$/i).map do |com|
|
|
63
|
+
Float(com.split[memory_index]).abs
|
|
64
|
+
end.inject(0) { |s,v| s += v }
|
|
65
|
+
if total
|
|
66
|
+
return total/MEM_CONVERSION
|
|
67
|
+
else
|
|
68
|
+
STDERR.puts "Command not found. No processes found matching #{ps_regex}."
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
end
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# A workaround to make Rails 2.1 gem dependency easier on case-sensitive filesystems.
|
|
2
|
+
# Since the gem name is RedCloth and the file is redcloth.rb, config.gem 'RedCloth' doesn't
|
|
3
|
+
# work. You'd have to use config.gem 'RedCloth', :lib => 'redcloth', and that's not
|
|
4
|
+
# immediately obvious. This file remedies that.
|
|
5
|
+
#
|
|
6
|
+
require File.join(File.dirname(__FILE__), '..', 'redcloth')
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
class ERB
|
|
2
|
+
module Util
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# A utility method for transforming Textile in _s_ to HTML.
|
|
6
|
+
#
|
|
7
|
+
# require "erb"
|
|
8
|
+
# include ERB::Util
|
|
9
|
+
#
|
|
10
|
+
# puts textilize("Isn't ERB *great*?")
|
|
11
|
+
#
|
|
12
|
+
# _Generates_
|
|
13
|
+
#
|
|
14
|
+
# <p>Isn’t <span class="caps">ERB</span> <strong>great</strong>?</p>
|
|
15
|
+
#
|
|
16
|
+
def textilize( s )
|
|
17
|
+
if s && s.respond_to?(:to_s)
|
|
18
|
+
RedCloth.new( s.to_s ).to_html
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
alias t textilize
|
|
23
|
+
module_function :t
|
|
24
|
+
module_function :textilize
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
module RedCloth::Formatters
|
|
2
|
+
module Base
|
|
3
|
+
|
|
4
|
+
def pba(opts)
|
|
5
|
+
opts.delete(:style) if filter_styles
|
|
6
|
+
opts.delete(:class) if filter_classes
|
|
7
|
+
opts.delete(:id) if filter_ids
|
|
8
|
+
|
|
9
|
+
atts = ''
|
|
10
|
+
opts[:"text-align"] = opts.delete(:align)
|
|
11
|
+
opts[:style] += ';' if opts[:style] && (opts[:style][-1..-1] != ';')
|
|
12
|
+
[:float, :"text-align", :"vertical-align"].each do |a|
|
|
13
|
+
opts[:style] = "#{a}:#{opts[a]};#{opts[:style]}" if opts[a]
|
|
14
|
+
end
|
|
15
|
+
[:"padding-right", :"padding-left"].each do |a|
|
|
16
|
+
opts[:style] = "#{a}:#{opts[a]}em;#{opts[:style]}" if opts[a]
|
|
17
|
+
end
|
|
18
|
+
[:style, :class, :lang, :id, :colspan, :rowspan, :title, :start, :align].each do |a|
|
|
19
|
+
atts << " #{a}=\"#{ html_esc(opts[a].to_s, :html_escape_attributes) }\"" if opts[a]
|
|
20
|
+
end
|
|
21
|
+
atts
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def ignore(opts)
|
|
25
|
+
opts[:text]
|
|
26
|
+
end
|
|
27
|
+
alias_method :notextile, :ignore
|
|
28
|
+
|
|
29
|
+
def redcloth_version(opts)
|
|
30
|
+
p(:text => "#{opts[:prefix]}#{RedCloth::VERSION}")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def inline_redcloth_version(opts)
|
|
34
|
+
RedCloth::VERSION::STRING
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
[:del_phrase, :sup_phrase, :sub_phrase, :span_phrase].each do |phrase_method|
|
|
38
|
+
method = phrase_method.to_s.split('_')[0]
|
|
39
|
+
define_method(phrase_method) do |opts|
|
|
40
|
+
"#{opts[:beginning_space]}#{self.send(method, opts)}"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def method_missing(method, opts)
|
|
45
|
+
opts[:text] || ""
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def before_transform(text)
|
|
49
|
+
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def after_transform(text)
|
|
53
|
+
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
unless defined?(NET::HTTP)
|
|
2
|
+
require 'net/http'
|
|
3
|
+
end
|
|
4
|
+
|
|
5
|
+
unless defined?(URI)
|
|
6
|
+
require 'URI'
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
unless defined?(REXML::Document)
|
|
10
|
+
require 'rexml/document'
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
module RedCloth::Formatters::HTML
|
|
14
|
+
include RedCloth::Formatters::Base
|
|
15
|
+
|
|
16
|
+
SWEARWORDS = [
|
|
17
|
+
{:code=>/bullshit/,:replace=>"bullcrap"},
|
|
18
|
+
{:code=>/f[^a-zA-Z0-9]*[u*]+[^a-zA-Z0-9]*c[^a-zA-Z0-9]*k(er)?/,:replace=>"****"},
|
|
19
|
+
{:code=>/sh[i1!]t(t?y)?/,:replace=>"****"},
|
|
20
|
+
{:code=>/tits/,:replace=>"****"},
|
|
21
|
+
{:code=>/motherfucker/,:replace=>"******"},
|
|
22
|
+
{:code=>/bitch/,:replace=>"****"},
|
|
23
|
+
{:code=>/cunt/,:replace=>"****"},
|
|
24
|
+
{:code=>/asshole/,:replace=>"*******"},
|
|
25
|
+
{:code=>/cocksucker/,:replace=>"****"},
|
|
26
|
+
{:code=>/cock/,:replace=>"****"},
|
|
27
|
+
{:code=>/n(!|\||\!|i|1|\*)gg((!|3|e|\*)(!|r|4)|a)/,:replace=>"African-American"},
|
|
28
|
+
{:code=>/fag(got)?/,:replace=>"***"}
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
# escapement for regular HTML (not in PRE tag)
|
|
32
|
+
def escape(text)
|
|
33
|
+
if self.filter_swears == true
|
|
34
|
+
for swear in SWEARWORDS
|
|
35
|
+
text.gsub!(swear[:code],swear[:replace])
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
html_esc(text)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# escapement for HTML in a PRE tag
|
|
42
|
+
def escape_pre(text)
|
|
43
|
+
html_esc(text, :html_escape_preformatted)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def escape_pre_bb(text)
|
|
47
|
+
text.gsub(/\"/,""")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# escaping for HTML attributes
|
|
51
|
+
def escape_attribute(text)
|
|
52
|
+
html_esc(text, :html_escape_attributes)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def after_transform(text)
|
|
56
|
+
text.chomp!
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
[:h1, :h2, :h3, :h4, :h5, :h6, :p, :pre, :div].each do |m|
|
|
60
|
+
define_method(m) do |opts|
|
|
61
|
+
"<#{m}#{pba(opts)}>#{opts[:text]}</#{m}>\n"
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
[:strong, :code, :em, :i, :b, :ins, :sup, :sub, :span, :cite].each do |m|
|
|
66
|
+
define_method(m) do |opts|
|
|
67
|
+
opts[:block] = true
|
|
68
|
+
"<#{m}#{pba(opts)}>#{opts[:text]}</#{m}>"
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def hr(opts)
|
|
73
|
+
"<hr />\n"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def acronym(opts)
|
|
77
|
+
opts[:block] = true
|
|
78
|
+
"<acronym#{pba(opts)}>#{caps(:text => opts[:text])}</acronym>"
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def caps(opts)
|
|
82
|
+
if no_span_caps
|
|
83
|
+
opts[:text]
|
|
84
|
+
else
|
|
85
|
+
opts[:class] = 'caps'
|
|
86
|
+
span(opts)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def del(opts)
|
|
91
|
+
opts[:block] = true
|
|
92
|
+
"<del#{pba(opts)}>#{opts[:text]}</del>"
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
[:ol, :ul].each do |m|
|
|
96
|
+
define_method("#{m}_open") do |opts|
|
|
97
|
+
opts[:block] = true
|
|
98
|
+
"#{"\n" if opts[:nest] > 1}#{"\t" * (opts[:nest] - 1)}<#{m}#{pba(opts)}>\n"
|
|
99
|
+
end
|
|
100
|
+
define_method("#{m}_close") do |opts|
|
|
101
|
+
"#{li_close}#{"\t" * (opts[:nest] - 1)}</#{m}>#{"\n" if opts[:nest] <= 1}"
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def li_open(opts)
|
|
106
|
+
"#{li_close unless opts.delete(:first)}#{"\t" * opts[:nest]}<li#{pba(opts)}>#{opts[:text]}"
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def li_close(opts=nil)
|
|
110
|
+
"</li>\n"
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def dl_open(opts)
|
|
114
|
+
opts[:block] = true
|
|
115
|
+
"<dl#{pba(opts)}>\n"
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def dl_close(opts=nil)
|
|
119
|
+
"</dl>\n"
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
[:dt, :dd].each do |m|
|
|
123
|
+
define_method(m) do |opts|
|
|
124
|
+
"\t<#{m}#{pba(opts)}>#{opts[:text]}</#{m}>\n"
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def td(opts)
|
|
129
|
+
tdtype = opts[:th] ? 'th' : 'td'
|
|
130
|
+
"\t\t<#{tdtype}#{pba(opts)}>#{opts[:text]}</#{tdtype}>\n"
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def tr_open(opts)
|
|
134
|
+
"\t<tr#{pba(opts)}>\n"
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def tr_close(opts)
|
|
138
|
+
"\t</tr>\n"
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def table_open(opts)
|
|
142
|
+
"<table#{pba(opts)}>\n"
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def table_close(opts)
|
|
146
|
+
"</table>\n"
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def bc_open(opts)
|
|
150
|
+
opts[:block] = true
|
|
151
|
+
"<pre#{pba(opts)}>"
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def bc_close(opts)
|
|
155
|
+
"</pre>\n"
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def bq_open(opts)
|
|
159
|
+
opts[:block] = true
|
|
160
|
+
cite = opts[:cite] ? " cite=\"#{ escape_attribute opts[:cite] }\"" : ''
|
|
161
|
+
"<blockquote#{cite}#{pba(opts)}>\n"
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def bq_close(opts)
|
|
165
|
+
"</blockquote>\n"
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
LINK_TEXT_WITH_TITLE_RE = /
|
|
169
|
+
([^"]+?) # $text
|
|
170
|
+
\s?
|
|
171
|
+
\(([^)]+?)\) # $title
|
|
172
|
+
$
|
|
173
|
+
/x
|
|
174
|
+
def link(opts)
|
|
175
|
+
if opts[:name] =~ LINK_TEXT_WITH_TITLE_RE
|
|
176
|
+
md = LINK_TEXT_WITH_TITLE_RE.match(opts[:name])
|
|
177
|
+
opts[:name] = md[1]
|
|
178
|
+
opts[:title] = md[2]
|
|
179
|
+
elsif opts[:name].nil? && !opts[:href].nil?
|
|
180
|
+
opts[:name] = opts[:href]
|
|
181
|
+
end
|
|
182
|
+
"<a href=\"#{escape_attribute opts[:href]}\"#{pba(opts)}>#{opts[:name]}</a>"
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def autolink(opts)
|
|
186
|
+
" #{link(opts)}"
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def image(opts)
|
|
190
|
+
opts.delete(:align)
|
|
191
|
+
opts[:alt] = opts[:title]
|
|
192
|
+
img = "<img src=\"#{escape_attribute opts[:src]}\"#{pba(opts)} alt=\"#{escape_attribute opts[:alt].to_s}\" />"
|
|
193
|
+
img = "<a href=\"#{escape_attribute opts[:href]}\">#{img}</a>" if opts[:href]
|
|
194
|
+
img
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def color(opts)
|
|
198
|
+
"<span style=\"color:#{opts[:color]};\">#{opts[:text]}</span>"
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def bbsize(opts)
|
|
202
|
+
"<span style=\"font-size:#{opts[:size]}#{"em" unless %w(em px pt %).include?(opts[:size][-2..-1])};\">#{opts[:text]}</span>"
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def bbalign(opts)
|
|
206
|
+
"<div style=\"text-align:#{opts[:bbalign]};\">#{opts[:text]}</div>"
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def bbquote(opts)
|
|
210
|
+
quote = "<blockquote>"
|
|
211
|
+
quote += "<cite>#{opts[:cite]}</cite>" if opts[:cite]
|
|
212
|
+
quote += "#{opts[:text]}</blockquote>\n"
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def bb_block_pre(opts)
|
|
216
|
+
#quote = "<blockquote>"
|
|
217
|
+
#quote += "<cite>#{opts[:cite]}</cite>" if opts[:cite]
|
|
218
|
+
#quote += opts[:text]+"</blockquote>\n"
|
|
219
|
+
"#{bb_pre(opts)}\n"
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def bb_spoiler(opts)
|
|
223
|
+
"<span class=\"inline_spoiler\" style=\"color:#333;background-color:#333;\">#{"<span class=\"inline_spoiler_title\" style=\"color:#F00\">#{opts[:title]}</span>" if opts[:title]}#{opts[:text]}</span>"
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def bb_block_spoiler(opts)
|
|
227
|
+
"<div class=\"spoiler_container\"><div class=\"spoileroncontainer\"><button type=\"button\" class=\"button spoileron\" title=\"Click to show the spoiler.\">#{opts[:title] || "Show Spoiler"}</button></div><div class=\"spoiler\"><div class=\"spoileroffcontainer\"><button type=\"button\" class=\"button spoileroff\" title=\"Click to hide the spoiler.\">hide spoiler</button><br/></div><div class=\"spoilertext\">#{opts[:text]}</div></div></div>"
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def bb_pre(opts)
|
|
231
|
+
"<pre><code>#{opts[:text]}</code></pre>"
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def footno(opts)
|
|
235
|
+
opts[:id] ||= opts[:text]
|
|
236
|
+
%Q{<sup class="footnote"><a href=\"#fn#{opts[:id]}\">#{opts[:text]}</a></sup>}
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def fn(opts)
|
|
240
|
+
no = opts[:id]
|
|
241
|
+
opts[:id] = "fn#{no}"
|
|
242
|
+
opts[:class] = ["footnote", opts[:class]].compact.join(" ")
|
|
243
|
+
"<p#{pba(opts)}><sup>#{no}</sup> #{opts[:text]}</p>\n"
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def snip(opts)
|
|
247
|
+
"<pre#{pba(opts)}><code>#{opts[:text]}</code></pre>\n"
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def quote1(opts)
|
|
251
|
+
"‘#{opts[:text]}’"
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def quote2(opts)
|
|
255
|
+
"“#{opts[:text]}”"
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
def multi_paragraph_quote(opts)
|
|
259
|
+
"“#{opts[:text]}"
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def ellipsis(opts)
|
|
263
|
+
"#{opts[:text]}…"
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def emdash(opts)
|
|
267
|
+
"—"
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
def endash(opts)
|
|
271
|
+
" – "
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def arrow(opts)
|
|
275
|
+
"→"
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def dim(opts)
|
|
279
|
+
opts[:text].gsub!('x', '×')
|
|
280
|
+
opts[:text].gsub!("'", '′')
|
|
281
|
+
opts[:text].gsub!('"', '″')
|
|
282
|
+
opts[:text]
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
def trademark(opts)
|
|
286
|
+
"™"
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
def registered(opts)
|
|
290
|
+
"®"
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def copyright(opts)
|
|
294
|
+
"©"
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def entity(opts)
|
|
298
|
+
"&#{opts[:text]};"
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
def amp(opts)
|
|
302
|
+
"&"
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
def gt(opts)
|
|
306
|
+
">"
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
def lt(opts)
|
|
310
|
+
"<"
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
def br(opts)
|
|
314
|
+
if hard_breaks == false
|
|
315
|
+
"\n"
|
|
316
|
+
else
|
|
317
|
+
"<br />\n"
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
def quot(opts)
|
|
322
|
+
"""
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
def squot(opts)
|
|
326
|
+
"’"
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
def apos(opts)
|
|
330
|
+
"'"
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
def html(opts)
|
|
334
|
+
"#{opts[:text]}\n"
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
def youtube(opts)
|
|
338
|
+
#gdata.youtube.com/feeds/api/videos/Gkwhxh5txJ0
|
|
339
|
+
|
|
340
|
+
begin
|
|
341
|
+
url = URI.parse("http://gdata.youtube.com/feeds/api/videos/#{opts[:youtubeid]}")
|
|
342
|
+
req = Net::HTTP::Get.new(url.path)
|
|
343
|
+
res = Net::HTTP.start(url.host, url.port) {|http|
|
|
344
|
+
http.request(req)
|
|
345
|
+
}
|
|
346
|
+
d = REXML::Document.new(res.body)
|
|
347
|
+
title = d.elements["entry/title"].text
|
|
348
|
+
rescue
|
|
349
|
+
title = "http://www.youtube.com/watch?v=#{opts[:youtubeid]}"
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
case opts[:youtubefmt]
|
|
353
|
+
when "22"
|
|
354
|
+
width = 700
|
|
355
|
+
height = 395
|
|
356
|
+
when "18"
|
|
357
|
+
width = 480
|
|
358
|
+
height = 320
|
|
359
|
+
when "6"
|
|
360
|
+
width = 480
|
|
361
|
+
height = 320
|
|
362
|
+
else
|
|
363
|
+
width = 320
|
|
364
|
+
height = 240
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
out = "<div class=\"youtube\"><div class=\"youtube_title\"><a href=\"http://www.youtube.com/watch?v=#{opts[:youtubeid]}#{"&fmt=#{opts[:youtubefmt]}" if opts[:youtubefmt]}\">#{title}</a></div><div class=\"youtube_video\"><object width=\"#{width}\" height=\"#{height}\"><param name=\"movie\" value=\"http://www.youtube.com/v/#{opts[:youtubeid]}&hl=en&fs=1&\"></param><param name=\"allowFullScreen\" value=\"true\"></param><param name=\"allowscriptaccess\" value=\"always\"></param><embed src=\"http://www.youtube.com/v/#{opts[:youtubeid]}&hl=en&fs=1&\" type=\"application/x-shockwave-flash\" allowscriptaccess=\"always\" allowfullscreen=\"true\" width=\"#{width}\" height=\"#{height}\"></embed></object></div></div>\n"
|
|
368
|
+
out
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
def vimeo(opts)
|
|
372
|
+
begin
|
|
373
|
+
#http://www.vimeo.com/api/v2/video/6583886.xml
|
|
374
|
+
|
|
375
|
+
url = URI.parse("http://www.vimeo.com/api/v2/video/#{opts[:vimeoid]}.xml")
|
|
376
|
+
req = Net::HTTP::Get.new(url.path)
|
|
377
|
+
res = Net::HTTP.start(url.host, url.port) {|http|
|
|
378
|
+
http.request(req)
|
|
379
|
+
}
|
|
380
|
+
d = REXML::Document.new(res.body)
|
|
381
|
+
title = d.elements["videos/video/title"].text
|
|
382
|
+
out = "#{title}"
|
|
383
|
+
width = 480
|
|
384
|
+
height = 320
|
|
385
|
+
out = "<div class=\"youtube\"><div class=\"youtube_title\"><a href=\"http://vimeo.com/#{opts[:vimeoid]}\">#{title}</a></div><div class=\"youtube_video\"><object width=\"#{width}\" height=\"#{height}\"><param name=\"allowfullscreen\" value=\"true\" /><param name=\"allowscriptaccess\" value=\"always\" /><param name=\"movie\" value=\"http://vimeo.com/moogaloop.swf?clip_id=#{opts[:vimeoid]}&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=&fullscreen=1\" /><embed src=\"http://vimeo.com/moogaloop.swf?clip_id=#{opts[:vimeoid]}&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=&fullscreen=1\" type=\"application/x-shockwave-flash\" allowfullscreen=\"true\" allowscriptaccess=\"always\" width=\"#{width}\" height=\"#{height}\"></embed></object></div></div>"
|
|
386
|
+
rescue
|
|
387
|
+
out = "ERROR WITH VIMEO API! VIDEO DOES NOT EXIST? VIDEO NOT ALLOWED TO EMBED?"
|
|
388
|
+
end
|
|
389
|
+
out
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
def html_block(opts)
|
|
393
|
+
inline_html(:text => "#{opts[:indent_before_start]}#{opts[:start_tag]}#{opts[:indent_after_start]}") +
|
|
394
|
+
"#{opts[:text]}" +
|
|
395
|
+
inline_html(:text => "#{opts[:indent_before_end]}#{opts[:end_tag]}#{opts[:indent_after_end]}")
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
def notextile(opts)
|
|
399
|
+
if filter_html
|
|
400
|
+
html_esc(opts[:text], :html_escape_preformatted)
|
|
401
|
+
else
|
|
402
|
+
opts[:text]
|
|
403
|
+
end
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
def inline_html(opts)
|
|
407
|
+
if filter_html
|
|
408
|
+
html_esc(opts[:text], :html_escape_preformatted)
|
|
409
|
+
else
|
|
410
|
+
"#{opts[:text]}" # nil-safe
|
|
411
|
+
end
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
def ignored_line(opts)
|
|
415
|
+
opts[:text] + "\n"
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
def before_transform(text)
|
|
419
|
+
clean_html(text) if sanitize_html
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
# HTML cleansing stuff
|
|
423
|
+
BASIC_TAGS = {
|
|
424
|
+
'a' => ['href', 'title'],
|
|
425
|
+
'img' => ['src', 'alt', 'title'],
|
|
426
|
+
'br' => [],
|
|
427
|
+
'i' => nil,
|
|
428
|
+
'u' => nil,
|
|
429
|
+
'b' => nil,
|
|
430
|
+
'pre' => nil,
|
|
431
|
+
'kbd' => nil,
|
|
432
|
+
'code' => ['lang'],
|
|
433
|
+
'cite' => nil,
|
|
434
|
+
'strong' => nil,
|
|
435
|
+
'em' => nil,
|
|
436
|
+
'ins' => nil,
|
|
437
|
+
'sup' => nil,
|
|
438
|
+
'sub' => nil,
|
|
439
|
+
'del' => nil,
|
|
440
|
+
'table' => nil,
|
|
441
|
+
'tr' => nil,
|
|
442
|
+
'td' => ['colspan', 'rowspan'],
|
|
443
|
+
'th' => nil,
|
|
444
|
+
'ol' => ['start'],
|
|
445
|
+
'ul' => nil,
|
|
446
|
+
'li' => nil,
|
|
447
|
+
'p' => nil,
|
|
448
|
+
'h1' => nil,
|
|
449
|
+
'h2' => nil,
|
|
450
|
+
'h3' => nil,
|
|
451
|
+
'h4' => nil,
|
|
452
|
+
'h5' => nil,
|
|
453
|
+
'h6' => nil,
|
|
454
|
+
'blockquote' => ['cite'],
|
|
455
|
+
'notextile' => nil
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
# Clean unauthorized tags.
|
|
459
|
+
def clean_html( text, allowed_tags = BASIC_TAGS )
|
|
460
|
+
text.gsub!( /<!\[CDATA\[/, '' )
|
|
461
|
+
text.gsub!( /<(\/*)([A-Za-z]\w*)([^>]*?)(\s?\/?)>/ ) do |m|
|
|
462
|
+
raw = $~
|
|
463
|
+
tag = raw[2].downcase
|
|
464
|
+
if allowed_tags.has_key? tag
|
|
465
|
+
pcs = [tag]
|
|
466
|
+
allowed_tags[tag].each do |prop|
|
|
467
|
+
['"', "'", ''].each do |q|
|
|
468
|
+
q2 = ( q != '' ? q : '\s' )
|
|
469
|
+
if raw[3] =~ /#{prop}\s*=\s*#{q}([^#{q2}]+)#{q}/i
|
|
470
|
+
attrv = $1
|
|
471
|
+
next if (prop == 'src' or prop == 'href') and not attrv =~ %r{^(http|https|ftp):}
|
|
472
|
+
pcs << "#{prop}=\"#{attrv.gsub('"', '\\"')}\""
|
|
473
|
+
break
|
|
474
|
+
end
|
|
475
|
+
end
|
|
476
|
+
end if allowed_tags[tag]
|
|
477
|
+
"<#{raw[1]}#{pcs.join " "}#{raw[4]}>"
|
|
478
|
+
else # Unauthorized tag
|
|
479
|
+
if block_given?
|
|
480
|
+
yield m
|
|
481
|
+
else
|
|
482
|
+
''
|
|
483
|
+
end
|
|
484
|
+
end
|
|
485
|
+
end
|
|
486
|
+
end
|
|
487
|
+
end
|