让文章编辑支持Markdown

现在很多写作者已经离不开 markdown 了,因此很多发文章的编辑器都需要支持。

如果要在 rails 的 webapp 里实现 markdown 支持,大概思路是,用户写文章的时候,用 markdown 格式输入,比如

# h1
## h2
some stuff
...

在文章显示的时候,将这些 markdown 格式解析成 HTML 格式来显示。这个解析的功能,一般可以用 redcarpet 这个gem。

添加 gemfile

gem 'redcarpet'

创建 renderer 类及方法

一般可以放在 /lib 目录下,比如创建一个 markdown_render.rb

class MarkdownRenderer < Redcarpet::Render::HTML
  def self.render(text)
    options = {
      filter_html: false,
      hard_wrap: true,
      link_attributes: { rel: 'nofollow', target: '_blank' },
      space_after_headers: true,
      fenced_code_blocks: true,
      with_toc_data: true
      # 各项设置见 gem 说明
    }

    extensions = {
      autolink: true,
      superscript: true,
      disable_indented_code_blocks: true
      # 各项设置见 gem 说明
    }

    renderer = new(options)
    markdown = Redcarpet::Markdown.new(renderer, extensions)
    markdown.render(text)
  end
end

创建 helper 方法

为了使用方便,还可以在 application_helper.rb 里创建解析文本的 helper

  def markdown_article(text)
    tag.article class: 'markdown-article' do
      MarkdownRenderer.render(text || '').html_safe
    end
  end

在 view 中使用 helper 时,比如说文章内容存在 @post.content ,那么

<% markdown_article(@post.content) %>

根据前面写的 helper,文章的内容会包在一个 <article> 的 tag 里,带有一个 markdown-article 的 class。这样就方便我们对文章的样式进行调整。

<article class="markdown-article">
  // 解析成 HTML 后的文章内容
</article>

生成文章目录

redcarpet 的说明中有介绍,还可以用来生成文章的目录,用的是 Redcarpet::Render::HTML_TOC 这个类。

使用方法类似,先创建一个 render 的类,同样可以放在 /lib 目录下

class MarkdownTocRenderer < Redcarpet::Render::HTML_TOC
  def self.render(text)
    options = {}
    extensions = { with_toc_data: true }
    renderer = new(options)
    markdown = Redcarpet::Markdown.new(renderer, extensions)
    markdown.render(text)
  end
end

application_helper.rb 里定义个 helper

def markdown_toc(text)
  tag.div class: 'markdown-toc' do
    MarkdownTocRenderer.render(text || '').html_safe
  end
end

解析后的效果是

<div class="markdown-toc">
  <ul>
    <li>
      <a href="#h1-id">h1-xxxx</a>
    </li>
    <li>
      <a href="#h2-id">h2-xxxx</a>
    </li>
    // ...
  </ul>
</div>

生成出来的效果很难看,重新添加一些 style 就可以了。

这里有一个需要注意的地方,生成出来的目录里带的超链接,要定位到各个标题位置,其实就是链接到本页的一个 id,那么文章中必须带有相应的标签才行。所以在解析文章内容时一定要带上 with_toc_data: true 这个参数设置。

· rails, markdown, gem