diff --git a/README.markdown b/README.markdown
index 94b4e9c..f8d01e1 100644
--- a/README.markdown
+++ b/README.markdown
@@ -66,6 +66,8 @@ RbbCode supports the following BBCode features:
* [i]
* [u]
* [s]
+ * [size]
+ * [color]
* [url]
* [img]
* [quote]
diff --git a/lib/rbbcode.rb b/lib/rbbcode.rb
index cc9849a..d00261a 100644
--- a/lib/rbbcode.rb
+++ b/lib/rbbcode.rb
@@ -25,16 +25,17 @@ def self.parser_class
end
RbbCodeGrammarParser
end
-
+
def initialize(options = {})
@options = {
:output_format => :html,
:emoticons => false,
:sanitize => true,
+ :unsupported_features => :remove,
:sanitize_config => RbbCode::DEFAULT_SANITIZE_CONFIG
}.merge(options)
end
-
+
def convert(bb_code, options = {})
# Options passed to #convert will override any options passed to .new.
options = @options.merge(options)
@@ -69,4 +70,4 @@ def convert_emoticons(output)
def output_format
@options[:output_format]
end
-end
\ No newline at end of file
+end
diff --git a/lib/rbbcode/node_extensions.rb b/lib/rbbcode/node_extensions.rb
index 0498c19..041114a 100644
--- a/lib/rbbcode/node_extensions.rb
+++ b/lib/rbbcode/node_extensions.rb
@@ -5,7 +5,7 @@ def strip_quotes(str)
str.sub(/^"+/, '').sub(/"+$/, '')
end
end
-
+
module RecursiveConversion
def recursively_convert(node, output_method, options, depth = 0)
if node.terminal?
@@ -34,7 +34,7 @@ def recursively_convert(node, output_method, options, depth = 0)
end
end
end
-
+
module DocumentNode
def to_html(options)
contents.elements.collect { |p| p.to_html(options) }.join
@@ -44,10 +44,10 @@ def to_markdown(options)
contents.elements.collect { |p| p.to_markdown(options) }.join
end
end
-
+
module ParagraphNode
include RecursiveConversion
-
+
def to_html(options)
# Convert all child nodes, concatenate the results,
# and wrap the concatenated HTML in
tags.
@@ -66,7 +66,7 @@ def to_markdown(options)
markdown + "\n\n"
end
end
-
+
module BlockquoteNode
include RecursiveConversion
@@ -102,7 +102,7 @@ def to_markdown(options)
end + "\n\n"
end
end
-
+
module BlockquoteLineNode
# Returns the number of line breaks after this line. May be zero for the final
# line, since there doesn't have to be a break before [/quote].
@@ -113,7 +113,7 @@ def post_breaks
module ListNode
include RecursiveConversion
-
+
def to_html(options)
# Convert the :contents child node (defined in the .treetop file)
# and wrap the result in
tags.
@@ -127,10 +127,10 @@ def to_markdown(options)
recursively_convert(items, :to_markdown, options) + "\n"
end
end
-
+
module ListItemNode
include RecursiveConversion
-
+
def to_html(options)
# Convert the :contents child node (defined in the .treetop file)
# and wrap the result in - tags.
@@ -143,13 +143,13 @@ def to_markdown(options)
"* " + recursively_convert(contents, :to_html, options) + "\n"
end
end
-
+
# You won't find this module in the .treetop file. Instead, it's effectively a specialization
# of TagNode, which calls to ImgTagNode when processing an img tag. (However, one of the
# child nodes used here, :url, is indeed defined in the .treetop file.)
module URLTagNode
include Attributes
-
+
def url_to_html(options)
# The :url child node (defined in the .treetop file) may or may not exist,
# depending on how the link is formatted in the BBCode source.
@@ -172,7 +172,7 @@ def url_to_markdown(options)
end
end
end
-
+
# You won't find this module in the .treetop file. Instead, it's effectively a specialization
# of TagNode, which calls to ImgTagNode when processing an img tag.
module ImgTagNode
@@ -185,37 +185,93 @@ def img_to_markdown(options)
end
end
+ # You won't find this module in the .treetop file. Instead, it's effectively a specialization
+ # of TagNode, which calls to ColorTagNode when processing a color tag.
+ module ColorTagNode
+ def color_to_html(options)
+ unsupported_tag(options)
+ end
+
+ def color_to_markdown(options)
+ unsupported_tag(options)
+ end
+
+ def unsupported_tag(options)
+ if options.fetch(:unsupported_features) == :remove
+ text.text_value
+ elsif options.fetch(:unsupported_features) == :span
+ '' + text.text_value + ''
+ end
+ end
+ end
+
+ # You won't find this module in the .treetop file. Instead, it's effectively a specialization
+ # of TagNode, which calls to SizeTagNode when processing a size tag.
+ module SizeTagNode
+ def size_to_html(options)
+ unsupported_tag(options)
+ end
+
+ def size_to_markdown(options)
+ unsupported_tag(options)
+ end
+
+ def unsupported_tag(options)
+ if options.fetch(:unsupported_features) == :remove
+ text.text_value
+ elsif options.fetch(:unsupported_features) == :span
+ '' + text.text_value + ''
+ end
+ end
+ end
+
module UTagNode
def u_to_markdown(options)
# Underlining is unsupported in Markdown. So we just ignore [u] tags.
inner_bbcode
end
end
-
+
module TagNode
include RecursiveConversion
-
+
# For each tag name, we can either: (a) map to a simple HTML tag or Markdown character, or
# (b) invoke a separate Ruby module for more advanced logic.
TAG_MAPPINGS = {
- html: {'b' => 'strong', 'i' => 'em', 'u' => 'u', 'url' => URLTagNode, 'img' => ImgTagNode},
- markdown: {'b' => '**', 'i' => '*', 'u' => UTagNode, 'url' => URLTagNode, 'img' => ImgTagNode}
+ html: {
+ 'b' => 'strong',
+ 'i' => 'em',
+ 'u' => 'u',
+ 'url' => URLTagNode,
+ 'img' => ImgTagNode,
+ 'color' => ColorTagNode,
+ 'size' => SizeTagNode
+ },
+ markdown: {
+ 'b' => '**',
+ 'i' => '*',
+ 'u' => UTagNode,
+ 'url' => URLTagNode,
+ 'img' => ImgTagNode,
+ 'color' => ColorTagNode,
+ 'size' => SizeTagNode
+ }
}
-
+
def contents
# The first element is the opening tag, the second is everything inside,
# and the third is the closing tag.
- elements[1]
+ elements[1]
end
-
+
def tag_name
elements.first.text_value.slice(1..-2).downcase
end
-
+
def inner_bbcode
contents.elements.collect { |e| e.text_value }.join
end
-
+
def inner_html(options)
contents.elements.collect do |node|
recursively_convert(node, :to_html, options)
@@ -254,7 +310,7 @@ def convert(output_format, options)
send("wrap_#{output_format}", t, options)
end
end
-
+
def to_html(options)
convert :html, options
end
@@ -263,7 +319,7 @@ def to_markdown(options)
convert :markdown, options
end
end
-
+
module SingleBreakNode
def to_html(options)
'
'
@@ -273,7 +329,7 @@ def to_markdown(options)
"\n"
end
end
-
+
module LiteralTextNode
def to_html(options)
text_value
diff --git a/lib/rbbcode/rbbcode_grammar.treetop b/lib/rbbcode/rbbcode_grammar.treetop
index 818673b..f166a9d 100644
--- a/lib/rbbcode/rbbcode_grammar.treetop
+++ b/lib/rbbcode/rbbcode_grammar.treetop
@@ -92,7 +92,7 @@ grammar RbbCodeGrammar
rule tag
# Make sure that anytime you call def_tag, you add it to this list:
- (bold / italic / underline / simple_url / complex_url / img)
+ (bold / italic / underline / simple_url / complex_url / img / color / size)
end
@@ -101,7 +101,19 @@ grammar RbbCodeGrammar
<%= def_tag 'underline', 'u' %>
<%= def_tag 'simple_url', 'url' %>
<%= def_tag 'img', 'img' %>
-
+
+ rule size
+ '[size=' size_value:[^\]]+ ']'
+ text:(!'[/size]' .)+
+ '[/size]'
+ end
+
+ rule color
+ '[color=' color_name:[^\]]+ ']'
+ text:(!'[/color]' .)+
+ '[/color]'
+ end
+
rule complex_url
'[url=' url:[^\]]+ ']'
text:(!'[/url]' .)+
diff --git a/test/unsupported_features_test.rb b/test/unsupported_features_test.rb
new file mode 100644
index 0000000..20f9a88
--- /dev/null
+++ b/test/unsupported_features_test.rb
@@ -0,0 +1,38 @@
+require File.join(File.expand_path(File.dirname(__FILE__)), 'test_helper.rb')
+
+class TestUnsupportedFeatures < Minitest::Test
+ include RbbCode::OutputAssertions
+
+ def test_remove_color_and_size_tags_to_html
+ assert_converts_to(
+ 'Not colored or resized but bold.
',
+ 'Not [color=red]colored[/color] or [size=3]resized[/size] but [b]bold.[/b]',
+ {}
+ )
+ end
+
+ def test_remove_color_and_size_tags_to_markdown
+ assert_converts_to(
+ "Not colored or resized but **bold.**\n\n",
+ 'Not [color=red]colored[/color] or [size=3]resized[/size] but [b]bold.[/b]',
+ { output_format: :markdown }
+ )
+ end
+
+ def test_color_and_size_with_span_tags_to_html
+ assert_converts_to(
+ 'Not colored or resized but bold.
',
+ 'Not [color=red]colored[/color] or [size=3]resized[/size] but [b]bold.[/b]',
+ { :unsupported_features => :span }
+ )
+ end
+
+ def test_color_and_size_with_tags_to_markdown
+ assert_converts_to(
+ "Not colored or resized but **bold.**\n\n",
+ 'Not [color=red]colored[/color] or [size=3]resized[/size] but [b]bold.[/b]',
+ { :unsupported_features => :span, output_format: :markdown }
+ )
+ end
+
+end