Is there a way to use either Redcarpet or Bluecloth such that when it interpolates the markdown it won't make any headers?
For example:
#header 1
yields:
header 1
header 1 (preferred)
And:
##header 2
yields:
header 2
header 2 (preferred)
Is there a way to use either Redcarpet or Bluecloth such that when it interpolates the markdown it won't make any headers?
For example:
#header 1
yields:
header 1
header 1 (preferred)
And:
##header 2
yields:
header 2
header 2 (preferred)
Well, you can escape characters in Markdown:
# header 1
\# header 1
## header 2
\## header 2
...gives:
header 1
# header 1
header 2
## header 2
If you don't want to have to do this, or you're parsing other people's Markdown and don't have a choice, I would recommend pre-processing the incoming Markdown to do the above for you:
def pound_filter text
text.gsub /^#/, '\#'
end
Using Redcarpet you can verify that it works:
text = <<-END
# Hello
## World
END
Markdown.new(text.to_html)
# => <h1>Hello</h1>
#
# <h2>World</h2>
Markdown.new(pound_filter text).to_html
# => <p># Hello
# ## World</p>
Of course since a line break in HTML doesn't actually render as such--it will appear as one line:
# Hello ## World"
...you might want to augment that:
def pound_filter text
text.gsub( /((\A^)|([^\A]^))#/ ) {|match| "\n" == match[0] ? "\n\n\\#" : '\#' }
end
pound_filter text
# => \# Hello
#
# \## World
Markdown.new(pound_filter text).to_html
# => <p>\# Hello</p>
#
# <p>\## World</p>
This last would appear as:
# Hello
## World
Unfortunately you eventually get into weird territory like this, where a heading is inside a quote:
> ## Heading
...but I leave that as an exercise to the reader.
Saw a similar solution here that went like this:
class RenderWithoutWrap < Redcarpet::Render::HTML
def postprocess(full_document)
Regexp.new(/\A<p>(.*)<\/p>\Z/m).match(full_document)[1] rescue full_document
end
end
It removes all <p> & </p> tags. I used it like that and it worked. I placed that class in a new file called /config/initializers/render_without_wrap.rb. You could do something similar for all <h1>-<h6> tags
class RenderWithoutHeaders < Redcarpet::Render::HTML
def postprocess(full_document)
Regexp.new(/\A<h1>(.*)<\/h1>\Z/m).match(full_document)[1] rescue full_document
Regexp.new(/\A<h2>(.*)<\/h2>\Z/m).match(full_document)[1] rescue full_document
Regexp.new(/\A<h3>(.*)<\/h3>\Z/m).match(full_document)[1] rescue full_document
...(you get the idea)
end
end
You could then use it like this
def custom_markdown_parse(text)
markdown = Redcarpet::Markdown.new(RenderWithoutHeaders.new(
filter_html: true,
hard_wrap: true,
other_options: its_your_call
))
markdown.render(text).html_safe
end
I haven't tested it, but it's an idea.
tags might. Also, this doesn't work if there are multiple h2s or multiple h3s. Any idea how to make the regex work in that case?
– DelPiero Dec 18 '15 at 21:28\# not a header
module RedCloth::Formatters::HTML
[:h1, :h2, :h3, :h4, :h5, :h6].each do |m|
define_method(m) do |opts|
"#{opts[:text]}\n"
end
end
end
Given that twiddling the Markdown pre-parsing is hard, and Markdown allows inserted HTML, how about stripping out heading elements from the resulting HTML instead?