Class: Kramdown::Converter::Html
Overview
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:
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 HTML element.
Constant Summary
collapse
- DISPATCHER =
The mapping of element type to conversion method.
Hash.new {|h,k| h[k] = "convert_#{k}"}
- HTML_TAGS_WITH_BODY =
A list of all HTML tags that need to have a body (even if the body is empty).
['div', 'span', 'script', 'iframe', 'textarea', 'a']
- ENTITY_NBSP =
::Kramdown::Utils::Entities.entity('nbsp')
- TYPOGRAPHIC_SYMS =
{
:mdash => [::Kramdown::Utils::Entities.entity('mdash')],
:ndash => [::Kramdown::Utils::Entities.entity('ndash')],
:hellip => [::Kramdown::Utils::Entities.entity('hellip')],
:laquo_space => [::Kramdown::Utils::Entities.entity('laquo'), ::Kramdown::Utils::Entities.entity('nbsp')],
:raquo_space => [::Kramdown::Utils::Entities.entity('nbsp'), ::Kramdown::Utils::Entities.entity('raquo')],
:laquo => [::Kramdown::Utils::Entities.entity('laquo')],
:raquo => [::Kramdown::Utils::Entities.entity('raquo')]
}
Constants included
from Utils::Html
Utils::Html::ESCAPE_ALL_RE, Utils::Html::ESCAPE_ATTRIBUTE_RE, Utils::Html::ESCAPE_MAP, Utils::Html::ESCAPE_RE_FROM_TYPE, Utils::Html::ESCAPE_TEXT_RE
Constants inherited
from Base
Base::SMART_QUOTE_INDICES
Instance Attribute Summary collapse
Attributes inherited from Base
#data, #options, #root, #warnings
Instance Method Summary
collapse
-
#convert(el, indent = -@indent)) ⇒ Object
Dispatch the conversion of the element el
to a convert_TYPE
method using the type
of the element.
-
#convert_a(el, indent) ⇒ Object
-
#convert_abbreviation(el, indent) ⇒ Object
-
#convert_blank(el, indent) ⇒ Object
-
#convert_blockquote(el, indent) ⇒ Object
-
#convert_br(el, indent) ⇒ Object
-
#convert_codeblock(el, indent) ⇒ Object
-
#convert_codespan(el, indent) ⇒ Object
-
#convert_comment(el, indent) ⇒ Object
-
#convert_dt(el, indent) ⇒ Object
-
#convert_em(el, indent) ⇒ Object
(also: #convert_strong)
-
#convert_entity(el, indent) ⇒ Object
-
#convert_footnote(el, indent) ⇒ Object
-
#convert_header(el, indent) ⇒ Object
-
#convert_hr(el, indent) ⇒ Object
-
#convert_html_element(el, indent) ⇒ Object
-
#convert_img(el, indent) ⇒ Object
-
#convert_li(el, indent) ⇒ Object
(also: #convert_dd)
-
#convert_math(el, indent) ⇒ Object
-
#convert_p(el, indent) ⇒ Object
-
#convert_raw(el, indent) ⇒ Object
-
#convert_root(el, indent) ⇒ Object
-
#convert_smart_quote(el, indent) ⇒ Object
-
#convert_table(el, indent) ⇒ Object
-
#convert_td(el, indent) ⇒ Object
-
#convert_text(el, indent) ⇒ Object
-
#convert_thead(el, indent) ⇒ Object
(also: #convert_tbody, #convert_tfoot, #convert_tr)
-
#convert_typographic_sym(el, indent) ⇒ Object
-
#convert_ul(el, indent) ⇒ Object
(also: #convert_ol, #convert_dl)
-
#convert_xml_comment(el, indent) ⇒ Object
(also: #convert_xml_pi)
-
#footnote_content ⇒ Object
Return a HTML ordered list with the footnote content for the used footnotes.
-
#generate_toc_tree(toc, type, attr) ⇒ Object
Generate and return an element tree for the table of contents.
-
#initialize(root, options) ⇒ Html
constructor
Initialize the HTML converter with the given Kramdown document doc
.
-
#inner(el, indent) ⇒ Object
Return the converted content of the children of el
as a string.
-
#obfuscate(text) ⇒ Object
Obfuscate the text
by using HTML entities.
#entity_to_str, #escape_html, #html_attributes
Methods inherited from Base
apply_template, convert, #generate_id, get_template, #in_toc?, #smart_quote_entity, #warning
Constructor Details
#initialize(root, options) ⇒ Html
Initialize the HTML converter with the given Kramdown document doc
.
59
60
61
62
63
64
65
66
67
|
# 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 = []
end
|
Instance Attribute Details
#indent ⇒ Object
The amount of indentation used when nesting HTML tags.
56
57
58
|
# File 'lib/kramdown/converter/html.rb', line 56
def indent
@indent
end
|
Instance Method Details
#convert(el, indent = -@indent)) ⇒ Object
Dispatch the conversion of the element el
to a convert_TYPE
method using the type
of the element.
74
75
76
|
# File 'lib/kramdown/converter/html.rb', line 74
def convert(el, indent = -@indent)
send(DISPATCHER[el.type], el, indent)
end
|
#convert_a(el, indent) ⇒ Object
251
252
253
254
255
256
257
258
259
|
# File 'lib/kramdown/converter/html.rb', line 251
def convert_a(el, indent)
res = inner(el, indent)
attr = el.attr.dup
if attr['href'] =~ /^mailto:/
attr['href'] = obfuscate('mailto') << ":" << obfuscate(attr['href'].sub(/^mailto:/, ''))
res = obfuscate(res)
end
"<a#{html_attributes(attr)}>#{res}</a>"
end
|
#convert_abbreviation(el, indent) ⇒ Object
321
322
323
324
|
# File 'lib/kramdown/converter/html.rb', line 321
def convert_abbreviation(el, indent)
title = @root.options[:abbrev_defs][el.value]
"<abbr#{!title.empty? ? " title=\"#{title}\"" : ''}>#{el.value}</abbr>"
end
|
#convert_blank(el, indent) ⇒ Object
94
95
96
|
# File 'lib/kramdown/converter/html.rb', line 94
def convert_blank(el, indent)
"\n"
end
|
#convert_blockquote(el, indent) ⇒ Object
136
137
138
|
# File 'lib/kramdown/converter/html.rb', line 136
def convert_blockquote(el, indent)
"#{' '*indent}<blockquote#{html_attributes(el.attr)}>\n#{inner(el, indent)}#{' '*indent}</blockquote>\n"
end
|
#convert_br(el, indent) ⇒ Object
247
248
249
|
# File 'lib/kramdown/converter/html.rb', line 247
def convert_br(el, indent)
"<br />"
end
|
#convert_codeblock(el, indent) ⇒ Object
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
# File 'lib/kramdown/converter/html.rb', line 110
def convert_codeblock(el, indent)
if el.attr['lang'] && HIGHLIGHTING_AVAILABLE
attr = el.attr.dup
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]}
result = CodeRay.scan(el.value, attr.delete('lang').to_sym).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
"#{' '*indent}<pre#{html_attributes(el.attr)}><code>#{result}\n</code></pre>\n"
end
end
|
#convert_codespan(el, indent) ⇒ Object
265
266
267
268
269
270
271
272
273
|
# File 'lib/kramdown/converter/html.rb', line 265
def convert_codespan(el, indent)
if el.attr['lang'] && HIGHLIGHTING_AVAILABLE
attr = el.attr.dup
result = CodeRay.scan(el.value, attr.delete('lang').to_sym).html(:wrap => :span, :css => @options[:coderay_css]).chomp
"<code#{html_attributes(attr)}>#{result}</code>"
else
"<code#{html_attributes(el.attr)}>#{escape_html(el.value)}</code>"
end
end
|
239
240
241
242
243
244
245
|
# File 'lib/kramdown/converter/html.rb', line 239
def (el, indent)
if el.options[:category] == :block
"#{' '*indent}<!-- #{el.value} -->\n"
else
"<!-- #{el.value} -->"
end
end
|
#convert_dt(el, indent) ⇒ Object
176
177
178
|
# File 'lib/kramdown/converter/html.rb', line 176
def convert_dt(el, indent)
"#{' '*indent}<dt#{html_attributes(el.attr)}>#{inner(el, indent)}</dt>\n"
end
|
#convert_em(el, indent) ⇒ Object
Also known as:
convert_strong
290
291
292
|
# File 'lib/kramdown/converter/html.rb', line 290
def convert_em(el, indent)
"<#{el.type}#{html_attributes(el.attr)}>#{inner(el, indent)}</#{el.type}>"
end
|
#convert_entity(el, indent) ⇒ Object
295
296
297
|
# File 'lib/kramdown/converter/html.rb', line 295
def convert_entity(el, indent)
entity_to_str(el.value, el.options[:original])
end
|
275
276
277
278
279
280
|
# File 'lib/kramdown/converter/html.rb', line 275
def (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
|
140
141
142
143
144
145
146
147
|
# File 'lib/kramdown/converter/html.rb', line 140
def (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)
"#{' '*indent}<h#{el.options[:level]}#{html_attributes(attr)}>#{inner(el, indent)}</h#{el.options[:level]}>\n"
end
|
#convert_hr(el, indent) ⇒ Object
149
150
151
|
# File 'lib/kramdown/converter/html.rb', line 149
def convert_hr(el, indent)
"#{' '*indent}<hr />\n"
end
|
#convert_html_element(el, indent) ⇒ Object
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
|
# File 'lib/kramdown/converter/html.rb', line 183
def convert_html_element(el, indent)
res = inner(el, indent)
if el.options[:category] == :span
"<#{el.value}#{html_attributes(el.attr)}" << (!res.empty? || HTML_TAGS_WITH_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 !res.empty? && el.options[:content_model] != :block
output << ">#{res}</#{el.value}>"
elsif !res.empty?
output << ">\n#{res.chomp}\n" << ' '*indent << "</#{el.value}>"
elsif HTML_TAGS_WITH_BODY.include?(el.value)
output << "></#{el.value}>"
else
output << " />"
end
output << "\n" if @stack.last.type != :html_element || @stack.last.options[:content_model] != :raw
output
end
end
|
#convert_img(el, indent) ⇒ Object
261
262
263
|
# File 'lib/kramdown/converter/html.rb', line 261
def convert_img(el, indent)
"<img#{html_attributes(el.attr)} />"
end
|
#convert_li(el, indent) ⇒ Object
Also known as:
convert_dd
164
165
166
167
168
169
170
171
172
173
|
# File 'lib/kramdown/converter/html.rb', line 164
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
|
#convert_math(el, indent) ⇒ Object
316
317
318
319
|
# File 'lib/kramdown/converter/html.rb', line 316
def convert_math(el, indent)
block = (el.options[:category] == :block)
"<script type=\"math/tex#{block ? '; mode=display' : ''}\">#{el.value}</script>#{block ? "\n" : ''}"
end
|
#convert_p(el, indent) ⇒ Object
102
103
104
105
106
107
108
|
# File 'lib/kramdown/converter/html.rb', line 102
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
|
#convert_raw(el, indent) ⇒ Object
282
283
284
285
286
287
288
|
# File 'lib/kramdown/converter/html.rb', line 282
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
|
#convert_root(el, indent) ⇒ Object
326
327
328
329
330
331
332
333
334
335
336
337
338
339
|
# File 'lib/kramdown/converter/html.rb', line 326
def convert_root(el, indent)
result = inner(el, indent)
result <<
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
|
#convert_smart_quote(el, indent) ⇒ Object
312
313
314
|
# File 'lib/kramdown/converter/html.rb', line 312
def convert_smart_quote(el, indent)
entity_to_str(smart_quote_entity(el))
end
|
#convert_table(el, indent) ⇒ Object
214
215
216
|
# File 'lib/kramdown/converter/html.rb', line 214
def convert_table(el, indent)
"#{' '*indent}<table#{html_attributes(el.attr)}>\n#{inner(el, indent)}#{' '*indent}</table>\n"
end
|
#convert_td(el, indent) ⇒ Object
227
228
229
230
231
232
233
234
235
236
237
|
# File 'lib/kramdown/converter/html.rb', line 227
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
|
#convert_text(el, indent) ⇒ Object
98
99
100
|
# File 'lib/kramdown/converter/html.rb', line 98
def convert_text(el, indent)
escape_html(el.value, :text)
end
|
#convert_thead(el, indent) ⇒ Object
Also known as:
convert_tbody, , convert_tr
218
219
220
|
# File 'lib/kramdown/converter/html.rb', line 218
def convert_thead(el, indent)
"#{' '*indent}<#{el.type}#{html_attributes(el.attr)}>\n#{inner(el, indent)}#{' '*indent}</#{el.type}>\n"
end
|
#convert_typographic_sym(el, indent) ⇒ Object
308
309
310
|
# File 'lib/kramdown/converter/html.rb', line 308
def convert_typographic_sym(el, indent)
TYPOGRAPHIC_SYMS[el.value].map {|e| entity_to_str(e)}.join('')
end
|
#convert_ul(el, indent) ⇒ Object
Also known as:
convert_ol, convert_dl
153
154
155
156
157
158
159
160
|
# File 'lib/kramdown/converter/html.rb', line 153
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
|
205
206
207
208
209
210
211
|
# File 'lib/kramdown/converter/html.rb', line 205
def (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.
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
|
# File 'lib/kramdown/converter/html.rb', line 388
def
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_toc_tree(toc, type, attr) ⇒ Object
Generate and return an element tree for the table of contents.
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
|
# File 'lib/kramdown/converter/html.rb', line 342
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(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
|
#inner(el, indent) ⇒ Object
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.
83
84
85
86
87
88
89
90
91
92
|
# File 'lib/kramdown/converter/html.rb', line 83
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(text) ⇒ Object
Obfuscate the text
by using HTML entities.
378
379
380
381
382
383
384
385
|
# File 'lib/kramdown/converter/html.rb', line 378
def obfuscate(text)
result = ""
text.each_byte do |b|
result << (b > 128 ? b.chr : "&#%03d;" % b)
end
result.force_encoding(text.encoding) if RUBY_VERSION >= '1.9'
result
end
|