Base
Converts a Kramdown::Document to HTML.
You can customize the HTML converter by sub-classing it and overriding the convert_NAME methods. Each such method takes the following parameters:
The element of type NAME to be converted.
A number representing the current amount of spaces for indent (only used for block-level elements).
The return value of such a method has to be a string containing the element el formatted as HTML element.
The mapping of element type to conversion method.
Highlighting via coderay is available if this constant is true.
Initialize the HTML converter with the given Kramdown document doc.
# File lib/kramdown/converter/html.rb, line 59 def initialize(root, options) super @footnote_counter = @footnote_start = @options[:footnote_nr] @footnotes = [] @toc = [] @toc_code = nil @indent = 2 @stack = [] @coderay_enabled = @options[:enable_coderay] && HIGHLIGHTING_AVAILABLE end
Dispatch the conversion of the element el to a convert_TYPE method using the type of the element.
# File lib/kramdown/converter/html.rb, line 75 def convert(el, indent = -@indent) send(DISPATCHER[el.type], el, indent) end
# File lib/kramdown/converter/html.rb, line 256 def convert_a(el, indent) res = inner(el, indent) attr = el.attr.dup if attr['href'] =~ /^mailto:/ mail_addr = attr['href'].sub(/^mailto:/, '') attr['href'] = obfuscate('mailto') << ":" << obfuscate(mail_addr) res = obfuscate(res) if res == mail_addr end "<a#{html_attributes(attr)}>#{res}</a>" end
# File lib/kramdown/converter/html.rb, line 328 def convert_abbreviation(el, indent) title = @root.options[:abbrev_defs][el.value] "<abbr#{!title.empty? ? html_attributes(:title => title) : ''}>#{el.value}</abbr>" end
# File lib/kramdown/converter/html.rb, line 95 def convert_blank(el, indent) "\n" end
# File lib/kramdown/converter/html.rb, line 141 def convert_blockquote(el, indent) "#{' '*indent}<blockquote#{html_attributes(el.attr)}>\n#{inner(el, indent)}#{' '*indent}</blockquote>\n" end
# File lib/kramdown/converter/html.rb, line 252 def convert_br(el, indent) "<br />" end
# File lib/kramdown/converter/html.rb, line 111 def convert_codeblock(el, indent) attr = el.attr.dup lang = extract_code_language!(attr) if @coderay_enabled && (lang || @options[:coderay_default_lang]) opts = {:wrap => @options[:coderay_wrap], :line_numbers => @options[:coderay_line_numbers], :line_number_start => @options[:coderay_line_number_start], :tab_width => @options[:coderay_tab_width], :bold_every => @options[:coderay_bold_every], :css => @options[:coderay_css]} lang = (lang || @options[:coderay_default_lang]).to_sym result = CodeRay.scan(el.value, lang).html(opts).chomp << "\n" "#{' '*indent}<div#{html_attributes(attr)}>#{result}#{' '*indent}</div>\n" else result = escape_html(el.value) result.chomp! if el.attr['class'].to_s =~ /\bshow-whitespaces\b/ result.gsub!(/(?:(^[ \t]+)|([ \t]+$)|([ \t]+))/) do |m| suffix = ($1 ? '-l' : ($2 ? '-r' : '')) m.scan(/./).map do |c| case c when "\t" then "<span class=\"ws-tab#{suffix}\">\t</span>" when " " then "<span class=\"ws-space#{suffix}\">⋅</span>" end end.join('') end end code_attr = {} code_attr['class'] = "language-#{lang}" if lang "#{' '*indent}<pre#{html_attributes(attr)}><code#{html_attributes(code_attr)}>#{result}\n</code></pre>\n" end end
# File lib/kramdown/converter/html.rb, line 271 def convert_codespan(el, indent) lang = extract_code_language(el.attr) if @coderay_enabled && lang result = CodeRay.scan(el.value, lang.to_sym).html(:wrap => :span, :css => @options[:coderay_css]).chomp "<code#{html_attributes(el.attr)}>#{result}</code>" else "<code#{html_attributes(el.attr)}>#{escape_html(el.value)}</code>" end end
# File lib/kramdown/converter/html.rb, line 244 def convert_comment(el, indent) if el.options[:category] == :block "#{' '*indent}<!-- #{el.value} -->\n" else "<!-- #{el.value} -->" end end
# File lib/kramdown/converter/html.rb, line 182 def convert_dt(el, indent) "#{' '*indent}<dt#{html_attributes(el.attr)}>#{inner(el, indent)}</dt>\n" end
# File lib/kramdown/converter/html.rb, line 296 def convert_em(el, indent) "<#{el.type}#{html_attributes(el.attr)}>#{inner(el, indent)}</#{el.type}>" end
# File lib/kramdown/converter/html.rb, line 301 def convert_entity(el, indent) entity_to_str(el.value, el.options[:original]) end
# File lib/kramdown/converter/html.rb, line 281 def convert_footnote(el, indent) number = @footnote_counter @footnote_counter += 1 @footnotes << [el.options[:name], el.value] "<sup id=\"fnref:#{el.options[:name]}\"><a href=\"#fn:#{el.options[:name]}\" rel=\"footnote\">#{number}</a></sup>" end
# File lib/kramdown/converter/html.rb, line 145 def convert_header(el, indent) attr = el.attr.dup if @options[:auto_ids] && !attr['id'] attr['id'] = generate_id(el.options[:raw_text]) end @toc << [el.options[:level], attr['id'], el.children] if attr['id'] && in_toc?(el) level = output_header_level(el.options[:level]) "#{' '*indent}<h#{level}#{html_attributes(attr)}>#{inner(el, indent)}</h#{level}>\n" end
# File lib/kramdown/converter/html.rb, line 155 def convert_hr(el, indent) "#{' '*indent}<hr />\n" end
# File lib/kramdown/converter/html.rb, line 186 def convert_html_element(el, indent) res = inner(el, indent) if el.options[:category] == :span "<#{el.value}#{html_attributes(el.attr)}" << (res.empty? && HTML_ELEMENTS_WITHOUT_BODY.include?(el.value) ? " />" : ">#{res}</#{el.value}>") else output = '' output << ' '*indent if @stack.last.type != :html_element || @stack.last.options[:content_model] != :raw output << "<#{el.value}#{html_attributes(el.attr)}" if el.options[:is_closed] && el.options[:content_model] == :raw output << " />" elsif !res.empty? && el.options[:content_model] != :block output << ">#{res}</#{el.value}>" elsif !res.empty? output << ">\n#{res.chomp}\n" << ' '*indent << "</#{el.value}>" elsif HTML_ELEMENTS_WITHOUT_BODY.include?(el.value) output << " />" else output << "></#{el.value}>" end output << "\n" if @stack.last.type != :html_element || @stack.last.options[:content_model] != :raw output end end
# File lib/kramdown/converter/html.rb, line 267 def convert_img(el, indent) "<img#{html_attributes(el.attr)} />" end
# File lib/kramdown/converter/html.rb, line 170 def convert_li(el, indent) output = ' '*indent << "<#{el.type}" << html_attributes(el.attr) << ">" res = inner(el, indent) if el.children.empty? || (el.children.first.type == :p && el.children.first.options[:transparent]) output << res << (res =~ /\n\Z/ ? ' '*indent : '') else output << "\n" << res << ' '*indent end output << "</#{el.type}>\n" end
# File lib/kramdown/converter/html.rb, line 322 def convert_math(el, indent) block = (el.options[:category] == :block) value = (el.value =~ /<|&/ ? "% <![CDATA[\n#{el.value} %]]>" : el.value) "<script type=\"math/tex#{block ? '; mode=display' : ''}\">#{value}</script>#{block ? "\n" : ''}" end
# File lib/kramdown/converter/html.rb, line 103 def convert_p(el, indent) if el.options[:transparent] inner(el, indent) else "#{' '*indent}<p#{html_attributes(el.attr)}>#{inner(el, indent)}</p>\n" end end
# File lib/kramdown/converter/html.rb, line 288 def convert_raw(el, indent) if !el.options[:type] || el.options[:type].empty? || el.options[:type].include?('html') el.value + (el.options[:category] == :block ? "\n" : '') else '' end end
# File lib/kramdown/converter/html.rb, line 333 def convert_root(el, indent) result = inner(el, indent) result << footnote_content if @toc_code toc_tree = generate_toc_tree(@toc, @toc_code[0], @toc_code[1] || {}) text = if toc_tree.children.size > 0 convert(toc_tree, 0) else '' end result.sub!(/#{@toc_code.last}/, text) end result end
# File lib/kramdown/converter/html.rb, line 318 def convert_smart_quote(el, indent) entity_to_str(smart_quote_entity(el)) end
# File lib/kramdown/converter/html.rb, line 219 def convert_table(el, indent) "#{' '*indent}<table#{html_attributes(el.attr)}>\n#{inner(el, indent)}#{' '*indent}</table>\n" end
# File lib/kramdown/converter/html.rb, line 232 def convert_td(el, indent) res = inner(el, indent) type = (@stack[-2].type == :thead ? :th : :td) attr = el.attr alignment = @stack[-3].options[:alignment][@stack.last.children.index(el)] if alignment != :default attr = el.attr.dup attr['style'] = (attr.has_key?('style') ? "#{attr['style']}; ": '') << "text-align: #{alignment}" end "#{' '*indent}<#{type}#{html_attributes(attr)}>#{res.empty? ? entity_to_str(ENTITY_NBSP) : res}</#{type}>\n" end
# File lib/kramdown/converter/html.rb, line 99 def convert_text(el, indent) escape_html(el.value, :text) end
# File lib/kramdown/converter/html.rb, line 223 def convert_thead(el, indent) "#{' '*indent}<#{el.type}#{html_attributes(el.attr)}>\n#{inner(el, indent)}#{' '*indent}</#{el.type}>\n" end
# File lib/kramdown/converter/html.rb, line 314 def convert_typographic_sym(el, indent) TYPOGRAPHIC_SYMS[el.value].map {|e| entity_to_str(e)}.join('') end
# File lib/kramdown/converter/html.rb, line 159 def convert_ul(el, indent) if !@toc_code && (el.options[:ial][:refs].include?('toc') rescue nil) && (el.type == :ul || el.type == :ol) @toc_code = [el.type, el.attr, (0..128).to_a.map{|a| rand(36).to_s(36)}.join] @toc_code.last else "#{' '*indent}<#{el.type}#{html_attributes(el.attr)}>\n#{inner(el, indent)}#{' '*indent}</#{el.type}>\n" end end
# File lib/kramdown/converter/html.rb, line 210 def convert_xml_comment(el, indent) if el.options[:category] == :block && (@stack.last.type != :html_element || @stack.last.options[:content_model] != :raw) ' '*indent << el.value << "\n" else el.value end end
Return a HTML ordered list with the footnote content for the used footnotes.
# File lib/kramdown/converter/html.rb, line 403 def footnote_content ol = Element.new(:ol) ol.attr['start'] = @footnote_start if @footnote_start != 1 @footnotes.each do |name, data| li = Element.new(:li, nil, {'id' => "fn:#{name}"}) li.children = Marshal.load(Marshal.dump(data.children)) ol.children << li ref = Element.new(:raw, "<a href=\"#fnref:#{name}\" rel=\"reference\">↩</a>") if li.children.last.type == :p para = li.children.last else li.children << (para = Element.new(:p)) end para.children << ref end (ol.children.empty? ? '' : "<div class=\"footnotes\">\n#{convert(ol, 2)}</div>\n") end
Generate and return an element tree for the table of contents.
# File lib/kramdown/converter/html.rb, line 349 def generate_toc_tree(toc, type, attr) sections = Element.new(type, nil, attr) sections.attr['id'] ||= 'markdown-toc' stack = [] toc.each do |level, id, children| li = Element.new(:li, nil, nil, {:level => level}) li.children << Element.new(:p, nil, nil, {:transparent => true}) a = Element.new(:a, nil, {'href' => "##{id}"}) a.children.concat(remove_footnotes(Marshal.load(Marshal.dump(children)))) li.children.last.children << a li.children << Element.new(type) success = false while !success if stack.empty? sections.children << li stack << li success = true elsif stack.last.options[:level] < li.options[:level] stack.last.children.last.children << li stack << li success = true else item = stack.pop item.children.pop unless item.children.last.children.size > 0 end end end while !stack.empty? item = stack.pop item.children.pop unless item.children.last.children.size > 0 end sections end
Return the converted content of the children of el as a string. The parameter indent has to be the amount of indentation used for the element el.
Pushes el onto the @stack before converting the child elements and pops it from the stack afterwards.
# File lib/kramdown/converter/html.rb, line 84 def inner(el, indent) result = '' indent += @indent @stack.push(el) el.children.each do |inner_el| result << send(DISPATCHER[inner_el.type], inner_el, indent) end @stack.pop result end
Obfuscate the text by using HTML entities.
# File lib/kramdown/converter/html.rb, line 393 def obfuscate(text) result = "" text.each_byte do |b| result << (b > 128 ? b.chr : "&#%03d;" % b) end result.force_encoding(text.encoding) if result.respond_to?(:force_encoding) result end
Generated with the Darkfish Rdoc Generator 2.