journalduhacker/extras/markdowner.rb
joshua stein a812f25c2f Markdowner: use Nokogiri for html rewriting
brute forcing changes by regexps gets things wrong sometimes, so use
nokogiri to parse the html output of rdiscount and do changes on
individual nodes, then turn back into a string

we lose the ability to move punctuation inside of auto-generated
links, but i don't see any easy/definitive way to do this properly.

closes #242
closes #209
2015-12-07 12:27:03 -06:00

51 lines
1.2 KiB
Ruby

class Markdowner
# opts[:allow_images] allows <img> tags
# opts[:disable_profile_links] disables @username -> /u/username links
def self.to_html(text, opts = {})
if text.blank?
return ""
end
args = [ :smart, :autolink, :safelink, :filter_styles, :filter_html,
:strict ]
if !opts[:allow_images]
args.push :no_image
end
ng = Nokogiri::HTML(RDiscount.new(text.to_s, *args).to_html)
# change <h1>, <h2>, etc. headings to just bold tags
ng.css("h1, h2, h3, h4, h5, h6").each do |h|
h.name = "strong"
end
# make links have rel=nofollow
ng.css("a").each do |h|
h[:rel] = "nofollow"
end
unless opts[:disable_profile_links]
# make @username link to that user's profile
ng.search("//text()").each do |t|
if t.parent && t.parent.name.downcase == "a"
# don't replace inside <a>s
next
end
tx = t.text.gsub(/\B\@([\w\-]+)/) do |u|
if User.exists?(:username => u[1 .. -1])
"<a href=\"/u/#{u[1 .. -1]}\">#{u}</a>"
else
u
end
end
t.replace(tx)
end
end
ng.at_css("body").inner_html
end
end