ubbparser 0.0.5
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/lib/ubbparser.rb +447 -0
- metadata +45 -0
data/lib/ubbparser.rb
ADDED
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
require "strscan"
|
|
2
|
+
require "securerandom"
|
|
3
|
+
|
|
4
|
+
# The UBBParser module converts UBB code into HTML. The parser is flexibel
|
|
5
|
+
# and adding new ubb codes is as easy as writing methods.
|
|
6
|
+
# Author:: Taco Jan Osinga, Osinga Software
|
|
7
|
+
#
|
|
8
|
+
# You can create your own ubbcodes by opening the module UBBParser and adding a method called render_xxx,
|
|
9
|
+
# where xxx is your ubb code of choice. The method should have the following arguments:
|
|
10
|
+
# (inner_text, attributes = {}, parse_options = {})
|
|
11
|
+
# inner_text:: Contains the text that's found between the opening and the closing tag.
|
|
12
|
+
# attributes:: A hash containing all the key-value attributes that are given.
|
|
13
|
+
# parse_options:: A hash containing the same parse_options that are used when UBBParser.parse() is called.
|
|
14
|
+
#
|
|
15
|
+
# *Example*
|
|
16
|
+
# The following example adds the ubb code \[sup\]...\[/sup], which wraps the inner_text with <sup> tags
|
|
17
|
+
#
|
|
18
|
+
# module UBBParser
|
|
19
|
+
# def render_sup(inner_text, attributes = {}, parse_options = {})
|
|
20
|
+
# "<sup>{inner_text}</sup>"
|
|
21
|
+
# end
|
|
22
|
+
# end
|
|
23
|
+
#
|
|
24
|
+
# When defining new ubb codes with a method and the name contains a dash, replace the dash by an underscore.
|
|
25
|
+
# I.e. the ubb code for img-left uses the method render_img_left
|
|
26
|
+
|
|
27
|
+
module UBBParser
|
|
28
|
+
|
|
29
|
+
# Converts a strings containing key-value-list into a hash. This function is mostly used by the parser itself.
|
|
30
|
+
# Attributes are given to the render methods as a hash.
|
|
31
|
+
def self.attrib_str_to_hash(attrib_str)
|
|
32
|
+
result = {:original_attrib_str => attrib_str.gsub(/^=/, "")}
|
|
33
|
+
|
|
34
|
+
attrib_str.insert(0, "default") if (attrib_str[0] == "=")
|
|
35
|
+
attrib_str.scan(/((\S*)=(\"[^\"]*\"|\'[^\']*\'|\S*))/) { | all, key, val |
|
|
36
|
+
result[(key.gsub(/-/, "_").to_sym rescue key)] = val.gsub(/^[\"\']/, "").gsub(/[\"\']$/, "")
|
|
37
|
+
}
|
|
38
|
+
return result
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Converts a hash into a string with key-values. You can use one of the following options:
|
|
42
|
+
# options[:allowed_keys]:: An array of keys that are only allowed
|
|
43
|
+
# options[:denied_keys]:: An array of keys that are denied
|
|
44
|
+
def self.hash_to_attrib_str(hash, options = {})
|
|
45
|
+
hash.delete_if { | k, v | !options[:allowed_keys].include?(k) } if options[:allowed_keys].is_a?(Array)
|
|
46
|
+
hash.delete_if { | k, v | options[:denied_keys].include?(k) } if options[:denied_keys].is_a?(Array)
|
|
47
|
+
return hash.map { | k, v | v = v.to_s.gsub(/\\|'/) { |c| "\\#{c}" }; "#{k}='#{v}'" }.join(" ");
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Parses the given text with ubb code into html. Use parse_options to specify a hash of options:
|
|
51
|
+
# parse_options\[:convert_newlines\]:: A boolean whether newlines should be convert into <br /> tags (default: true).
|
|
52
|
+
# parse_options\[:protect_email\]:: A boolean whether email addresses should be protected from spoofing using embedded JavaScript.
|
|
53
|
+
# parse_options\[:class_xxx\]:: A string with css class(es) that is embedded in the html for the tag xxx. Not all tags supports this.
|
|
54
|
+
# Replaces a dash in a tag with underscore (i.e. the class for img-left is defined in :class_img_left).
|
|
55
|
+
# {:class_code: "prettify linenums"} => <pre class='prettify linenums'>...</pre>
|
|
56
|
+
#
|
|
57
|
+
# When developing your own tags, you can also define your own parse_options.
|
|
58
|
+
def self.parse(text, parse_options = {})
|
|
59
|
+
result = ""
|
|
60
|
+
scnr = StringScanner.new(text)
|
|
61
|
+
parse_options.each { | k, v | v.to_s.gsub(/-/, "_").gsub(/[^\w]+/, "") if (k.to_s.start_with?("class_")); v }
|
|
62
|
+
while (!scnr.eos?)
|
|
63
|
+
untagged_text = scnr.scan(/[^\[]*/)
|
|
64
|
+
|
|
65
|
+
# convert newlines to breaks
|
|
66
|
+
untagged_text.gsub!(/\n/, "<br />") if (!parse_options.include?(:convert_newlines) || parse_options[:convert_newlines])
|
|
67
|
+
|
|
68
|
+
# check for untagged url's
|
|
69
|
+
uri_pattern = /(((http|https|ftp)\:\/\/)|(www))[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,4}(:[a-zA-Z0-9]*)?\/?([a-zA-Z0-9\-\._\?\,\'\/\\\+&%\$#\=~])*[^\.\,\)\(\s]*/
|
|
70
|
+
untagged_text.gsub!(uri_pattern) { | url, | render_url(url, {}, parse_options) }
|
|
71
|
+
|
|
72
|
+
# check for untagged emails
|
|
73
|
+
email_pattern = /(([a-zA-Z0-9_\-\.\+]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?))/
|
|
74
|
+
untagged_text.gsub!(email_pattern) { | email, | render_email(email, {}, parse_options) }
|
|
75
|
+
|
|
76
|
+
result << untagged_text
|
|
77
|
+
|
|
78
|
+
# check for the upcoming ubb tag and process it (if valid tag)
|
|
79
|
+
if (scnr.match?(/\[/))
|
|
80
|
+
scnr.skip(/\[/)
|
|
81
|
+
code = scnr.scan(/[\w-]*/)
|
|
82
|
+
method_name = ("render_" + code.to_s.gsub(/-/, "_")).to_sym
|
|
83
|
+
if ((scnr.eos?) || (code == "") || (!self.respond_to?(method_name)))
|
|
84
|
+
result << "[" + code
|
|
85
|
+
else
|
|
86
|
+
attributes = self.attrib_str_to_hash(scnr.scan(/[^\]]*/))
|
|
87
|
+
scnr.skip(/\]/)
|
|
88
|
+
inner_text = scnr.scan_until(/\[\/#{code}\]/)
|
|
89
|
+
if inner_text.nil? #no closing tag found
|
|
90
|
+
inner_text = scnr.rest
|
|
91
|
+
scnr.terminate
|
|
92
|
+
else
|
|
93
|
+
inner_text.chomp!("[/#{code}]")
|
|
94
|
+
end
|
|
95
|
+
method_result = self.send(method_name, inner_text, attributes, parse_options).to_s
|
|
96
|
+
result << method_result
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
return result
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Returns true if the given value matches the given regular expression.
|
|
104
|
+
# :category: Validation methods
|
|
105
|
+
def self.matches_regexp?(value, regexp)
|
|
106
|
+
return !value.to_s.match(regexp).nil?
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Returns true if the given value is a valid email address
|
|
110
|
+
# :category: Validation methods
|
|
111
|
+
def self.is_email?(value)
|
|
112
|
+
return false if !value.is_a?(String)
|
|
113
|
+
return self.matches_regexp?(value, /^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@([a-z0-9_][-a-z0-9_]*(\.[-a-z0-9_]+)*\.(aero|arpa|biz|com|coop|edu|gov|info|int|mil|museum|name|net|org|pro|travel|mobi|[a-z][a-z])|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,5})?$/i)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Returns true if the given value is a valid url
|
|
117
|
+
# :category: Validation methods
|
|
118
|
+
def self.is_url?(value)
|
|
119
|
+
return self.matches_regexp?(value, /^(http|https)\:\/\/([a-zA-Z0-9\.\-]+(\:[a-zA-Z0-9\.&%\$\-]+)*@)*((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|localhost|([a-zA-Z0-9\-]+\.)*[a-zA-Z0-9\-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(\:[0-9]+)*(\/($|[a-zA-Z0-9\.\,\?\'\\\+&%\$#\=~_\-]+))*$/)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
# Converts the [anchor=myname]...[/anchor] tag into <a name='myname'>...</a>. Use the :class_anchor parse option to define html classes.
|
|
125
|
+
# :category: Render methods
|
|
126
|
+
def self.render_anchor(inner_text, attributes = {}, parse_options = {})
|
|
127
|
+
name = attributes[:default] || ""
|
|
128
|
+
name.inner_text.gsub!(/\\|'/) { |c| "\\#{c}" }
|
|
129
|
+
"<a name='#{name}' class='#{parse_options[:class_anchor].to_s.strip}'>#{self.parse(inner_text, parse_options)}</a>"
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Converts the url in the inner_text into a webplayer, playing the audio file.
|
|
133
|
+
# :category: Render methods
|
|
134
|
+
def self.render_audio(inner_text, attributes = {}, parse_options = {})
|
|
135
|
+
# Not yet implemented
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Renders the inner_text bold (using <strong>).
|
|
139
|
+
# :category: Render methods
|
|
140
|
+
def self.render_b(inner_text, attributes = {}, parse_options = {})
|
|
141
|
+
"<strong>#{self.parse(inner_text, parse_options)}</strong>"
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Converts [br] into a <br />.
|
|
145
|
+
# :category: Render methods
|
|
146
|
+
def self.render_br(inner_text, attributes = {}, parse_options = {})
|
|
147
|
+
"<br />#{self.parse(inner_text, parse_options)}"
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Converts all lines in the inner_text as a bullet list. Each line represents one list item. Empty lines are ignored. Use the :class_bullet parse option to define html classes.
|
|
151
|
+
# :category: Render methods
|
|
152
|
+
def self.render_bullets(inner_text, attributes = {}, parse_options = {})
|
|
153
|
+
items = inner_text.split(/\n/)
|
|
154
|
+
items.delete_if { | item | item.strip == "" }
|
|
155
|
+
items.map! { | item | "<li>" + self.parse(item, parse_options) + "</li>" }
|
|
156
|
+
return (items.empty?) ? "" : "<ul class='#{parse_options[:class_bullets].to_s.strip}'>" + items.join("") + "</ul>"
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Centers the inner_text.
|
|
160
|
+
# :category: Render methods
|
|
161
|
+
def self.render_center(inner_text, attributes = {}, parse_options = {})
|
|
162
|
+
"<div style='text-align: center'>#{self.parse(inner_text, parse_options)}</div>"
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Assures the inner_text is rendered below floating elements.
|
|
166
|
+
# :category: Render methods
|
|
167
|
+
def self.render_clear(inner_text, attributes = {}, parse_options = {})
|
|
168
|
+
"<div style='clear: both'></div>"
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Changes the font color of the inner_text
|
|
172
|
+
# :category: Render methods
|
|
173
|
+
def self.render_color(inner_text, attributes = {}, parse_options = {})
|
|
174
|
+
"<div style='color:#{attributes[:default]}'>#{self.parse(inner_text, parse_options)}</div>"
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Ignores all the inner_text
|
|
178
|
+
# :category: Render methods
|
|
179
|
+
def self.render_comment(inner_text, attributes = {}, parse_options = {})
|
|
180
|
+
""
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Places the inner_text in a fixed font type. Also adds the classes prettify and linenums for styling purposes. Use the :class_code parse option to define html classes.
|
|
184
|
+
# :category: Render methods
|
|
185
|
+
def self.render_code(inner_text, attributes = {}, parse_options = {})
|
|
186
|
+
"<pre class='#{parse_options[:class_code].to_s.strip}'>#{inner_text}</pre>"
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Renders csv-data into a html table. You can use the following attributes:
|
|
190
|
+
# has_header: The first row should be rendered as header cells (using th).
|
|
191
|
+
# :category: Render methods
|
|
192
|
+
def self.render_csv(inner_text, attributes = {}, parse_options = {})
|
|
193
|
+
head_cells = body_cells = ""
|
|
194
|
+
cell_tag = (attributes[:has_header] || true) ? "th" : "td"
|
|
195
|
+
lines = inner_text.split(/\n/)
|
|
196
|
+
csv_pattern = /(\"[^\"]*\"|\'[^\']*\'|[^\n\r,]+)[,\n]?/
|
|
197
|
+
lines.each { | line |
|
|
198
|
+
cells = attrib_str.scan(csv_pattern) { | item | "<#{cell_tag}>#{item}</#{cell_tag}>" }
|
|
199
|
+
cells = "<tr>#{cells}</tr>"
|
|
200
|
+
if (cell_tag == "th")
|
|
201
|
+
head_cells += cells
|
|
202
|
+
else
|
|
203
|
+
body_cells += cells
|
|
204
|
+
end
|
|
205
|
+
cell_tag = "td"
|
|
206
|
+
}
|
|
207
|
+
result = ""
|
|
208
|
+
if (!head_cells.empty? || !body_cells.empty?)
|
|
209
|
+
result = "<table class='#{parse_options[:class_csv].to_s.strip}'>"
|
|
210
|
+
result += "<thead>#{head_cells}</thead>" if (!head_cells.empty?)
|
|
211
|
+
result += "<tbody>#{body_cells}</tbody>"
|
|
212
|
+
result = "</table>"
|
|
213
|
+
end
|
|
214
|
+
return result
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# Renders an email address. There are two options to define:
|
|
218
|
+
# [email]info@osingasoftware.nl[/email]
|
|
219
|
+
# [email=info@osingasoftware.nl]Osinga Software[/email]
|
|
220
|
+
# By default the email address is protected against spoofing, using JavaScript. Use the :class_email parse option to define html classes.
|
|
221
|
+
# :category: Render methods
|
|
222
|
+
def self.render_email(inner_text, attributes = {}, parse_options = {})
|
|
223
|
+
email = (attributes[:default] || inner_text)
|
|
224
|
+
if (!self.is_email?(email))
|
|
225
|
+
parse_options[:class_email] = parse_options[:class_email].to_s + " ubbparser-error"
|
|
226
|
+
result = "<span class='#{parse_options[:class_email].to_s.strip}'>UBB error: invalid email address #{email}</span>"
|
|
227
|
+
elsif ((parse_options.has_key?(:protect_email) && !parse_options[:protect_email]) || (attributes[:protected] == "false"))
|
|
228
|
+
result = "<a href='mailto:#{email}' class='#{parse_options[:class_email].to_s.strip}'>#{inner_text}</a>"
|
|
229
|
+
else
|
|
230
|
+
username, domain = email.split("@", 2)
|
|
231
|
+
id = "ubb-email-" + SecureRandom.hex(16)
|
|
232
|
+
|
|
233
|
+
# Some generic javascript so every browser can parse this (instantly), regardless of used framework
|
|
234
|
+
title = (inner_text == email) ? "protected email address" : inner_text
|
|
235
|
+
script = "<script type='text/javascript'>obj=document.getElementById(\"#{id}\");email=obj.getAttribute(\"data-username\")+\"@\"+obj.getAttribute(\"data-domain\");obj.href=\"mailto:\"+email;obj.innerHTML=\"#{title}\"</script>";
|
|
236
|
+
result = "<a id='#{id}' class='#{parse_options[:class_email].to_s.strip}' href='#' data-username='#{username}' data-domain='#{domain}'>#{title}</a>#{script}"
|
|
237
|
+
end
|
|
238
|
+
return result
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# Renders the inner_text in the specified list. The list should contain CSS style font-families, i.e.:
|
|
242
|
+
# [font=Arial, Helvetica, Sans]...[/font]
|
|
243
|
+
# :category: Render methods
|
|
244
|
+
def self.render_font(inner_text, attributes = {}, parse_options = {})
|
|
245
|
+
font = attributes[:original_attrib_str].gsub!(/\\|'/) { |c| "\\#{c}" }
|
|
246
|
+
"<span style='font-family: #{font}'>#{self.parse(inner_text, parse_options)}</span>"
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
# Renders the inner_text in a H1 heading.
|
|
250
|
+
# :category: Render methods
|
|
251
|
+
def self.render_h1(inner_text, attributes = {}, parse_options = {})
|
|
252
|
+
"<h1>#{self.parse(inner_text, parse_options)}</h1>"
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# Renders the inner_text in a H2 heading.
|
|
256
|
+
# :category: Render methods
|
|
257
|
+
def self.render_h2(inner_text, attributes = {}, parse_options = {})
|
|
258
|
+
"<h2>#{self.parse(inner_text, parse_options)}</h2>"
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
# Renders the inner_text in a H3 heading.
|
|
262
|
+
# :category: Render methods
|
|
263
|
+
def self.render_h3(inner_text, attributes = {}, parse_options = {})
|
|
264
|
+
"<h3>#{self.parse(inner_text, parse_options)}</h3>"
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
# Renders a horizontal ruler.
|
|
268
|
+
# :category: Render methods
|
|
269
|
+
def self.render_hr(inner_text, attributes = {}, parse_options = {})
|
|
270
|
+
"<hr />#{self.parse(inner_text, parse_options)}"
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# Renders the inner_text in italic.
|
|
274
|
+
# :category: Render methods
|
|
275
|
+
def self.render_i(inner_text, attributes = {}, parse_options = {})
|
|
276
|
+
"<em>#{self.parse(inner_text, parse_options)}</em>"
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
# Renders an iframe. Use the inner_text as source. Use the :class_iframe parse option to define html classes.
|
|
280
|
+
# :category: Render methods
|
|
281
|
+
def self.render_iframe(inner_text, attributes = {}, parse_options = {})
|
|
282
|
+
src = inner_text
|
|
283
|
+
src = "http://" + src if (src.match(/^www\./))
|
|
284
|
+
src.gsub!(/\\|'/) { |c| "\\#{c}" }
|
|
285
|
+
attributes[:src] = inner_text
|
|
286
|
+
attributes[:class] = (attributes[:class].to_s + " " + parse_options[:class_iframe].to_s).strip if ((!attributes.has_key?(:skip_class)) || !attributes[:skip_class])
|
|
287
|
+
attrib_str = self.hash_to_attrib_str(attributes, :allowed_keys => [:src, :class, :frameborder, :marginwidth, :marginheight, :width, :height])
|
|
288
|
+
return "<iframe #{attrib_str}></iframe>"
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
# Doesn't render the ubb code in the inner_text. It does strip all html-tags from the inner_text
|
|
292
|
+
# :category: Render methods
|
|
293
|
+
def self.render_ignore(inner_text, attributes = {}, parse_options = {})
|
|
294
|
+
inner_text
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
# Renders an image. Use the :class_img parse option to define html classes.
|
|
298
|
+
# :category: Render methods
|
|
299
|
+
def self.render_img(inner_text, attributes = {}, parse_options = {})
|
|
300
|
+
url = inner_text
|
|
301
|
+
url = "" if (!self.is_url?(inner_text))
|
|
302
|
+
attributes[:src] = inner_text.gsub(/\\|'/) { |c| "\\#{c}" }
|
|
303
|
+
attributes[:alt] ||= ""
|
|
304
|
+
attributes[:class] = parse_options[:class_img] if ((!attributes.has_key?(:skip_class)) || !attributes[:skip_class])
|
|
305
|
+
attrib_str = self.hash_to_attrib_str(attributes, :allowed_keys => [:src, :alt, :styles, :class])
|
|
306
|
+
return "<img #{attrib_str} />"
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
# Renders an image, floated on the left side of the text frame. Use the :class_img_left parse option to define html classes.
|
|
310
|
+
# :category: Render methods
|
|
311
|
+
def self.render_img_left(inner_text, attributes = {}, parse_options = {})
|
|
312
|
+
attributes[:styles] = "float: left; margin: 0px 10px 10px 0px"
|
|
313
|
+
attributes[:class] += " " + parse_options[:class_img_left]
|
|
314
|
+
attributes[:skip_class] = true
|
|
315
|
+
render_img(inner_text, attributes, parse_options)
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
# Renders an image, floated on the right side of the text frame. Use the :class_img_right parse option to define html classes.
|
|
319
|
+
# :category: Render methods
|
|
320
|
+
def self.render_img_right(inner_text, attributes = {}, parse_options = {})
|
|
321
|
+
attributes[:styles] = "float: left; margin: 0px 0px 10px 10px"
|
|
322
|
+
attributes[:class] += " " + parse_options[:class_img_right]
|
|
323
|
+
attributes[:skip_class] = true
|
|
324
|
+
render_img(inner_text, attributes, parse_options)
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
# Renders the inner_text with a justified text alignment.
|
|
328
|
+
# :category: Render methods
|
|
329
|
+
def self.render_justify(inner_text, attributes = {}, parse_options = {})
|
|
330
|
+
"<div style='text-align: justify'>#{self.parse(inner_text, parse_options)}</div>"
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
# Renders the inner_text with a left text alignment.
|
|
334
|
+
# :category: Render methods
|
|
335
|
+
def self.render_left(inner_text, attributes = {}, parse_options = {})
|
|
336
|
+
"<div style='text-align: left'>#{self.parse(inner_text, parse_options)}</div>"
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
# Renders the inner_text as an ordered list. Each line represents a list item. Use the :class_list parse option to define html classes.
|
|
340
|
+
# :category: Render methods
|
|
341
|
+
def self.render_list(inner_text, attributes = {}, parse_options = {})
|
|
342
|
+
items = inner_text.split(/\n/)
|
|
343
|
+
items.delete_if { | item | item.strip == "" }
|
|
344
|
+
items.map! { | item | "<li>" + self.parse(item, parse_options) + "</li>" }
|
|
345
|
+
return (items.empty?) ? "" : "<ul class='#{parse_options[:class_list].to_s.strip}'>" + items.join("") + "</ol>"
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
# Renders the inner_text as a paragraph. Use the :class_p parse option to define html classes.
|
|
349
|
+
# :category: Render methods
|
|
350
|
+
def self.render_p(inner_text, attributes = {}, parse_options = {})
|
|
351
|
+
"<p class='#{parse_options[:class_p].to_s.strip}'>#{self.parse(inner_text, parse_options)}</p>"
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
# Renders the inner_text with a right text alignment.
|
|
355
|
+
# :category: Render methods
|
|
356
|
+
def self.render_right(inner_text, attributes = {}, parse_options = {})
|
|
357
|
+
"<div style='text-align: right'>#{self.parse(inner_text, parse_options)}</div>"
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
# Renders the inner_text in a <div> block with inline CSS styles, i.e.:
|
|
361
|
+
# [style color: red; border: 1px solid green]...[/style]
|
|
362
|
+
# :category: Render methods
|
|
363
|
+
def self.render_style(inner_text, attributes = {}, parse_options = {})
|
|
364
|
+
styles = attributes[:original_attrib_str].gsub(/'/, "\'")
|
|
365
|
+
"<div style='#{styles}'>#{self.parse(inner_text, parse_options)}</div>"
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
# Converts the [table] to a <table>. Always use this in combination with [tr] and [td] or [th]. Use the :class_table parse option to define html classes.
|
|
369
|
+
# [style color: red; border: 1px solid green]...[/style]
|
|
370
|
+
# :category: Render methods
|
|
371
|
+
def self.render_table(inner_text, attributes = {}, parse_options = {})
|
|
372
|
+
styles = attributes[:default].gsub(/'/, "\'")
|
|
373
|
+
"<div style='#{styles}' class='#{parse_options[:class_table].to_s.strip}'>#{self.parse(inner_text, parse_options)}</div>"
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
# Renders the inner_text underline. Use this with caution, since underline text is associated with hyperlinks.
|
|
377
|
+
# :category: Render methods
|
|
378
|
+
def self.render_u(inner_text, attributes = {}, parse_options = {})
|
|
379
|
+
"<u>#{self.parse(inner_text, parse_options)}</u>"
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
# Renders a web addres. There are two options to define:
|
|
383
|
+
# [url]www.osingasoftware.nl[/ur]
|
|
384
|
+
# [url=www.osingasoftware.nl]Osinga Software[/url]
|
|
385
|
+
# Use the :class_url parse option to define html classes.
|
|
386
|
+
# :category: Render methods
|
|
387
|
+
def self.render_url(inner_text, attributes = {}, parse_options = {})
|
|
388
|
+
url = (attributes[:default] || inner_text)
|
|
389
|
+
url = "http://" + url if (url.match(/^www\./))
|
|
390
|
+
url.gsub!(/\\|'/) { |c| "\\#{c}" }
|
|
391
|
+
return "<a href='#{url}' class='#{parse_options[:class_url].to_s.strip}'>#{inner_text}</a>"
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
# Renders a YouTube video using the video id or url in the inner_text.
|
|
395
|
+
# :category: Render methods
|
|
396
|
+
def self.render_vimeo(inner_text, attributes = {}, parse_options = {})
|
|
397
|
+
attributes[:width] ||= 500
|
|
398
|
+
attributes[:height] ||= 281
|
|
399
|
+
attributes[:class] = parse_options[:class_vimeo]
|
|
400
|
+
attributes[:skip_class] = true
|
|
401
|
+
videoid = (inner_text.scan(/[0-9]{5,}/).to_a)[0].to_s
|
|
402
|
+
src = "http://player.vimeo.com/video/#{videoid}"
|
|
403
|
+
return render_iframe(src, attributes, parse_options)
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
# Renders a YouTube video using the video id or url in the inner_text.
|
|
407
|
+
# :category: Render methods
|
|
408
|
+
def self.render_youtube(inner_text, attributes = {}, parse_options = {})
|
|
409
|
+
attributes[:width] ||= 560
|
|
410
|
+
attributes[:height] ||= 315
|
|
411
|
+
attributes[:class] = parse_options[:class_youtube]
|
|
412
|
+
attributes[:skip_class] = true
|
|
413
|
+
videoid = !inner_text.match(/^[^\?\&]$/).nil? ? inner_text : inner_text.scan(/(\?|&)v=([^\&]*)/)[0][1]
|
|
414
|
+
src = "http://www.youtube.com/embed/#{videoid}"
|
|
415
|
+
return render_iframe(src, attributes, parse_options)
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
# Renders a Youtube, Vimeo or Zideo video using the video id or url in the inner_text.
|
|
419
|
+
# It automatically determines which video renderer should be used based on the given url.
|
|
420
|
+
# :category: Render methods
|
|
421
|
+
def self.render_video(inner_text, attributes = {}, parse_options = {})
|
|
422
|
+
attributes[:class] += " " + parse_options[:class_zideo]
|
|
423
|
+
url = inner_text
|
|
424
|
+
if (!url.match(/zideo\.nl/).nil?)
|
|
425
|
+
return self.render_zideo(inner_text, attributes, parse_options)
|
|
426
|
+
elsif (!url.match(/[0-9]{5,}/).nil?) || (!url.match(/vimeo/).nil?)
|
|
427
|
+
return self.render_vimeo(inner_text, attributes, parse_options)
|
|
428
|
+
elsif (!url.match(/youtu/).nil?) || (!url.match(/^[^\?\&]+{11}$/).nil?)
|
|
429
|
+
return self.render_youtube(inner_text, attributes, parse_options)
|
|
430
|
+
else
|
|
431
|
+
return "Unknown video"
|
|
432
|
+
end
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
# Renders a zideo.nl video using the video id or url in the inner_text.
|
|
436
|
+
# :category: Render methods
|
|
437
|
+
def self.render_zideo(inner_text, attributes = {}, parse_options = {})
|
|
438
|
+
attributes[:width] ||= 480
|
|
439
|
+
attributes[:height] ||= 360
|
|
440
|
+
attributes[:class] += " " + parse_options[:class_zideo]
|
|
441
|
+
attributes[:skip_class] = true
|
|
442
|
+
videoid = !inner_text.match(/^\w+$/).nil? ? inner_text : (inner_text.scan(/playzideo\/(\w+)/).to_a)[1].to_s
|
|
443
|
+
src = "http://www.zideo.nl/zideomediaplayer.php?" + inner_text
|
|
444
|
+
return render_iframe(src, attributes, parse_options)
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: ubbparser
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.5
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Taco Jan Osinga
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2013-01-16 00:00:00.000000000 Z
|
|
13
|
+
dependencies: []
|
|
14
|
+
description: A simple and flexibel ubb parser.
|
|
15
|
+
email: info@osingasoftware.nl
|
|
16
|
+
executables: []
|
|
17
|
+
extensions: []
|
|
18
|
+
extra_rdoc_files: []
|
|
19
|
+
files:
|
|
20
|
+
- lib/ubbparser.rb
|
|
21
|
+
homepage: http://ubbparser.mojura.nl
|
|
22
|
+
licenses: []
|
|
23
|
+
post_install_message:
|
|
24
|
+
rdoc_options: []
|
|
25
|
+
require_paths:
|
|
26
|
+
- lib
|
|
27
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
28
|
+
none: false
|
|
29
|
+
requirements:
|
|
30
|
+
- - ! '>='
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '0'
|
|
33
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
34
|
+
none: false
|
|
35
|
+
requirements:
|
|
36
|
+
- - ! '>='
|
|
37
|
+
- !ruby/object:Gem::Version
|
|
38
|
+
version: '0'
|
|
39
|
+
requirements: []
|
|
40
|
+
rubyforge_project:
|
|
41
|
+
rubygems_version: 1.8.11
|
|
42
|
+
signing_key:
|
|
43
|
+
specification_version: 3
|
|
44
|
+
summary: UBB Parser
|
|
45
|
+
test_files: []
|