# -*- coding: utf-8 -*-
#
#--
# This file is part of based on kramdown.Confluence convertor
#
# kramdown is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#++
#
require 'rexml/parsers/baseparser'
module Kramdown
module Converter
# Converts a Kramdown::Document to Confluence ML
#
# You can customize the Confluence converter by sub-classing it and overriding the +convert_NAME+
# methods. Each such method takes the following parameters:
#
# [+el+] The element of type +NAME+ to be converted.
#
# [+indent+] 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
# Confluence element.
class Confluence < Base
# The amount of indentation used when nesting Confluence tags.
attr_accessor :indent
# Initialize the Confluence converter with the given Kramdown document +doc+.
def initialize(root, options)
super
@indent = 2
@stack = []
@table_header = false
end
# The mapping of element type to conversion method.
DISPATCHER = Hash.new {|h,k| h[k] = "convert_#{k}"}
# Dispatch the conversion of the element +el+ to a +convert_TYPE+ method using the +type+ of
# the element.
def convert(el, indent = -@indent)
send(DISPATCHER[el.type], el, indent)
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.
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
def convert_blank(el, indent)
"\n"
end
def convert_text(el, indent)
el.value
end
def convert_p(el, indent)
"#{' '*indent}#{inner(el, indent)}\n"
end
def convert_blockquote(el, indent)
"#{' '*indent}bq. #{inner(el, indent)}\n"
end
def convert_header(el, indent)
"h#{el.options[:level]}. #{inner(el, indent)}\n"
end
def convert_hr(el, indent)
"#{' '*indent}----\n"
end
def convert_ul(el, indent)
inner(el,indent)
end
alias :convert_ol :convert_ul
alias :convert_dl :convert_ul
def convert_li(el, indent)
"#{'-'*(indent/2)}#{inner(el, 0)}"
end
alias :convert_dd :convert_li
def convert_dt(el, indent)
inner(el, indent)
end
def convert_html_element(el, indent)
markup=case el.value
when "iframe" then "{iframe:src=#{el.attr["src"]}}"
when "pre" then
if inner(el,indent).strip.match(/\n/)
"{code}#{inner(el,indent)}{code}"
else
"{{#{inner(el,indent).strip}}}"
end
else inner(el, indent)
end
end
def convert_xml_comment(el, indent)
""
end
alias :convert_xml_pi :convert_xml_comment
def convert_table(el, indent)
"#{inner(el, indent)}"
end
def convert_thead(el, indent)
@table_header = true
"#{inner(el, indent)}"
end
def convert_tbody(el, indent)
@table_header = false
"#{inner(el, indent)}"
end
alias :convert_tfoot :convert_tbody
def convert_tr(el, indent)
if @table_header
"||#{inner(el, indent)}\n"
else
"|#{inner(el, indent)}\n"
end
end
def convert_td(el, indent)
if @table_header
" #{inner(el, indent)} ||"
else
" #{inner(el, indent)} |"
end
end
def convert_empty(el, indent)
""
end
def convert_comment(el, indent)
inner(el, indent)
end
def convert_br(el, indent)
"\\"
end
def convert_a(el, indent)
text = inner(el,indent)
link = el.attr['href']
"[#{text+'|' unless text.nil?}#{link}]"
end
def convert_img(el, indent)
src = el.attr['src']
alt = el.attr['alt']
alt.to_s.empty? ? "!#{src}!" : "!#{src}|alt=#{alt}!"
end
def convert_codeblock(el, indent)
"{code}#{el.value}{code}\n"
end
def convert_codespan(el, indent)
if el.value.strip.match(/\n/)
"{code}#{el.value}{code}\n"
else
"{{#{el.value.strip}}}"
end
end
def convert_footnote(el, indent)
inner(el, indent)
end
def convert_raw(el, indent)
inner(el, indent)
end
def convert_em(el, indent)
"_#{inner(el, indent)}_"
end
def convert_strong(el, indent)
"*#{inner(el, indent)}*"
end
def convert_entity(el, indent)
inner(el,indent)
end
def convert_typographic_sym(el, indent)
inner(el,indent)
end
def convert_smart_quote(el, indent)
"'"
end
def convert_math(el, indent)
inner(el,indent)
end
def convert_abbreviation(el, indent)
inner(el,indent)
end
def convert_root(el, indent)
handle_iframes(inner(el, indent))
end
def handle_iframes(text)
markup=text.gsub(//) { |match|
doc =Nokogiri::HTML::DocumentFragment.parse(match)
element=doc.search('iframe').first
attributes=element.attributes.map{ |at| "#{at[1].name}=#{at[1].value}"}
"{iframe:#{attributes.join('|')}}#{element.text}{iframe}"
}
return markup
end
end
end
end