Render Single-Line Markdown Text with Redcarpet
We love Markdown. We use it wherever we can for text formatting. In a web app, the obvious place for it is in large text areas, where we can allow complete freedom of formatting. Headers, paragraphs, lists, it’s all good.
What about the formatting of text in single-line text fields? If our form entry is a single line, that’s usually how its text will be displayed in our interface. In this case, we probably want to avoid all the block-level elements that Markdown will let the user create.
This is easy to do using Redcarpet, a fantastic Markdown renderer for Ruby. It is fast and, importantly, it is modular: it allows us to define our own custom renderers. We can use this to create a renderer that ignores all the block-level Markdown elements. Put this somewhere in your Rails app (e.g., lib/redcarpet_renderers.rb
):
module Redcarpet
module Render
class HTMLWithoutBlockElements < HTML
include SmartyPants
def initialize(opts = {})
opts[:tables] = false
super(opts)
end
# Regular markdown, just ignore all the block-level elements
def block_code(code, language)
code
end
def block_quote(quote)
quote
end
def block_html(raw_html)
raw_html
end
def header(text, header_level)
"#{text} "
end
def hrule
" "
end
def list(contents, list_type)
" #{contents}"
end
def list_item(text, list_type)
"* #{text}"
end
def paragraph(text)
text
end
# Span-level calls
def linebreak
" "
end
# Postprocessing: strip the newlines
def postprocess(document)
document.gsub("\\n", ' ').strip
end
end
end
end
Now we can safely render the content from our single-line text fields using markdown. The user can still make things _emphasised_ or **bold** or even [linked](http://icelab.com.au/) and we don’t have to worry about unwanted block elements messing up our page layouts.
To use this renderer, just throw something like the following into your app/helpers/application_helper.rb
file:
module ApplicationHelper
def markdown(text)
renderer = Redcarpet::Render::HTML.new({
:filter_html => true,
:hard_wrap => true
})
markdown = Redcarpet::Markdown.new(renderer, {
:autolink => true,
:no_intra_emphasis => true
})
markdown.render(text).html_safe
end
def markdown_line(text)
renderer = Redcarpet::Render::HTMLWithoutBlockElements.new({
:filter_html => true,
:hard_wrap => true
})
markdown = Redcarpet::Markdown.new(renderer, {
:autolink => true,
:no_intra_emphasis => true
})
markdown.render(text).html_safe
end
end
And it’s now a helper ready for use in our page templates. For example:
<div class="item">
<h3 class="name"><%= markdown_line(item.name) %></h3>
<div class="description">
<%= markdown(item.description) %>
</div>
</div>
The more Markdown we can use, the happier we are!