1
# encoding: utf-8
2
#--
3
#   Copyright (C) 2009 Johan Sørensen
4
#
5
#   This program is free software: you can redistribute it and/or modify
6
#   it under the terms of the GNU Affero General Public License as published by
7
#   the Free Software Foundation, either version 3 of the License, or
8
#   (at your option) any later version.
9
#
10
#   This program is distributed in the hope that it will be useful,
11
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
12
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
#   GNU Affero General Public License for more details.
14
#
15
#   You should have received a copy of the GNU Affero General Public License
16
#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
#++
18
19
require "zlib"
20
21
class MarkupRenderer
22
  class NotProcessedYetError < StandardError; end
23
  
24
  WRAPPER_NAME = "markdown-wrapper".freeze
25
  PRE_TAG_EXTRATION_KEY = "gts-markup-renderer".freeze
26
  
27
  def initialize(content, options = {})
28
    @content = content.to_s
29
    @options = options
30
    @options[:markdown] ||= [:smart]
31
    @markdown = nil
32
  end
33
34
  def markdown
35
    raise NotProcessedYetError unless @markdown
36
    @markdown
37
  end
38
39
  def to_html
40
    pre_process
41
    @markdown = RDiscount.new(@content, *@options[:markdown])
42
    post_process(@markdown.to_html)
43
  end
44
45
  def pre_process
46
    # Extract <pre> tags
47
    pre_tag_content = {}
48
    @content.gsub!(/(<pre>.*?<\/pre>)/im) do |pre|
49
      crc = Zlib.crc32(pre)
50
      pre_tag_content[crc] = pre
51
      "$#{PRE_TAG_EXTRATION_KEY}-#{crc}$"
52
    end
53
54
    # Convert windows lineendings
55
    @content.gsub!(/\r\n?/, "\n")
56
    
57
    # Convert any single newlines to space-space-newline
58
    # so markdown will break them
59
    @content.gsub!(/([^\n]\n)(?=[^\n])/) do |m|
60
      m.gsub!(/^(.+)$/, '\1  ')
61
    end
62
63
    # re-insert the extracted <pre> tag content
64
    @content.gsub!(/\$#{PRE_TAG_EXTRATION_KEY}-(\d+)\$/) do
65
      pre_tag_content[$1.to_i]
66
    end
67
68
    @content
69
  end
70
71
  def post_process(text)
72
    if @options[:wrapper].blank?
73
      text
74
    else
75
      if @options[:wrapper] == true
76
        "<div class=\"#{WRAPPER_NAME}\">\n#{text}</div>\n"
77
      else
78
        "<div class=\"#{@options[:wrapper]} #{WRAPPER_NAME}\">\n#{text}</div>\n"
79
      end
80
    end
81
  end
82
end