11class Markdowner
22 # opts[:allow_images] allows <img> tags
33
4+ COMMONMARKER_OPTIONS = {
5+ parse : { smart : true } ,
6+ render : { unsafe : true } ,
7+ extension : { tagfilter : true , autolink : true , strikethrough : true }
8+ } . freeze
9+
410 def self . to_html ( text , opts = { } )
511 if text . blank?
612 return ""
713 end
814
9- exts = [ :tagfilter , :autolink , :strikethrough ]
10- root = CommonMarker . render_doc ( text . to_s , [ :SMART ] , exts )
15+ # Preprocess @mentions before markdown parsing
16+ processed_text = preprocess_mentions ( text . to_s )
1117
12- walk_text_nodes ( root ) { | n | postprocess_text_node ( n ) }
18+ html = Commonmarker . to_html ( processed_text , options : COMMONMARKER_OPTIONS )
1319
14- ng = Nokogiri ::HTML ( root . to_html ( [ :DEFAULT ] , exts ) )
20+ ng = Nokogiri ::HTML ( html )
1521
1622 # change <h1>, <h2>, etc. headings to just bold tags
1723 ng . css ( "h1, h2, h3, h4, h5, h6" ) . each do |h |
@@ -33,44 +39,13 @@ def self.to_html(text, opts = {})
3339 end
3440 end
3541
36- def self . walk_text_nodes ( node , &block )
37- return if node . type == :link
38- return block . call ( node ) if node . type == :text
39-
40- node . each do |child |
41- walk_text_nodes ( child , &block )
42- end
43- end
44-
45- def self . postprocess_text_node ( node )
46- while node
47- return unless node . string_content =~ /\B (@#{ User ::VALID_USERNAME } )/
48- before , user , after = $`, $1, $'
49-
50- node . string_content = before
51-
52- if User . exists? ( :username => user [ 1 ..-1 ] )
53- link = CommonMarker ::Node . new ( :link )
54- link . url = Rails . application . root_url + "u/#{ user [ 1 ..-1 ] } "
55- node . insert_after ( link )
56-
57- link_text = CommonMarker ::Node . new ( :text )
58- link_text . string_content = user
59- link . append_child ( link_text )
60-
61- node = link
62- else
63- node . string_content += user
64- end
65-
66- if after . length > 0
67- remainder = CommonMarker ::Node . new ( :text )
68- remainder . string_content = after
69- node . insert_after ( remainder )
70-
71- node = remainder
42+ def self . preprocess_mentions ( text )
43+ text . gsub ( /\B (@#{ User ::VALID_USERNAME } )/ ) do |match |
44+ user = match [ 1 ..-1 ]
45+ if User . exists? ( username : user )
46+ "[#{ match } ](#{ Rails . application . root_url } u/#{ user } )"
7247 else
73- node = nil
48+ match
7449 end
7550 end
7651 end
0 commit comments