Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ RbbCode supports the following BBCode features:
* [i]
* [u]
* [s]
* [size]
* [color]
* [url]
* [img]
* [quote]
Expand Down
25 changes: 17 additions & 8 deletions lib/rbbcode.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ def self.parser_class
end

def initialize(options = {})
@options = {
@@options = {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am introducing @@options here as a class variable in order to be able to use it in a static RbbCode.options called in the new Node classes. These don't have any reference to the RbbCode instance and I don't know how to inject options into them.

:output_format => :html,
:sanitize => true,
:unsupported_features => :remove,
:sanitize_config => RbbCode::DEFAULT_SANITIZE_CONFIG
}.merge(options)
end
Expand All @@ -39,26 +40,34 @@ def convert(bb_code)
bb_code = bb_code.gsub("\r\n", "\n").gsub("\r", "\n")
# Add linebreaks before and after so that paragraphs etc. can be recognized.
bb_code = "\n\n" + bb_code + "\n\n"
output = self.class.parser_class.new.parse(bb_code).send("to_#{@options[:output_format]}")
if @options[:emoticons]
output = self.class.parser_class.new.parse(bb_code).send("to_#{output_format}")
if options[:emoticons]
output = convert_emoticons(output)
end
# Sanitization works for HTML only.
if @options[:output_format] == :html and @options[:sanitize]
Sanitize.clean(output, @options[:sanitize_config])
if output_format == :html and options[:sanitize]
Sanitize.clean(output, options[:sanitize_config])
else
output
end
end

def convert_emoticons(output)
@options[:emoticons].each do |emoticon, url|
options[:emoticons].each do |emoticon, url|
output.gsub!(emoticon, '<img src="' + url + '" alt="Emoticon"/>')
end
output
end

def output_format
@options[:output_format]
options[:output_format]
end
end

def options
@@options
end

def self.options
@@options
end
end
60 changes: 58 additions & 2 deletions lib/rbbcode/node_extensions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,46 @@ def img_to_markdown
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
unsupported_tag
end

def color_to_markdown
unsupported_tag
end

def unsupported_tag
if RbbCode.options.fetch(:unsupported_features) == :remove
text.text_value
elsif RbbCode.options.fetch(:unsupported_features) == :span
'<span class="' + color_name.text_value + '">' + text.text_value + '</span>'
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
unsupported_tag
end

def size_to_markdown
unsupported_tag
end

def unsupported_tag
if RbbCode.options.fetch(:unsupported_features) == :remove
text.text_value
elsif RbbCode.options.fetch(:unsupported_features) == :span
'<span class="size' + size_value.text_value + '">' + text.text_value + '</span>'
end
end
end

module UTagNode
def u_to_markdown
# Underlining is unsupported in Markdown. So we just ignore [u] tags.
Expand All @@ -198,8 +238,24 @@ module TagNode
# 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
Expand Down
16 changes: 14 additions & 2 deletions lib/rbbcode/rbbcode_grammar.treetop
Original file line number Diff line number Diff line change
Expand Up @@ -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)
<RbbCode::TagNode>
end

Expand All @@ -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]' .)+
Expand Down
38 changes: 38 additions & 0 deletions test/unsupported_features_test.rb
Original file line number Diff line number Diff line change
@@ -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(
'<p>Not colored or resized but <strong>bold.</strong></p>',
'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(
'<p>Not colored or resized but <strong>bold.</strong></p>',
'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 <span class=\"red\">colored</span> or <span class=\"size3\">resized</span> 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