rbbcode 0.1.11 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/rbbcode/node_extensions.rb +126 -0
- data/lib/rbbcode/rbbcode_grammar.treetop +113 -0
- data/lib/rbbcode/sanitize.rb +13 -0
- data/lib/rbbcode.rb +49 -5
- metadata +34 -131
- data/.document +0 -5
- data/Gemfile +0 -13
- data/LICENSE.txt +0 -21
- data/README.markdown +0 -126
- data/Rakefile +0 -35
- data/VERSION +0 -1
- data/lib/rbbcode/html_maker.rb +0 -90
- data/lib/rbbcode/parser.rb +0 -32
- data/lib/rbbcode/schema.rb +0 -309
- data/lib/rbbcode/tree_maker.rb +0 -430
- data/pkg/rbbcode-0.1.8.gem +0 -0
- data/rbbcode.gemspec +0 -82
- data/spec/html_maker_spec.rb +0 -92
- data/spec/node_spec_helper.rb +0 -117
- data/spec/parser_spec.rb +0 -163
- data/spec/schema_spec.rb +0 -100
- data/spec/spec_helper.rb +0 -17
- data/spec/tree_maker_spec.rb +0 -123
@@ -0,0 +1,126 @@
|
|
1
|
+
class RbbCode
|
2
|
+
module RecursiveConversion
|
3
|
+
def recursively_convert(node, depth = 0)
|
4
|
+
if node.terminal?
|
5
|
+
if node.respond_to?(:to_html)
|
6
|
+
node.to_html
|
7
|
+
else
|
8
|
+
node.text_value.match(/^[\r\n\t]+$/) ? '' : node.text_value
|
9
|
+
end
|
10
|
+
else
|
11
|
+
if node.respond_to?(:to_html)
|
12
|
+
node.to_html
|
13
|
+
else
|
14
|
+
node.elements.collect do |sub_node|
|
15
|
+
recursively_convert(sub_node, depth + 1)
|
16
|
+
end.join
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module DocumentNode
|
23
|
+
def to_html
|
24
|
+
contents.elements.collect { |p| p.to_html }.join
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module ParagraphNode
|
29
|
+
include RecursiveConversion
|
30
|
+
|
31
|
+
def to_html
|
32
|
+
html = elements.collect do |node|
|
33
|
+
recursively_convert(node)
|
34
|
+
end.join
|
35
|
+
"\n<p>" + html + "</p>\n"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
module BlockquoteNode
|
40
|
+
include RecursiveConversion
|
41
|
+
|
42
|
+
def to_html
|
43
|
+
"\n<blockquote>" + recursively_convert(contents) + "</blockquote>\n"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
module ListNode
|
48
|
+
include RecursiveConversion
|
49
|
+
|
50
|
+
def to_html
|
51
|
+
"\n<ul>" + recursively_convert(contents) + "</ul>\n"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
module ListItemNode
|
56
|
+
include RecursiveConversion
|
57
|
+
|
58
|
+
def to_html
|
59
|
+
"\n<li>" + recursively_convert(contents) + "</li>\n"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
module URLTagNode
|
64
|
+
def url_to_html
|
65
|
+
if respond_to?(:url) and respond_to?(:text)
|
66
|
+
# A URL tag formatted like [url=http://example.com]Example[/url]
|
67
|
+
'<a href="' + url.text_value + '">' + text.text_value + '</a>'
|
68
|
+
else
|
69
|
+
# A URL tag formatted like [url]http://example.com[/url]
|
70
|
+
'<a href="' + inner_bbcode + '">' + inner_bbcode + '</a>'
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
module ImgTagNode
|
76
|
+
def img_to_html
|
77
|
+
'<img src="' + inner_bbcode + '" alt="Image"/>'
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
module TagNode
|
82
|
+
include RecursiveConversion
|
83
|
+
|
84
|
+
TAG_MAPPINGS = {'b' => 'strong', 'i' => 'em', 'u' => 'u', 'url' => URLTagNode, 'img' => ImgTagNode}
|
85
|
+
|
86
|
+
def contents
|
87
|
+
# The first element is the opening tag, the second is everything inside,
|
88
|
+
# and the third is the closing tag.
|
89
|
+
elements[1]
|
90
|
+
end
|
91
|
+
|
92
|
+
def tag_name
|
93
|
+
elements.first.text_value.slice(1..-2).downcase
|
94
|
+
end
|
95
|
+
|
96
|
+
def inner_bbcode
|
97
|
+
contents.elements.collect { |e| e.text_value }.join
|
98
|
+
end
|
99
|
+
|
100
|
+
def inner_html
|
101
|
+
contents.elements.collect do |node|
|
102
|
+
recursively_convert(node)
|
103
|
+
end.join
|
104
|
+
end
|
105
|
+
|
106
|
+
def to_html
|
107
|
+
t = TAG_MAPPINGS[tag_name]
|
108
|
+
if t.nil?
|
109
|
+
raise "No tag mapping found for #{tag_name}"
|
110
|
+
elsif t.is_a?(Module)
|
111
|
+
extend(t)
|
112
|
+
send(tag_name + '_to_html')
|
113
|
+
# Thus, if our tag_name is"url, and TAG_MAPPINGS points us to URLTagNode,
|
114
|
+
# that module must define url_to_html.
|
115
|
+
else
|
116
|
+
"<#{t}>" + inner_html + "</#{t}>"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
module SingleBreakNode
|
122
|
+
def to_html
|
123
|
+
'<br/>'
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
<%
|
2
|
+
def def_tag(rule_name, tag_name)
|
3
|
+
"
|
4
|
+
rule #{rule_name}
|
5
|
+
('[#{tag_name.downcase}]'/'[#{tag_name.upcase}]')
|
6
|
+
(!'[/#{tag_name.downcase}]' !'[/#{tag_name.upcase}]'
|
7
|
+
(tag <RbbCode::TagNode> / .))+
|
8
|
+
('[/#{tag_name.downcase}]' / '[/#{tag_name.upcase}]')
|
9
|
+
end
|
10
|
+
"
|
11
|
+
end
|
12
|
+
%>
|
13
|
+
|
14
|
+
grammar RbbCodeGrammar
|
15
|
+
rule document
|
16
|
+
# Consume the trailing linebreaks, because the paragraph lookahead
|
17
|
+
# doesn't consume them.
|
18
|
+
contents:(blockquote <RbbCode::BlockquoteNode> / list <RbbCode::ListNode> / paragraph <RbbCode::ParagraphNode>)* break_ws* <RbbCode::DocumentNode>
|
19
|
+
end
|
20
|
+
|
21
|
+
rule paragraph
|
22
|
+
(break_ws 2..)
|
23
|
+
(
|
24
|
+
!(break_ws 2..)
|
25
|
+
paragraph_contents
|
26
|
+
)+
|
27
|
+
end
|
28
|
+
|
29
|
+
rule paragraph_contents
|
30
|
+
(tag <RbbCode::TagNode> / single_break_ws / .)
|
31
|
+
end
|
32
|
+
|
33
|
+
rule break_ws
|
34
|
+
# Allow whitespace around the linebreaks
|
35
|
+
[ \t]* [\r\n] [ \t]*
|
36
|
+
end
|
37
|
+
|
38
|
+
rule whitespace
|
39
|
+
# Any whitespace, including linebreaks
|
40
|
+
[ \t\r\n]
|
41
|
+
end
|
42
|
+
|
43
|
+
rule single_break_ws
|
44
|
+
# We don't count linebreaks when they're immediately followed by
|
45
|
+
# certain keywords. This avoids printing an extra <br/> in some cases.
|
46
|
+
break_ws !break_ws !(break_ws* ('[/quote]' / '[*]' / '[/list]')) <RbbCode::SingleBreakNode>
|
47
|
+
end
|
48
|
+
|
49
|
+
rule blockquote
|
50
|
+
break_ws*
|
51
|
+
'[quote]'
|
52
|
+
contents:(
|
53
|
+
# Possible linebreaks after opening quote tag
|
54
|
+
break_ws*
|
55
|
+
|
56
|
+
# First paragraph (mandatory)
|
57
|
+
(blockquote_paragraph <RbbCode::ParagraphNode>)
|
58
|
+
|
59
|
+
# Subsequent paragraphs (optional)
|
60
|
+
(
|
61
|
+
(break_ws 2..)
|
62
|
+
(blockquote_paragraph <RbbCode::ParagraphNode>)
|
63
|
+
)*
|
64
|
+
|
65
|
+
# Possible linebreaks before closing quote tag
|
66
|
+
break_ws*
|
67
|
+
)
|
68
|
+
'[/quote]'
|
69
|
+
end
|
70
|
+
|
71
|
+
rule blockquote_paragraph
|
72
|
+
(!('[/quote]' / (break_ws 2..)) paragraph_contents)+
|
73
|
+
end
|
74
|
+
|
75
|
+
rule list
|
76
|
+
break_ws*
|
77
|
+
'[list]'
|
78
|
+
contents:(
|
79
|
+
# Possible linebreaks after opening list tag
|
80
|
+
whitespace*
|
81
|
+
|
82
|
+
# At least one list item
|
83
|
+
(
|
84
|
+
(
|
85
|
+
'[*]'
|
86
|
+
contents:(!'[/list]' !'[*]' paragraph_contents)*
|
87
|
+
<RbbCode::ListItemNode>
|
88
|
+
)
|
89
|
+
)+
|
90
|
+
|
91
|
+
# Possible linebreaks before closing list tag
|
92
|
+
whitespace*
|
93
|
+
)
|
94
|
+
'[/list]'
|
95
|
+
end
|
96
|
+
|
97
|
+
rule tag
|
98
|
+
# Make sure that anytime you call def_tag, you add it to this list:
|
99
|
+
bold / italic / underline / simple_url / complex_url / img
|
100
|
+
end
|
101
|
+
|
102
|
+
<%= def_tag 'bold', 'b' %>
|
103
|
+
<%= def_tag 'italic', 'i' %>
|
104
|
+
<%= def_tag 'underline', 'u' %>
|
105
|
+
<%= def_tag 'simple_url', 'url' %>
|
106
|
+
<%= def_tag 'img', 'img' %>
|
107
|
+
|
108
|
+
rule complex_url
|
109
|
+
'[url=' url:[^\]]+ ']'
|
110
|
+
text:(!'[/url]' .)+
|
111
|
+
'[/url]'
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class RbbCode
|
2
|
+
DEFAULT_SANITIZE_CONFIG = {
|
3
|
+
:elements => %w[a blockquote br code del em img li p pre strong ul],
|
4
|
+
:attributes => {
|
5
|
+
'a' => %w[href],
|
6
|
+
'img' => %w[alt src]
|
7
|
+
},
|
8
|
+
|
9
|
+
:protocols => {
|
10
|
+
'a' => {'href' => ['ftp', 'http', 'https', 'mailto', :relative]}
|
11
|
+
}
|
12
|
+
}
|
13
|
+
end
|
data/lib/rbbcode.rb
CHANGED
@@ -1,6 +1,50 @@
|
|
1
|
-
|
1
|
+
# Uncomment this when developing:
|
2
|
+
#$:.unshift './lib'
|
2
3
|
|
3
|
-
require '
|
4
|
-
require '
|
5
|
-
require '
|
6
|
-
require '
|
4
|
+
require 'erb'
|
5
|
+
require 'rubygems'
|
6
|
+
require 'treetop'
|
7
|
+
require 'sanitize'
|
8
|
+
require 'rbbcode/node_extensions'
|
9
|
+
require 'rbbcode/sanitize'
|
10
|
+
|
11
|
+
class RbbCode
|
12
|
+
def self.parser_class
|
13
|
+
if !@grammar_loaded
|
14
|
+
Treetop.load_from_string(
|
15
|
+
ERB.new(
|
16
|
+
File.read(
|
17
|
+
File.join(
|
18
|
+
File.dirname(__FILE__),
|
19
|
+
'rbbcode/rbbcode_grammar.treetop'
|
20
|
+
)
|
21
|
+
)
|
22
|
+
).result
|
23
|
+
)
|
24
|
+
@grammar_loaded = true
|
25
|
+
end
|
26
|
+
RbbCodeGrammarParser
|
27
|
+
end
|
28
|
+
|
29
|
+
def initialize(options = {})
|
30
|
+
@options = {
|
31
|
+
:sanitize => true,
|
32
|
+
:sanitize_config => RbbCode::DEFAULT_SANITIZE_CONFIG
|
33
|
+
}.merge(options)
|
34
|
+
end
|
35
|
+
|
36
|
+
def convert(bb_code)
|
37
|
+
html = self.class.parser_class.new.parse("\n\n" + bb_code + "\n\n").to_html
|
38
|
+
if @options[:emoticons]
|
39
|
+
@options[:emoticons].each do |emoticon, url|
|
40
|
+
html.gsub!(emoticon, '<img src="' + url + '" alt="Emoticon"/>')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
html
|
44
|
+
if @options[:sanitize]
|
45
|
+
Sanitize.clean(html, @options[:sanitize_config])
|
46
|
+
else
|
47
|
+
html
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
metadata
CHANGED
@@ -1,152 +1,66 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rbbcode
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 1
|
9
|
-
- 11
|
10
|
-
version: 0.1.11
|
4
|
+
prerelease:
|
5
|
+
version: 1.0.0
|
11
6
|
platform: ruby
|
12
7
|
authors:
|
13
8
|
- Jarrett Colby
|
14
|
-
- aq1018@gmail.com
|
15
9
|
autorequire:
|
16
10
|
bindir: bin
|
17
11
|
cert_chain: []
|
18
12
|
|
19
|
-
date:
|
13
|
+
date: 2012-10-27 00:00:00 -05:00
|
20
14
|
default_executable:
|
21
15
|
dependencies:
|
22
16
|
- !ruby/object:Gem::Dependency
|
23
|
-
|
17
|
+
name: treetop
|
24
18
|
prerelease: false
|
25
|
-
|
26
|
-
version_requirements: &id001 !ruby/object:Gem::Requirement
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
27
20
|
none: false
|
28
21
|
requirements:
|
29
22
|
- - ">="
|
30
23
|
- !ruby/object:Gem::Version
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
- 1
|
35
|
-
- 3
|
36
|
-
version: 0.1.3
|
37
|
-
requirement: *id001
|
38
|
-
- !ruby/object:Gem::Dependency
|
39
|
-
type: :development
|
40
|
-
prerelease: false
|
41
|
-
name: rspec
|
42
|
-
version_requirements: &id002 !ruby/object:Gem::Requirement
|
43
|
-
none: false
|
44
|
-
requirements:
|
45
|
-
- - ~>
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
hash: 3
|
48
|
-
segments:
|
49
|
-
- 2
|
50
|
-
- 3
|
51
|
-
- 0
|
52
|
-
version: 2.3.0
|
53
|
-
requirement: *id002
|
24
|
+
version: "0"
|
25
|
+
type: :runtime
|
26
|
+
version_requirements: *id001
|
54
27
|
- !ruby/object:Gem::Dependency
|
55
|
-
|
28
|
+
name: lorax
|
56
29
|
prerelease: false
|
57
|
-
|
58
|
-
version_requirements: &id003 !ruby/object:Gem::Requirement
|
30
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
59
31
|
none: false
|
60
32
|
requirements:
|
61
33
|
- - ">="
|
62
34
|
- !ruby/object:Gem::Version
|
63
|
-
hash: 3
|
64
|
-
segments:
|
65
|
-
- 0
|
66
35
|
version: "0"
|
67
|
-
requirement: *id003
|
68
|
-
- !ruby/object:Gem::Dependency
|
69
36
|
type: :development
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
none: false
|
74
|
-
requirements:
|
75
|
-
- - ~>
|
76
|
-
- !ruby/object:Gem::Version
|
77
|
-
hash: 7
|
78
|
-
segments:
|
79
|
-
- 0
|
80
|
-
- 6
|
81
|
-
- 0
|
82
|
-
version: 0.6.0
|
83
|
-
requirement: *id004
|
84
|
-
- !ruby/object:Gem::Dependency
|
85
|
-
type: :development
|
86
|
-
prerelease: false
|
87
|
-
name: bundler
|
88
|
-
version_requirements: &id005 !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
|
-
requirements:
|
91
|
-
- - ~>
|
92
|
-
- !ruby/object:Gem::Version
|
93
|
-
hash: 23
|
94
|
-
segments:
|
95
|
-
- 1
|
96
|
-
- 0
|
97
|
-
- 0
|
98
|
-
version: 1.0.0
|
99
|
-
requirement: *id005
|
100
|
-
- !ruby/object:Gem::Dependency
|
101
|
-
type: :development
|
102
|
-
prerelease: false
|
103
|
-
name: jeweler
|
104
|
-
version_requirements: &id006 !ruby/object:Gem::Requirement
|
105
|
-
none: false
|
106
|
-
requirements:
|
107
|
-
- - ~>
|
108
|
-
- !ruby/object:Gem::Version
|
109
|
-
hash: 7
|
110
|
-
segments:
|
111
|
-
- 1
|
112
|
-
- 5
|
113
|
-
- 2
|
114
|
-
version: 1.5.2
|
115
|
-
requirement: *id006
|
116
|
-
description: RbbCode is a customizable Ruby library for parsing BB Code. RbbCode validates and cleans input. It supports customizable schemas so you can set rules about what tags are allowed where. The default rules are designed to ensure valid HTML output.
|
117
|
-
email: jarrett@jarrettcolby.com, aq1018@gmail.com
|
37
|
+
version_requirements: *id002
|
38
|
+
description: Converts BBCode to HTML. Gracefully handles invalid input.
|
39
|
+
email: jarrett@madebyhq.com
|
118
40
|
executables: []
|
119
41
|
|
120
42
|
extensions: []
|
121
43
|
|
122
|
-
extra_rdoc_files:
|
123
|
-
|
124
|
-
- README.markdown
|
44
|
+
extra_rdoc_files: []
|
45
|
+
|
125
46
|
files:
|
126
|
-
- .
|
127
|
-
-
|
128
|
-
-
|
129
|
-
- README.markdown
|
130
|
-
- Rakefile
|
131
|
-
- VERSION
|
47
|
+
- lib/rbbcode/node_extensions.rb
|
48
|
+
- lib/rbbcode/rbbcode_grammar.treetop
|
49
|
+
- lib/rbbcode/sanitize.rb
|
132
50
|
- lib/rbbcode.rb
|
133
|
-
- lib/rbbcode/html_maker.rb
|
134
|
-
- lib/rbbcode/parser.rb
|
135
|
-
- lib/rbbcode/schema.rb
|
136
|
-
- lib/rbbcode/tree_maker.rb
|
137
|
-
- pkg/rbbcode-0.1.8.gem
|
138
|
-
- rbbcode.gemspec
|
139
|
-
- spec/html_maker_spec.rb
|
140
|
-
- spec/node_spec_helper.rb
|
141
|
-
- spec/parser_spec.rb
|
142
|
-
- spec/schema_spec.rb
|
143
|
-
- spec/spec_helper.rb
|
144
|
-
- spec/tree_maker_spec.rb
|
145
51
|
has_rdoc: true
|
146
|
-
homepage:
|
147
|
-
licenses:
|
148
|
-
|
149
|
-
post_install_message:
|
52
|
+
homepage: https://github.com/jarrett/rbbcode
|
53
|
+
licenses: []
|
54
|
+
|
55
|
+
post_install_message: "\n\
|
56
|
+
Important notice for users of 0.1.11 or lower\n\
|
57
|
+
=============================================\n\n\
|
58
|
+
RbbCode has been updated! The new release (1.x.x)\n\
|
59
|
+
is not compatible with the old one (0.1.11). If\n\
|
60
|
+
you want to upgrade to 1.x.x, you'll need to\n\
|
61
|
+
adjust any calls to RbbCode in your code to match\n\
|
62
|
+
the new API. For more information:\n\n\
|
63
|
+
https://github.com/jarrett/rbbcode\n"
|
150
64
|
rdoc_options: []
|
151
65
|
|
152
66
|
require_paths:
|
@@ -156,30 +70,19 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
156
70
|
requirements:
|
157
71
|
- - ">="
|
158
72
|
- !ruby/object:Gem::Version
|
159
|
-
hash: 3
|
160
|
-
segments:
|
161
|
-
- 0
|
162
73
|
version: "0"
|
163
74
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
164
75
|
none: false
|
165
76
|
requirements:
|
166
77
|
- - ">="
|
167
78
|
- !ruby/object:Gem::Version
|
168
|
-
hash: 3
|
169
|
-
segments:
|
170
|
-
- 0
|
171
79
|
version: "0"
|
172
80
|
requirements: []
|
173
81
|
|
174
82
|
rubyforge_project:
|
175
|
-
rubygems_version: 1.
|
83
|
+
rubygems_version: 1.6.2
|
176
84
|
signing_key:
|
177
85
|
specification_version: 3
|
178
|
-
summary:
|
179
|
-
test_files:
|
180
|
-
|
181
|
-
- spec/node_spec_helper.rb
|
182
|
-
- spec/parser_spec.rb
|
183
|
-
- spec/schema_spec.rb
|
184
|
-
- spec/spec_helper.rb
|
185
|
-
- spec/tree_maker_spec.rb
|
86
|
+
summary: RbbCode
|
87
|
+
test_files: []
|
88
|
+
|
data/.document
DELETED
data/Gemfile
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
source 'http://rubygems.org'
|
2
|
-
|
3
|
-
gem 'sanitize-url', '>= 0.1.3'
|
4
|
-
|
5
|
-
# Add dependencies to develop your gem here.
|
6
|
-
# Include everything needed to run rake, tests, features, etc.
|
7
|
-
group :development do
|
8
|
-
gem 'rspec', '~> 2.3.0'
|
9
|
-
gem 'bluecloth'
|
10
|
-
gem 'yard', '~> 0.6.0'
|
11
|
-
gem 'bundler', '~> 1.0.0'
|
12
|
-
gem 'jeweler', '~> 1.5.2'
|
13
|
-
end
|
data/LICENSE.txt
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
Copyright (c) 2004-2008 David Heinemeier Hansson
|
2
|
-
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
-
a copy of this software and associated documentation files (the
|
5
|
-
"Software"), to deal in the Software without restriction, including
|
6
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
-
permit persons to whom the Software is furnished to do so, subject to
|
9
|
-
the following conditions:
|
10
|
-
|
11
|
-
The above copyright notice and this permission notice shall be
|
12
|
-
included in all copies or substantial portions of the Software.
|
13
|
-
|
14
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
-
|
data/README.markdown
DELETED
@@ -1,126 +0,0 @@
|
|
1
|
-
About RbbCode
|
2
|
-
=============
|
3
|
-
|
4
|
-
RbbCode is a customizable Ruby library for parsing BB Code originally developed by Jarret (https://github.com/jarrett/rbbcode).
|
5
|
-
|
6
|
-
RbbCode validates and cleans input. It supports customizable schemas so you can set rules about what tags are allowed where. The default rules are designed to ensure valid HTML output.
|
7
|
-
|
8
|
-
Example usage:
|
9
|
-
|
10
|
-
require 'rubygems'
|
11
|
-
require 'rbbcode'
|
12
|
-
|
13
|
-
bb_code = 'This is [b]bold[/b] text'
|
14
|
-
parser = RbbCode::Parser.new
|
15
|
-
html = parser.parse(bb_code)
|
16
|
-
# => '<p>This is <strong>bold</strong> text</p>'
|
17
|
-
|
18
|
-
Customizing
|
19
|
-
===========
|
20
|
-
|
21
|
-
You can customize RbbCode by subclassing HtmlMaker and/or by passing configuration directives to a Schema object.
|
22
|
-
|
23
|
-
HtmlMaker can be extended by adding methods like this:
|
24
|
-
|
25
|
-
class MyHtmlMaker < RbbCode::HtmlMaker
|
26
|
-
def html_from_TAGNAME_tag(node)
|
27
|
-
# ...
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
...where TAGNAME should be replaced with the name of the tag. The method should accept an RbbCode::TagNode and return HTML as a string. (See tree_maker.rb for the definition of RbbCode::TagNode.) Anytime the parser encounters the specified tag, it will call your method and insert the returned HTML into the output.
|
32
|
-
|
33
|
-
Now you just have to tell the Parser object to use an instance of your custom subclass instead of the default HtmlMaker:
|
34
|
-
|
35
|
-
my_html_maker = MyHtmlMaker.new
|
36
|
-
parser = RbbCode::Parser.new(:html_maker => my_html_maker)
|
37
|
-
|
38
|
-
RbbCode removes invalid markup by comparing the input against a Schema object. The Schema is much like a DTD in XML. You can set your own rules and change the default ones by calling configuration methods on a Schema instance. Look at Schema#use_defaults in schema.rb for examples.
|
39
|
-
|
40
|
-
Normally, RbbCode instantiates Schema behind the scenes, but if you want to customize it, you'll have to instantiate it yourself and pass the instance to the Parser object:
|
41
|
-
|
42
|
-
schema = RbbCode::Schema.new
|
43
|
-
schema.tag('quote').may_not_be_nested # Or whatever other configuration methods you want to call
|
44
|
-
parser = RbbCode::Parser.new(:schema => schema)
|
45
|
-
|
46
|
-
Unicode Support
|
47
|
-
===============
|
48
|
-
|
49
|
-
UTF-8 compatibility is a high priority for this project. RbbCode aims to be fully compatible with UTF-8, but not with other multibyte encodings. As of the most recent release, UTF-8 support has been tested to a limited extent. It is possible that there are some hidden gotchas. Please report any bugs you may find.
|
50
|
-
|
51
|
-
RbbCode does not use any Unicode-aware string classes or methods. Instead, it relies on the fact that BBCode control characters are all in the ASCII range (0x00-0x7F). Since bytes in that range are not allowed as part of multibyte characters, the parser should not mistake a single byte in a multibyte character for a control character. This approach does mean that multibyte characters will be temporarily split up in the RbbCode internals. But in theory, this should be of no consequence, because they should always be correctly reassembled in the output. Please submit a bug report if this is not the case.
|
52
|
-
|
53
|
-
BBCode Syntax
|
54
|
-
=================
|
55
|
-
|
56
|
-
As of this writing, there is no official BBCode standard. There are reference implementations, but they differ quite substantially. Wikipedia seemed like the only source with any claim to being canonical, so I followed its examples. The Wikipedia article is at:
|
57
|
-
|
58
|
-
http://en.wikipedia.org/wiki/BBCode
|
59
|
-
|
60
|
-
From that, I extracted some rules for "common" BBCode syntax. Here are the rules.
|
61
|
-
|
62
|
-
Text gets wrapped in `<p>` tags unless it's marked up as some other block-level element such as a list. A single line break becomes a `<br/>`. Two line breaks mark the end of a paragraph, thus a closing `</p>` and possibly an opening `<p>`.
|
63
|
-
|
64
|
-
Tags must be in one of the following forms:
|
65
|
-
|
66
|
-
[tagname]Text[/tagname]
|
67
|
-
[tagname=value]Text[/tagname]
|
68
|
-
|
69
|
-
As you can infer from the second example, RbbCode does not support attributes like in HTML and XML. Rather, a tag can have a single "value," which is similar to an anonymous attribute. This is how [url] and [img] tags work, for example.
|
70
|
-
|
71
|
-
RbbCode does not support all the tags listed on Wikpedia out of the box, and probably never will. However, you can easily add support for as many tags as you want.
|
72
|
-
|
73
|
-
|
74
|
-
BBCode Syntax Extensions
|
75
|
-
========================
|
76
|
-
|
77
|
-
In order to support inline BBCode tags like smileys I added the following syntax:
|
78
|
-
[:tagname]
|
79
|
-
|
80
|
-
These tags do not need to be closed. For HTML generation the method html_from_tagname_tag(node) is called, as usual.
|
81
|
-
|
82
|
-
XSS Prevention
|
83
|
-
==============
|
84
|
-
|
85
|
-
Preventing XSS is one of the top priorities for RbbCode. For tags, RbbCode uses a whitelist. However, URLs can contain JavaScript, and it is not possible to construct a URL whitelist. Therefore, when parsing tags like [url] and [img], RbbCode has to use a blacklist. If you find a vulnerability there, please submit a bug report immediately.
|
86
|
-
|
87
|
-
RbbCode sanitizes its URLs in two ways. First, it prepends "http://" to any URL that doesn't have a well-formed protocol. "javascript:" is not a well-formed protocol, because it lacks the two slashes. "javascript://" should not execute. Second, RbbCode hex-encodes various permutations of the word "JavaScript." These two precautions will *hopefully* be enough to prevent browsers executing scripts in URLs, but I can't be sure, because there are a lot of browsers out there.
|
88
|
-
|
89
|
-
Also, by enforcing valid XHTML, RbbCode should prevent users breaking your layouts with unclosed tags. Submit a bug report if it doesn't.
|
90
|
-
|
91
|
-
Bug Reports
|
92
|
-
===========
|
93
|
-
|
94
|
-
This project is maintained, but bugs sometimes take a few weeks to get fixed. If you find a bug, please take the following steps. Doing so will save me effort and thus greatly increase the chance of the bug being fixed in a timely manner.
|
95
|
-
|
96
|
-
1. Make sure it's a bug and not a feature request. See below for details.
|
97
|
-
2. Write a failing spec. This project uses RSpec. If you don't know how to use it and don't care to learn, then just create a script that produces bad output. Be sure to make it clear what you think the correct output should be. (Don't just say "the output is wrong.") Provide the *shortest* possible input that demonstrates the bug. For example, "Foo bar" is better dummy text than "Mary had a little lamb whose fleece was white as snow." Don't include extra markup that isn't necessary to trigger the bug.
|
98
|
-
3. Open an issue on Github and paste in your spec or sample script. This is preferred over sending a message.
|
99
|
-
|
100
|
-
Feature Requests vs Bugs
|
101
|
-
========================
|
102
|
-
|
103
|
-
Examples of bugs:
|
104
|
-
|
105
|
-
- Executable JavaScript appears in the output
|
106
|
-
- The output is not a valid XHTML fragment
|
107
|
-
- RbbCode fails to support common BBCode syntax, as exemplified in http://en.wikipedia.org/wiki/BBCode
|
108
|
-
- UTF-8 messes up, or the output is otherwise mangled
|
109
|
-
- Any of the specs fail
|
110
|
-
|
111
|
-
Example of feature requests:
|
112
|
-
|
113
|
-
- You want support for more tags. RbbCode lets you define your own tags. So the absence of, say, the "color" tag in the default parser is not a bug
|
114
|
-
- You want to support uncommon BBCode syntax, i.e. something you wouldn't see on http://en.wikipedia.org/wiki/BBCode
|
115
|
-
|
116
|
-
Do not open an issue for a feature request. Just send a message on Github.
|
117
|
-
|
118
|
-
Installation
|
119
|
-
============
|
120
|
-
|
121
|
-
gem install rbbcode
|
122
|
-
|
123
|
-
If that doesn't work, it's probably because RbbCode is hosted on Gemcutter, and your computer doesn't know about Gemcutter yet. To fix that:
|
124
|
-
|
125
|
-
gem install gemcutter
|
126
|
-
gem tumble
|