aboutsummaryrefslogtreecommitdiffstats
path: root/guides/rails_guides/markdown.rb
blob: 12eabcbcc8186b1b87c87983ffc62bcb4a4d6c14 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
require 'redcarpet'
require 'nokogiri'
require 'rails_guides/markdown/renderer'

module RailsGuides
  class Markdown
    def initialize(view, layout)
      @view = view
      @layout = layout
      @index_counter = Hash.new(0)
    end

    def render(body)
      @raw_header, _, @raw_body = body.partition(/^\-{40,}$/).map(&:strip)
      generate_header
      generate_title
      generate_body
      generate_structure
      generate_index
      render_page
    end

    private

      def dom_id(nodes)
        nodes.map{ |node| node.text.downcase.gsub(/[^a-z0-9]+/, '-') }.join('-')
      end

      def engine
        @engine ||= Redcarpet::Markdown.new(Renderer, {
          no_intra_emphasis: true,
          fenced_code_blocks: true,
          autolink: true,
          strikethrough: true,
          superscript: true
        })
      end

      def generate_body
        @body = engine.render(@raw_body)
      end

      def generate_header
        @header = engine.render(@raw_header).html_safe
      end

      def generate_structure
        @raw_index = ''
        @body = Nokogiri::HTML(@body).tap do |doc|
          hierarchy = []

          doc.at('body').children.each do |node|
            if node.name =~ /^h[3-6]$/
              case node.name
              when 'h3'
                hierarchy = [node]
                node[:id] = dom_id(hierarchy)
                @raw_index += "1. [#{node.text}](##{node[:id]})\n"
              when 'h4'
                hierarchy = hierarchy[0, 1] + [node]
                node[:id] = dom_id(hierarchy)
                @raw_index += "    * [#{node.text}](##{node[:id]})\n"
              when 'h5'
                hierarchy = hierarchy[0, 2] + [node]
                node[:id] = dom_id(hierarchy)
              when 'h6'
                hierarchy = hierarchy[0, 3] + [node]
                node[:id] = dom_id(hierarchy)
              end

              node.inner_html = "#{node_index(hierarchy)} #{node.text}"
            end
          end
        end.to_html
      end

      def generate_index
        @index = Nokogiri::HTML(engine.render(@raw_index)).tap do |doc|
          doc.at('ol')[:class] = 'chapters'
        end.to_html

        @index = <<-INDEX.html_safe
        <div id="subCol">
          <h3 class="chapter"><img src="images/chapters_icon.gif" alt="" />Chapters</h3>
          #{@index}
        </div>
        INDEX
      end

      def generate_title
        @title = "Ruby on Rails Guides: #{Nokogiri::HTML(@header).at(:h2).text}".html_safe
      end

      def node_index(hierarchy)
        case hierarchy.size
        when 1
          @index_counter[2] = @index_counter[3] = @index_counter[4] = 0
          "#{@index_counter[1] += 1}"
        when 2
          @index_counter[3] = @index_counter[4] = 0
          "#{@index_counter[1]}.#{@index_counter[2] += 1}"
        when 3
          @index_counter[4] = 0
          "#{@index_counter[1]}.#{@index_counter[2]}.#{@index_counter[3] += 1}"
        when 4
          "#{@index_counter[1]}.#{@index_counter[2]}.#{@index_counter[3]}.#{@index_counter[4] += 1}"
        end
      end

      def render_page
        @view.content_for(:header_section) { @header }
        @view.content_for(:page_title) { @title }
        @view.content_for(:index_section) { @index.html_safe }
        @view.render(:layout => @layout, :text => @body)
      end
  end
end