class Asciidoctor::Converter::Html5Converter
A built-in {Converter} implementation that generates HTML 5 output consistent with the html5 backend from AsciiDoc Python.
Constants
- DimensionAttributeRx
- QUOTE_TAGS
- SvgPreambleRx
- SvgStartTagRx
Public Class Methods
new(backend, opts = {})
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 25 def initialize backend, opts = {} @xml_mode = opts[:htmlsyntax] == 'xml' @void_element_slash = @xml_mode ? '/' : nil @stylesheets = Stylesheets.instance end
Public Instance Methods
admonition(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 354 def admonition node id_attr = node.id ? %Q( id="#{node.id}") : nil name = node.attr 'name' title_element = node.title? ? %Q(<div class="title">#{node.title}</div>\n) : nil caption = if node.document.attr? 'icons' if (node.document.attr? 'icons', 'font') && !(node.attr? 'icon') %Q(<i class="fa icon-#{name}" title="#{node.caption}"></i>) else %Q(<img src="#{node.icon_uri name}" alt="#{node.caption}"#{@void_element_slash}>) end else %Q(<div class="title">#{node.caption}</div>) end %Q(<div#{id_attr} class="admonitionblock #{name}#{(role = node.role) && " #{role}"}"> <table> <tr> <td class="icon"> #{caption} </td> <td class="content"> #{title_element}#{node.content} </td> </tr> </table> </div>) end
append_boolean_attribute(name, xml)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 1146 def append_boolean_attribute name, xml xml ? %Q( #{name}="#{name}") : %Q( #{name}) end
audio(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 381 def audio node xml = @xml_mode id_attribute = node.id ? %Q( id="#{node.id}") : nil classes = ['audioblock', node.role].compact class_attribute = %Q( class="#{classes * ' '}") title_element = node.title? ? %Q(<div class="title">#{node.captioned_title}</div>\n) : nil %Q(<div#{id_attribute}#{class_attribute}> #{title_element}<div class="content"> <audio src="#{node.media_uri(node.attr 'target')}"#{(node.option? 'autoplay') ? (append_boolean_attribute 'autoplay', xml) : nil}#{(node.option? 'nocontrols') ? nil : (append_boolean_attribute 'controls', xml)}#{(node.option? 'loop') ? (append_boolean_attribute 'loop', xml) : nil}> Your browser does not support the audio tag. </audio> </div> </div>) end
colist(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 396 def colist node result = [] id_attribute = node.id ? %Q( id="#{node.id}") : nil classes = ['colist', node.style, node.role].compact class_attribute = %Q( class="#{classes * ' '}") result << %Q(<div#{id_attribute}#{class_attribute}>) result << %Q(<div class="title">#{node.title}</div>) if node.title? if node.document.attr? 'icons' result << '<table>' font_icons = node.document.attr? 'icons', 'font' node.items.each_with_index do |item, i| num = i + 1 num_element = if font_icons %Q(<i class="conum" data-value="#{num}"></i><b>#{num}</b>) else %Q(<img src="#{node.icon_uri "callouts/#{num}"}" alt="#{num}"#{@void_element_slash}>) end result << %Q(<tr> <td>#{num_element}</td> <td>#{item.text}</td> </tr>) end result << '</table>' else result << '<ol>' node.items.each do |item| result << %Q(<li> <p>#{item.text}</p> </li>) end result << '</ol>' end result << '</div>' result * EOL end
dlist(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 437 def dlist node result = [] id_attribute = node.id ? %Q( id="#{node.id}") : nil classes = case node.style when 'qanda' ['qlist', 'qanda', node.role] when 'horizontal' ['hdlist', node.role] else ['dlist', node.style, node.role] end.compact class_attribute = %Q( class="#{classes * ' '}") result << %Q(<div#{id_attribute}#{class_attribute}>) result << %Q(<div class="title">#{node.title}</div>) if node.title? case node.style when 'qanda' result << '<ol>' node.items.each do |terms, dd| result << '<li>' [*terms].each do |dt| result << %Q(<p><em>#{dt.text}</em></p>) end if dd result << %Q(<p>#{dd.text}</p>) if dd.text? result << dd.content if dd.blocks? end result << '</li>' end result << '</ol>' when 'horizontal' slash = @void_element_slash result << '<table>' if (node.attr? 'labelwidth') || (node.attr? 'itemwidth') result << '<colgroup>' col_style_attribute = (node.attr? 'labelwidth') ? %Q( style="width: #{(node.attr 'labelwidth').chomp '%'}%;") : nil result << %Q(<col#{col_style_attribute}#{slash}>) col_style_attribute = (node.attr? 'itemwidth') ? %Q( style="width: #{(node.attr 'itemwidth').chomp '%'}%;") : nil result << %Q(<col#{col_style_attribute}#{slash}>) result << '</colgroup>' end node.items.each do |terms, dd| result << '<tr>' result << %Q(<td class="hdlist1#{(node.option? 'strong') ? ' strong' : nil}">) terms_array = [*terms] last_term = terms_array[-1] terms_array.each do |dt| result << dt.text result << %Q(<br#{slash}>) if dt != last_term end result << '</td>' result << '<td class="hdlist2">' if dd result << %Q(<p>#{dd.text}</p>) if dd.text? result << dd.content if dd.blocks? end result << '</td>' result << '</tr>' end result << '</table>' else result << '<dl>' dt_style_attribute = node.style ? nil : ' class="hdlist1"' node.items.each do |terms, dd| [*terms].each do |dt| result << %Q(<dt#{dt_style_attribute}>#{dt.text}</dt>) end if dd result << '<dd>' result << %Q(<p>#{dd.text}</p>) if dd.text? result << dd.content if dd.blocks? result << '</dd>' end end result << '</dl>' end result << '</div>' result * EOL end
document(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 31 def document node result = [] slash = @void_element_slash br = %Q(<br#{slash}>) unless (asset_uri_scheme = (node.attr 'asset-uri-scheme', 'https')).empty? asset_uri_scheme = %Q(#{asset_uri_scheme}:) end cdn_base = %Q(#{asset_uri_scheme}//cdnjs.cloudflare.com/ajax/libs) linkcss = node.safe >= SafeMode::SECURE || (node.attr? 'linkcss') result << '<!DOCTYPE html>' lang_attribute = (node.attr? 'nolang') ? nil : %Q( lang="#{node.attr 'lang', 'en'}") result << %Q(<html#{@xml_mode ? ' xmlns="http://www.w3.org/1999/xhtml"' : nil}#{lang_attribute}>) result << %Q(<head> <meta charset="#{node.attr 'encoding', 'UTF-8'}"#{slash}> <!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"#{slash}><![endif]--> <meta name="viewport" content="width=device-width, initial-scale=1.0"#{slash}> <meta name="generator" content="Asciidoctor #{node.attr 'asciidoctor-version'}"#{slash}>) result << %Q(<meta name="application-name" content="#{node.attr 'app-name'}"#{slash}>) if node.attr? 'app-name' result << %Q(<meta name="description" content="#{node.attr 'description'}"#{slash}>) if node.attr? 'description' result << %Q(<meta name="keywords" content="#{node.attr 'keywords'}"#{slash}>) if node.attr? 'keywords' result << %Q(<meta name="author" content="#{node.attr 'authors'}"#{slash}>) if node.attr? 'authors' result << %Q(<meta name="copyright" content="#{node.attr 'copyright'}"#{slash}>) if node.attr? 'copyright' result << %Q(<title>#{node.doctitle :sanitize => true, :use_fallback => true}</title>) if DEFAULT_STYLESHEET_KEYS.include?(node.attr 'stylesheet') if (webfonts = node.attr 'webfonts') result << %Q(<link rel="stylesheet" href="#{asset_uri_scheme}//fonts.googleapis.com/css?family=#{webfonts.empty? ? 'Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700' : webfonts}"#{slash}>) end if linkcss result << %Q(<link rel="stylesheet" href="#{node.normalize_web_path DEFAULT_STYLESHEET_NAME, (node.attr 'stylesdir', ''), false}"#{slash}>) else result << @stylesheets.embed_primary_stylesheet end elsif node.attr? 'stylesheet' if linkcss result << %Q(<link rel="stylesheet" href="#{node.normalize_web_path((node.attr 'stylesheet'), (node.attr 'stylesdir', ''))}"#{slash}>) else result << %Q(<style> #{node.read_asset node.normalize_system_path((node.attr 'stylesheet'), (node.attr 'stylesdir', '')), :warn_on_failure => true} </style>) end end if node.attr? 'icons', 'font' if node.attr? 'iconfont-remote' result << %Q(<link rel="stylesheet" href="#{node.attr 'iconfont-cdn', %[#{cdn_base}/font-awesome/4.6.3/css/font-awesome.min.css]}"#{slash}>) else iconfont_stylesheet = %Q(#{node.attr 'iconfont-name', 'font-awesome'}.css) result << %Q(<link rel="stylesheet" href="#{node.normalize_web_path iconfont_stylesheet, (node.attr 'stylesdir', ''), false}"#{slash}>) end end case (highlighter = node.attr 'source-highlighter') when 'coderay' if (node.attr 'coderay-css', 'class') == 'class' if linkcss result << %Q(<link rel="stylesheet" href="#{node.normalize_web_path @stylesheets.coderay_stylesheet_name, (node.attr 'stylesdir', ''), false}"#{slash}>) else result << @stylesheets.embed_coderay_stylesheet end end when 'pygments' if (node.attr 'pygments-css', 'class') == 'class' pygments_style = node.attr 'pygments-style' if linkcss result << %Q(<link rel="stylesheet" href="#{node.normalize_web_path @stylesheets.pygments_stylesheet_name(pygments_style), (node.attr 'stylesdir', ''), false}"#{slash}>) else result << (@stylesheets.embed_pygments_stylesheet pygments_style) end end end unless (docinfo_content = node.docinfo).empty? result << docinfo_content end result << '</head>' body_attrs = [] body_attrs << %Q(id="#{node.id}") if node.id if (sectioned = node.sections?) && (node.attr? 'toc-class') && (node.attr? 'toc') && (node.attr? 'toc-placement', 'auto') body_attrs << %Q(class="#{node.doctype} #{node.attr 'toc-class'} toc-#{node.attr 'toc-position', 'header'}") else body_attrs << %Q(class="#{node.doctype}") end body_attrs << %Q(style="max-width: #{node.attr 'max-width'};") if node.attr? 'max-width' result << %Q(<body #{body_attrs * ' '}>) unless node.noheader result << '<div id="header">' if node.doctype == 'manpage' result << %Q(<h1>#{node.doctitle} Manual Page</h1>) if sectioned && (node.attr? 'toc') && (node.attr? 'toc-placement', 'auto') result << %Q(<div id="toc" class="#{node.attr 'toc-class', 'toc'}"> <div id="toctitle">#{node.attr 'toc-title'}</div> #{outline node} </div>) end # QUESTION should this h2 have an auto-generated id? result << %Q(<h2>#{node.attr 'manname-title'}</h2> <div class="sectionbody"> <p>#{node.attr 'manname'} - #{node.attr 'manpurpose'}</p> </div>) else if node.has_header? result << %Q(<h1>#{node.header.title}</h1>) unless node.notitle details = [] if node.attr? 'author' details << %Q(<span id="author" class="author">#{node.attr 'author'}</span>#{br}) if node.attr? 'email' details << %Q(<span id="email" class="email">#{node.sub_macros(node.attr 'email')}</span>#{br}) end if (authorcount = (node.attr 'authorcount').to_i) > 1 (2..authorcount).each do |idx| details << %Q(<span id="author#{idx}" class="author">#{node.attr "author_#{idx}"}</span>#{br}) if node.attr? %Q(email_#{idx}) details << %Q(<span id="email#{idx}" class="email">#{node.sub_macros(node.attr "email_#{idx}")}</span>#{br}) end end end end if node.attr? 'revnumber' details << %Q(<span id="revnumber">#{((node.attr 'version-label') || '').downcase} #{node.attr 'revnumber'}#{(node.attr? 'revdate') ? ',' : ''}</span>) end if node.attr? 'revdate' details << %Q(<span id="revdate">#{node.attr 'revdate'}</span>) end if node.attr? 'revremark' details << %Q(#{br}<span id="revremark">#{node.attr 'revremark'}</span>) end unless details.empty? result << '<div class="details">' result.concat details result << '</div>' end end if sectioned && (node.attr? 'toc') && (node.attr? 'toc-placement', 'auto') result << %Q(<div id="toc" class="#{node.attr 'toc-class', 'toc'}"> <div id="toctitle">#{node.attr 'toc-title'}</div> #{outline node} </div>) end end result << '</div>' end result << %Q(<div id="content"> #{node.content} </div>) if node.footnotes? && !(node.attr? 'nofootnotes') result << %Q(<div id="footnotes"> <hr#{slash}>) node.footnotes.each do |footnote| result << %Q(<div class="footnote" id="_footnote_#{footnote.index}"> <a href="#_footnoteref_#{footnote.index}">#{footnote.index}</a>. #{footnote.text} </div>) end result << '</div>' end unless node.nofooter result << '<div id="footer">' result << '<div id="footer-text">' result << %Q(#{node.attr 'version-label'} #{node.attr 'revnumber'}#{br}) if node.attr? 'revnumber' result << %Q(#{node.attr 'last-update-label'} #{node.attr 'docdatetime'}) if (node.attr? 'last-update-label') && !(node.attr? 'reproducible') result << '</div>' result << '</div>' end unless (docinfo_content = node.docinfo :footer).empty? result << docinfo_content end # Load Javascript at the end of body for performance # See http://www.html5rocks.com/en/tutorials/speed/script-loading/ case highlighter when 'highlightjs', 'highlight.js' highlightjs_path = node.attr 'highlightjsdir', %Q(#{cdn_base}/highlight.js/8.9.1) result << %Q(<link rel="stylesheet" href="#{highlightjs_path}/styles/#{node.attr 'highlightjs-theme', 'github'}.min.css"#{slash}>) result << %Q(<script src="#{highlightjs_path}/highlight.min.js"></script> <script>hljs.initHighlighting()</script>) when 'prettify' prettify_path = node.attr 'prettifydir', %Q(#{cdn_base}/prettify/r298) result << %Q(<link rel="stylesheet" href="#{prettify_path}/#{node.attr 'prettify-theme', 'prettify'}.min.css"#{slash}>) result << %Q(<script src="#{prettify_path}/prettify.min.js"></script> <script>prettyPrint()</script>) end if node.attr? 'stem' eqnums_val = node.attr 'eqnums', 'none' eqnums_val = 'AMS' if eqnums_val.empty? eqnums_opt = %Q( equationNumbers: { autoNumber: "#{eqnums_val}" } ) # IMPORTANT inspect calls on delimiter arrays are intentional for JavaScript compat (emulates JSON.stringify) result << %Q(<script type="text/x-mathjax-config"> MathJax.Hub.Config({ messageStyle: "none", tex2jax: { inlineMath: [#{INLINE_MATH_DELIMITERS[:latexmath].inspect}], displayMath: [#{BLOCK_MATH_DELIMITERS[:latexmath].inspect}], ignoreClass: "nostem|nolatexmath" }, asciimath2jax: { delimiters: [#{BLOCK_MATH_DELIMITERS[:asciimath].inspect}], ignoreClass: "nostem|noasciimath" }, TeX: {#{eqnums_opt}} }); </script> <script src="#{cdn_base}/mathjax/2.6.0/MathJax.js?config=TeX-MML-AM_HTMLorMML"></script>) end result << '</body>' result << '</html>' result * EOL end
embedded(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 248 def embedded node result = [] if node.doctype == 'manpage' # QUESTION should notitle control the manual page title? unless node.notitle id_attr = node.id ? %Q( id="#{node.id}") : nil result << %Q(<h1#{id_attr}>#{node.doctitle} Manual Page</h1>) end # QUESTION should this h2 have an auto-generated id? result << %Q(<h2>#{node.attr 'manname-title'}</h2> <div class="sectionbody"> <p>#{node.attr 'manname'} - #{node.attr 'manpurpose'}</p> </div>) else if node.has_header? && !node.notitle id_attr = node.id ? %Q( id="#{node.id}") : nil result << %Q(<h1#{id_attr}>#{node.header.title}</h1>) end end if node.sections? && (node.attr? 'toc') && (toc_p = node.attr 'toc-placement') != 'macro' && toc_p != 'preamble' result << %Q(<div id="toc" class="toc"> <div id="toctitle">#{node.attr 'toc-title'}</div> #{outline node} </div>) end result << node.content if node.footnotes? && !(node.attr? 'nofootnotes') result << %Q(<div id="footnotes"> <hr#{@void_element_slash}>) node.footnotes.each do |footnote| result << %Q(<div class="footnote" id="_footnote_#{footnote.index}"> <a href="#_footnoteref_#{footnote.index}">#{footnote.index}</a>. #{footnote.text} </div>) end result << '</div>' end result * EOL end
example(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 520 def example node id_attribute = node.id ? %Q( id="#{node.id}") : nil title_element = node.title? ? %Q(<div class="title">#{node.captioned_title}</div>\n) : nil %Q(<div#{id_attribute} class="#{(role = node.role) ? ['exampleblock', role] * ' ' : 'exampleblock'}"> #{title_element}<div class="content"> #{node.content} </div> </div>) end
floating_title(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 531 def floating_title node tag_name = %Q(h#{node.level + 1}) id_attribute = node.id ? %Q( id="#{node.id}") : nil classes = [node.style, node.role].compact %Q(<#{tag_name}#{id_attribute} class="#{classes * ' '}">#{node.title}</#{tag_name}>) end
image(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 538 def image node target = node.attr 'target' width_attr = (node.attr? 'width') ? %Q( width="#{node.attr 'width'}") : nil height_attr = (node.attr? 'height') ? %Q( height="#{node.attr 'height'}") : nil if ((node.attr? 'format', 'svg', false) || (target.include? '.svg')) && node.document.safe < SafeMode::SECURE && ((svg = (node.option? 'inline')) || (obj = (node.option? 'interactive'))) if svg img = (read_svg_contents node, target) || %Q(<span class="alt">#{node.attr 'alt'}</span>) elsif obj fallback = (node.attr? 'fallback') ? %Q(<img src="#{node.image_uri(node.attr 'fallback')}" alt="#{node.attr 'alt'}"#{width_attr}#{height_attr}#{@void_element_slash}>) : %Q(<span class="alt">#{node.attr 'alt'}</span>) img = %Q(<object type="image/svg+xml" data="#{node.image_uri target}"#{width_attr}#{height_attr}>#{fallback}</object>) end end img ||= %Q(<img src="#{node.image_uri target}" alt="#{node.attr 'alt'}"#{width_attr}#{height_attr}#{@void_element_slash}>) if (link = node.attr 'link') img = %Q(<a class="image" href="#{link}">#{img}</a>) end id_attr = node.id ? %Q( id="#{node.id}") : nil classes = ['imageblock', node.role].compact class_attr = %Q( class="#{classes * ' '}") styles = [] styles << %Q(text-align: #{node.attr 'align'}) if node.attr? 'align' styles << %Q(float: #{node.attr 'float'}) if node.attr? 'float' style_attr = styles.empty? ? nil : %Q( style="#{styles * ';'}") title_el = node.title? ? %Q(\n<div class="title">#{node.captioned_title}</div>) : nil %Q(<div#{id_attr}#{class_attr}#{style_attr}> <div class="content"> #{img} </div>#{title_el} </div>) end
inline_anchor(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 1014 def inline_anchor node target = node.target case node.type when :xref refid = node.attributes['refid'] || target # NOTE we lookup text in converter because DocBook doesn't need this logic text = node.text || (node.document.references[:ids][refid] || %Q([#{refid}])) # FIXME shouldn't target be refid? logic seems confused here %Q(<a href="#{target}">#{text}</a>) when :ref %Q(<a id="#{target}"></a>) when :link attrs = [] attrs << %Q( id="#{node.id}") if node.id if (role = node.role) attrs << %Q( class="#{role}") end attrs << %Q( title="#{node.attr 'title'}") if node.attr? 'title', nil, false attrs << %Q( target="#{node.attr 'window'}") if node.attr? 'window', nil, false %Q(<a href="#{target}"#{attrs.join}>#{node.text}</a>) when :bibref %Q(<a id="#{target}"></a>[#{target}]) else warn %Q(asciidoctor: WARNING: unknown anchor type: #{node.type.inspect}) end end
inline_break(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 1041 def inline_break node %Q(#{node.text}<br#{@void_element_slash}>) end
inline_callout(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 1049 def inline_callout node if node.document.attr? 'icons', 'font' %Q(<i class="conum" data-value="#{node.text}"></i><b>(#{node.text})</b>) elsif node.document.attr? 'icons' src = node.icon_uri("callouts/#{node.text}") %Q(<img src="#{src}" alt="#{node.text}"#{@void_element_slash}>) else %Q(<b class="conum">(#{node.text})</b>) end end
inline_footnote(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 1060 def inline_footnote node if (index = node.attr 'index') if node.type == :xref %Q(<sup class="footnoteref">[<a class="footnote" href="#_footnote_#{index}" title="View footnote.">#{index}</a>]</sup>) else id_attr = node.id ? %Q( id="_footnote_#{node.id}") : nil %Q(<sup class="footnote"#{id_attr}>[<a id="_footnoteref_#{index}" class="footnote" href="#_footnote_#{index}" title="View footnote.">#{index}</a>]</sup>) end elsif node.type == :xref %Q(<sup class="footnoteref red" title="Unresolved footnote reference.">[#{node.text}]</sup>) end end
inline_image(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 1073 def inline_image node if (type = node.type) == 'icon' && (node.document.attr? 'icons', 'font') class_attr_val = %Q(fa fa-#{node.target}) {'size' => 'fa-', 'rotate' => 'fa-rotate-', 'flip' => 'fa-flip-'}.each do |key, prefix| class_attr_val = %Q(#{class_attr_val} #{prefix}#{node.attr key}) if node.attr? key end title_attr = (node.attr? 'title') ? %Q( title="#{node.attr 'title'}") : nil img = %Q(<i class="#{class_attr_val}"#{title_attr}></i>) elsif type == 'icon' && !(node.document.attr? 'icons') img = %Q([#{node.attr 'alt'}]) else target = node.target attrs = ['width', 'height', 'title'].map {|name| (node.attr? name) ? %Q( #{name}="#{node.attr name}") : nil }.join if type != 'icon' && ((node.attr? 'format', 'svg', false) || (target.include? '.svg')) && node.document.safe < SafeMode::SECURE && ((svg = (node.option? 'inline')) || (obj = (node.option? 'interactive'))) if svg img = (read_svg_contents node, target) || %Q(<span class="alt">#{node.attr 'alt'}</span>) elsif obj fallback = (node.attr? 'fallback') ? %Q(<img src="#{node.image_uri(node.attr 'fallback')}" alt="#{node.attr 'alt'}"#{attrs}#{@void_element_slash}>) : %Q(<span class="alt">#{node.attr 'alt'}</span>) img = %Q(<object type="image/svg+xml" data="#{node.image_uri target}"#{attrs}>#{fallback}</object>) end end img ||= %Q(<img src="#{type == 'icon' ? (node.icon_uri target) : (node.image_uri target)}" alt="#{node.attr 'alt'}"#{attrs}#{@void_element_slash}>) end if node.attr? 'link' window_attr = (node.attr? 'window') ? %Q( target="#{node.attr 'window'}") : nil img = %Q(<a class="image" href="#{node.attr 'link'}"#{window_attr}>#{img}</a>) end class_attr_val = (role = node.role) ? %Q(#{type} #{role}) : type style_attr = (node.attr? 'float') ? %Q( style="float: #{node.attr 'float'}") : nil %Q(<span class="#{class_attr_val}"#{style_attr}>#{img}</span>) end
inline_indexterm(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 1106 def inline_indexterm node node.type == :visible ? node.text : '' end
inline_kbd(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 1110 def inline_kbd node if (keys = node.attr 'keys').size == 1 %Q(<kbd>#{keys[0]}</kbd>) else key_combo = keys.map {|key| %Q(<kbd>#{key}</kbd>+) }.join.chop %Q(<span class="keyseq">#{key_combo}</span>) end end
inline_quoted(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 1131 def inline_quoted node open, close, is_tag = QUOTE_TAGS[node.type] if (role = node.role) if is_tag quoted_text = %Q(#{open.chop} class="#{role}">#{node.text}#{close}) else quoted_text = %Q(<span class="#{role}">#{open}#{node.text}#{close}</span>) end else quoted_text = %Q(#{open}#{node.text}#{close}) end node.id ? %Q(<a id="#{node.id}"></a>#{quoted_text}) : quoted_text end
listing(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 570 def listing node nowrap = !(node.document.attr? 'prewrap') || (node.option? 'nowrap') if node.style == 'source' if (language = node.attr 'language', nil, false) code_attrs = %Q( data-lang="#{language}") else code_attrs = nil end case node.document.attr 'source-highlighter' when 'coderay' pre_class = %Q( class="CodeRay highlight#{nowrap ? ' nowrap' : nil}") when 'pygments' pre_class = %Q( class="pygments highlight#{nowrap ? ' nowrap' : nil}") when 'highlightjs', 'highlight.js' pre_class = %Q( class="highlightjs highlight#{nowrap ? ' nowrap' : nil}") code_attrs = %Q( class="language-#{language}"#{code_attrs}) if language when 'prettify' pre_class = %Q( class="prettyprint highlight#{nowrap ? ' nowrap' : nil}#{(node.attr? 'linenums') ? ' linenums' : nil}") code_attrs = %Q( class="language-#{language}"#{code_attrs}) if language when 'html-pipeline' pre_class = language ? %Q( lang="#{language}") : nil code_attrs = nil else pre_class = %Q( class="highlight#{nowrap ? ' nowrap' : nil}") code_attrs = %Q( class="language-#{language}"#{code_attrs}) if language end pre_start = %Q(<pre#{pre_class}><code#{code_attrs}>) pre_end = '</code></pre>' else pre_start = %Q(<pre#{nowrap ? ' class="nowrap"' : nil}>) pre_end = '</pre>' end id_attribute = node.id ? %Q( id="#{node.id}") : nil title_element = node.title? ? %Q(<div class="title">#{node.captioned_title}</div>\n) : nil %Q(<div#{id_attribute} class="listingblock#{(role = node.role) && " #{role}"}"> #{title_element}<div class="content"> #{pre_start}#{node.content}#{pre_end} </div> </div>) end
literal(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 612 def literal node id_attribute = node.id ? %Q( id="#{node.id}") : nil title_element = node.title? ? %Q(<div class="title">#{node.title}</div>\n) : nil nowrap = !(node.document.attr? 'prewrap') || (node.option? 'nowrap') %Q(<div#{id_attribute} class="literalblock#{(role = node.role) && " #{role}"}"> #{title_element}<div class="content"> <pre#{nowrap ? ' class="nowrap"' : nil}>#{node.content}</pre> </div> </div>) end
olist(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 639 def olist node result = [] id_attribute = node.id ? %Q( id="#{node.id}") : nil classes = ['olist', node.style, node.role].compact class_attribute = %Q( class="#{classes * ' '}") result << %Q(<div#{id_attribute}#{class_attribute}>) result << %Q(<div class="title">#{node.title}</div>) if node.title? type_attribute = (keyword = node.list_marker_keyword) ? %Q( type="#{keyword}") : nil start_attribute = (node.attr? 'start') ? %Q( start="#{node.attr 'start'}") : nil reversed_attribute = (node.option? 'reversed') ? (append_boolean_attribute 'reversed', @xml_mode) : nil result << %Q(<ol class="#{node.style}"#{type_attribute}#{start_attribute}#{reversed_attribute}>) node.items.each do |item| result << '<li>' result << %Q(<p>#{item.text}</p>) result << item.content if item.blocks? result << '</li>' end result << '</ol>' result << '</div>' result * EOL end
open(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 665 def open node if (style = node.style) == 'abstract' if node.parent == node.document && node.document.doctype == 'book' warn 'asciidoctor: WARNING: abstract block cannot be used in a document without a title when doctype is book. Excluding block content.' '' else id_attr = node.id ? %Q( id="#{node.id}") : nil title_el = node.title? ? %Q(<div class="title">#{node.title}</div>\n) : nil %Q(<div#{id_attr} class="quoteblock abstract#{(role = node.role) && " #{role}"}"> #{title_el}<blockquote> #{node.content} </blockquote> </div>) end elsif style == 'partintro' && (node.level > 0 || node.parent.context != :section || node.document.doctype != 'book') warn 'asciidoctor: ERROR: partintro block can only be used when doctype is book and it\s a child of a book part. Excluding block content.' '' else id_attr = node.id ? %Q( id="#{node.id}") : nil title_el = node.title? ? %Q(<div class="title">#{node.title}</div>\n) : nil %Q(<div#{id_attr} class="openblock#{style && style != 'open' ? " #{style}" : ''}#{(role = node.role) && " #{role}"}"> #{title_el}<div class="content"> #{node.content} </div> </div>) end end
outline(node, opts = {})
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 291 def outline node, opts = {} return unless node.sections? sectnumlevels = opts[:sectnumlevels] || (node.document.attr 'sectnumlevels', 3).to_i toclevels = opts[:toclevels] || (node.document.attr 'toclevels', 2).to_i result = [] sections = node.sections # FIXME the level for special sections should be set correctly in the model # slevel will only be 0 if we have a book doctype with parts slevel = (first_section = sections[0]).level slevel = 1 if slevel == 0 && first_section.special result << %Q(<ul class="sectlevel#{slevel}">) sections.each do |section| section_num = (section.numbered && !section.caption && section.level <= sectnumlevels) ? %Q(#{section.sectnum} ) : nil if section.level < toclevels && (child_toc_level = outline section, :toclevels => toclevels, :secnumlevels => sectnumlevels) result << %Q(<li><a href="##{section.id}">#{section_num}#{section.captioned_title}</a>) result << child_toc_level result << '</li>' else result << %Q(<li><a href="##{section.id}">#{section_num}#{section.captioned_title}</a></li>) end end result << '</ul>' result * EOL end
page_break(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 693 def page_break node '<div style="page-break-after: always;"></div>' end
paragraph(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 697 def paragraph node class_attribute = node.role ? %Q(class="paragraph #{node.role}") : 'class="paragraph"' attributes = node.id ? %Q(id="#{node.id}" #{class_attribute}) : class_attribute if node.title? %Q(<div #{attributes}> <div class="title">#{node.title}</div> <p>#{node.content}</p> </div>) else %Q(<div #{attributes}> <p>#{node.content}</p> </div>) end end
preamble(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 713 def preamble node if (doc = node.document).attr?('toc-placement', 'preamble') && doc.sections? && (doc.attr? 'toc') toc = %Q( <div id="toc" class="#{doc.attr 'toc-class', 'toc'}"> <div id="toctitle">#{doc.attr 'toc-title'}</div> #{outline doc} </div>) else toc = nil end %Q(<div id="preamble"> <div class="sectionbody"> #{node.content} </div>#{toc} </div>) end
quote(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 731 def quote node id_attribute = node.id ? %Q( id="#{node.id}") : nil classes = ['quoteblock', node.role].compact class_attribute = %Q( class="#{classes * ' '}") title_element = node.title? ? %Q(\n<div class="title">#{node.title}</div>) : nil attribution = (node.attr? 'attribution') ? (node.attr 'attribution') : nil citetitle = (node.attr? 'citetitle') ? (node.attr 'citetitle') : nil if attribution || citetitle cite_element = citetitle ? %Q(<cite>#{citetitle}</cite>) : nil attribution_text = attribution ? %Q(— #{attribution}#{citetitle ? "<br#{@void_element_slash}>\n" : nil}) : nil attribution_element = %Q(\n<div class="attribution">\n#{attribution_text}#{cite_element}\n</div>) else attribution_element = nil end %Q(<div#{id_attribute}#{class_attribute}>#{title_element} <blockquote> #{node.content} </blockquote>#{attribution_element} </div>) end
read_svg_contents(node, target)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 1150 def read_svg_contents node, target if (svg = node.read_contents target, :start => (node.document.attr 'imagesdir'), :normalize => true, :label => 'SVG') svg = svg.sub SvgPreambleRx, '' unless svg.start_with? '<svg' old_start_tag = new_start_tag = nil # NOTE width, height and style attributes are removed if either width or height is specified ['width', 'height'].each do |dim| if node.attr? dim new_start_tag = (old_start_tag = (svg.match SvgStartTagRx)[0]).gsub DimensionAttributeRx, '' unless new_start_tag # QUESTION should we add px since it's already the default? new_start_tag = %Q(#{new_start_tag.chop} #{dim}="#{node.attr dim}px">) end end svg = %Q(#{new_start_tag}#{svg[old_start_tag.length..-1]}) if new_start_tag end svg end
section(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 316 def section node slevel = node.level # QUESTION should the check for slevel be done in section? slevel = 1 if slevel == 0 && node.special htag = %Q(h#{slevel + 1}) id_attr = anchor = link_start = link_end = nil if node.id id_attr = %Q( id="#{id = node.id}") if (doc = node.document).attr? 'sectanchors' anchor = %Q(<a class="anchor" href="##{id}"></a>) # possible idea - anchor icons GitHub-style #if doc.attr? 'icons', 'font' # anchor = %(<a class="anchor" href="##{id}"><i class="fa fa-anchor"></i></a>) #else # anchor = %(<a class="anchor" href="##{id}"></a>) #end end if doc.attr? 'sectlinks' link_start = %Q(<a class="link" href="##{id}">) link_end = '</a>' end end if slevel == 0 %Q(<h1#{id_attr} class="sect0">#{anchor}#{link_start}#{node.title}#{link_end}</h1> #{node.content}) else class_attr = (role = node.role) ? %Q( class="sect#{slevel} #{role}") : %Q( class="sect#{slevel}") sectnum = if node.numbered && !node.caption && slevel <= (node.document.attr 'sectnumlevels', 3).to_i %Q(#{node.sectnum} ) end %Q(<div#{class_attr}> <#{htag}#{id_attr}>#{anchor}#{link_start}#{sectnum}#{node.captioned_title}#{link_end}</#{htag}> #{slevel == 1 ? %[<div class="sectionbody">\n#{node.content}\n</div>] : node.content} </div>) end end
stem(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 623 def stem node id_attribute = node.id ? %Q( id="#{node.id}") : nil title_element = node.title? ? %Q(<div class="title">#{node.title}</div>\n) : nil open, close = BLOCK_MATH_DELIMITERS[node.style.to_sym] unless ((equation = node.content).start_with? open) && (equation.end_with? close) equation = %Q(#{open}#{equation}#{close}) end %Q(<div#{id_attribute} class="#{(role = node.role) ? ['stemblock', role] * ' ' : 'stemblock'}"> #{title_element}<div class="content"> #{equation} </div> </div>) end
table(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 767 def table node result = [] id_attribute = node.id ? %Q( id="#{node.id}") : nil classes = ['tableblock', %Q(frame-#{node.attr 'frame', 'all'}), %Q(grid-#{node.attr 'grid', 'all'})] styles = [] unless (node.option? 'autowidth') && !(node.attr? 'width', nil, false) if node.attr? 'tablepcwidth', 100 classes << 'spread' else styles << %Q(width: #{node.attr 'tablepcwidth'}%;) end end if (role = node.role) classes << role end class_attribute = %Q( class="#{classes * ' '}") styles << %Q(float: #{node.attr 'float'};) if node.attr? 'float' style_attribute = styles.empty? ? nil : %Q( style="#{styles * ' '}") result << %Q(<table#{id_attribute}#{class_attribute}#{style_attribute}>) result << %Q(<caption class="title">#{node.captioned_title}</caption>) if node.title? if (node.attr 'rowcount') > 0 slash = @void_element_slash result << '<colgroup>' if node.option? 'autowidth' tag = %Q(<col#{slash}>) node.columns.size.times do result << tag end else node.columns.each do |col| result << %Q(<col style="width: #{col.attr 'colpcwidth'}%;"#{slash}>) end end result << '</colgroup>' [:head, :foot, :body].select {|tsec| !node.rows[tsec].empty? }.each do |tsec| result << %Q(<t#{tsec}>) node.rows[tsec].each do |row| result << '<tr>' row.each do |cell| if tsec == :head cell_content = cell.text else case cell.style when :asciidoc cell_content = %Q(<div>#{cell.content}</div>) when :verse cell_content = %Q(<div class="verse">#{cell.text}</div>) when :literal cell_content = %Q(<div class="literal"><pre>#{cell.text}</pre></div>) else cell_content = '' cell.content.each do |text| cell_content = %Q(#{cell_content}<p class="tableblock">#{text}</p>) end end end cell_tag_name = (tsec == :head || cell.style == :header ? 'th' : 'td') cell_class_attribute = %Q( class="tableblock halign-#{cell.attr 'halign'} valign-#{cell.attr 'valign'}") cell_colspan_attribute = cell.colspan ? %Q( colspan="#{cell.colspan}") : nil cell_rowspan_attribute = cell.rowspan ? %Q( rowspan="#{cell.rowspan}") : nil cell_style_attribute = (node.document.attr? 'cellbgcolor') ? %Q( style="background-color: #{node.document.attr 'cellbgcolor'};") : nil result << %Q(<#{cell_tag_name}#{cell_class_attribute}#{cell_colspan_attribute}#{cell_rowspan_attribute}#{cell_style_attribute}>#{cell_content}</#{cell_tag_name}>) end result << '</tr>' end result << %Q(</t#{tsec}>) end end result << '</table>' result * EOL end
thematic_break(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 753 def thematic_break node %Q(<hr#{@void_element_slash}>) end
toc(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 841 def toc node unless (doc = node.document).attr?('toc-placement', 'macro') && doc.sections? && (doc.attr? 'toc') return '<!-- toc disabled -->' end if node.id id_attr = %Q( id="#{node.id}") title_id_attr = %Q( id="#{node.id}title") else id_attr = ' id="toc"' title_id_attr = ' id="toctitle"' end title = node.title? ? node.title : (doc.attr 'toc-title') levels = (node.attr? 'levels') ? (node.attr 'levels').to_i : nil role = node.role? ? node.role : (doc.attr 'toc-class', 'toc') %Q(<div#{id_attr} class="#{role}"> <div#{title_id_attr} class="title">#{title}</div> #{outline doc, :toclevels => levels} </div>) end
ulist(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 863 def ulist node result = [] id_attribute = node.id ? %Q( id="#{node.id}") : nil div_classes = ['ulist', node.style, node.role].compact marker_checked = nil marker_unchecked = nil if (checklist = node.option? 'checklist') div_classes.insert 1, 'checklist' ul_class_attribute = ' class="checklist"' if node.option? 'interactive' if @xml_mode marker_checked = '<input type="checkbox" data-item-complete="1" checked="checked"/> ' marker_unchecked = '<input type="checkbox" data-item-complete="0"/> ' else marker_checked = '<input type="checkbox" data-item-complete="1" checked> ' marker_unchecked = '<input type="checkbox" data-item-complete="0"> ' end else if node.document.attr? 'icons', 'font' marker_checked = '<i class="fa fa-check-square-o"></i> ' marker_unchecked = '<i class="fa fa-square-o"></i> ' else marker_checked = '✓ ' marker_unchecked = '❏ ' end end else ul_class_attribute = node.style ? %Q( class="#{node.style}") : nil end result << %Q(<div#{id_attribute} class="#{div_classes * ' '}">) result << %Q(<div class="title">#{node.title}</div>) if node.title? result << %Q(<ul#{ul_class_attribute}>) node.items.each do |item| result << '<li>' if checklist && (item.attr? 'checkbox') result << %Q(<p>#{(item.attr? 'checked') ? marker_checked : marker_unchecked}#{item.text}</p>) else result << %Q(<p>#{item.text}</p>) end result << item.content if item.blocks? result << '</li>' end result << '</ul>' result << '</div>' result * EOL end
verse(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 912 def verse node id_attribute = node.id ? %Q( id="#{node.id}") : nil classes = ['verseblock', node.role].compact class_attribute = %Q( class="#{classes * ' '}") title_element = node.title? ? %Q(\n<div class="title">#{node.title}</div>) : nil attribution = (node.attr? 'attribution') ? (node.attr 'attribution') : nil citetitle = (node.attr? 'citetitle') ? (node.attr 'citetitle') : nil if attribution || citetitle cite_element = citetitle ? %Q(<cite>#{citetitle}</cite>) : nil attribution_text = attribution ? %Q(— #{attribution}#{citetitle ? "<br#{@void_element_slash}>\n" : nil}) : nil attribution_element = %Q(\n<div class="attribution">\n#{attribution_text}#{cite_element}\n</div>) else attribution_element = nil end %Q(<div#{id_attribute}#{class_attribute}>#{title_element} <pre class="content">#{node.content}</pre>#{attribution_element} </div>) end
video(node)
click to toggle source
# File lib/asciidoctor/converter/html5.rb, line 932 def video node xml = @xml_mode id_attribute = node.id ? %Q( id="#{node.id}") : nil classes = ['videoblock', node.role].compact class_attribute = %Q( class="#{classes * ' '}") title_element = node.title? ? %Q(\n<div class="title">#{node.captioned_title}</div>) : nil width_attribute = (node.attr? 'width') ? %Q( width="#{node.attr 'width'}") : nil height_attribute = (node.attr? 'height') ? %Q( height="#{node.attr 'height'}") : nil case node.attr 'poster' when 'vimeo' unless (asset_uri_scheme = (node.document.attr 'asset-uri-scheme', 'https')).empty? asset_uri_scheme = %Q(#{asset_uri_scheme}:) end start_anchor = (node.attr? 'start', nil, false) ? %Q(#at=#{node.attr 'start'}) : nil delimiter = '?' autoplay_param = (node.option? 'autoplay') ? %Q(#{delimiter}autoplay=1) : nil delimiter = '&' if autoplay_param loop_param = (node.option? 'loop') ? %Q(#{delimiter}loop=1) : nil %Q(<div#{id_attribute}#{class_attribute}>#{title_element} <div class="content"> <iframe#{width_attribute}#{height_attribute} src="#{asset_uri_scheme}//player.vimeo.com/video/#{node.attr 'target'}#{start_anchor}#{autoplay_param}#{loop_param}" frameborder="0"#{(node.option? 'nofullscreen') ? nil : (append_boolean_attribute 'allowfullscreen', xml)}></iframe> </div> </div>) when 'youtube' unless (asset_uri_scheme = (node.document.attr 'asset-uri-scheme', 'https')).empty? asset_uri_scheme = %Q(#{asset_uri_scheme}:) end rel_param_val = (node.option? 'related') ? 1 : 0 # NOTE start and end must be seconds (t parameter allows XmYs where X is minutes and Y is seconds) start_param = (node.attr? 'start', nil, false) ? %Q(&start=#{node.attr 'start'}) : nil end_param = (node.attr? 'end', nil, false) ? %Q(&end=#{node.attr 'end'}) : nil autoplay_param = (node.option? 'autoplay') ? '&autoplay=1' : nil loop_param = (node.option? 'loop') ? '&loop=1' : nil controls_param = (node.option? 'nocontrols') ? '&controls=0' : nil # cover both ways of controlling fullscreen option if node.option? 'nofullscreen' fs_param = '&fs=0' fs_attribute = nil else fs_param = nil fs_attribute = append_boolean_attribute 'allowfullscreen', xml end modest_param = (node.option? 'modest') ? '&modestbranding=1' : nil theme_param = (node.attr? 'theme', nil, false) ? %Q(&theme=#{node.attr 'theme'}) : nil hl_param = (node.attr? 'lang') ? %Q(&hl=#{node.attr 'lang'}) : nil # parse video_id/list_id syntax where list_id (i.e., playlist) is optional target, list = (node.attr 'target').split '/', 2 if (list ||= (node.attr 'list', nil, false)) list_param = %Q(&list=#{list}) else # parse dynamic playlist syntax: video_id1,video_id2,... target, playlist = target.split ',', 2 if (playlist ||= (node.attr 'playlist', nil, false)) # INFO playlist bar doesn't appear in Firefox unless showinfo=1 and modestbranding=1 list_param = %Q(&playlist=#{playlist}) else # NOTE for loop to work, playlist must be specified; use VIDEO_ID if there's no explicit playlist list_param = loop_param ? %Q(&playlist=#{target}) : nil end end %Q(<div#{id_attribute}#{class_attribute}>#{title_element} <div class="content"> <iframe#{width_attribute}#{height_attribute} src="#{asset_uri_scheme}//www.youtube.com/embed/#{target}?rel=#{rel_param_val}#{start_param}#{end_param}#{autoplay_param}#{loop_param}#{controls_param}#{list_param}#{fs_param}#{modest_param}#{theme_param}#{hl_param}" frameborder="0"#{fs_attribute}></iframe> </div> </div>) else poster_attribute = %Q(#{poster = node.attr 'poster'}).empty? ? nil : %Q( poster="#{node.media_uri poster}") start_t = node.attr 'start', nil, false end_t = node.attr 'end', nil, false time_anchor = (start_t || end_t) ? %Q(#t=#{start_t}#{end_t ? ',' : nil}#{end_t}) : nil %Q(<div#{id_attribute}#{class_attribute}>#{title_element} <div class="content"> <video src="#{node.media_uri(node.attr 'target')}#{time_anchor}"#{width_attribute}#{height_attribute}#{poster_attribute}#{(node.option? 'autoplay') ? (append_boolean_attribute 'autoplay', xml) : nil}#{(node.option? 'nocontrols') ? nil : (append_boolean_attribute 'controls', xml)}#{(node.option? 'loop') ? (append_boolean_attribute 'loop', xml) : nil}> Your browser does not support the video tag. </video> </div> </div>) end end