# encoding: UTF-8 module Asciidoctor # A built-in {Converter} implementation that generates HTML 5 output # consistent with the html5 backend from AsciiDoc Python. class Converter::Html5Converter < Converter::BuiltIn (QUOTE_TAGS = { :emphasis => ['', '', true], :strong => ['', '', true], :monospaced => ['', '', true], :superscript => ['', '', true], :subscript => ['', '', true], :double => ['“', '”', false], :single => ['‘', '’', false], :mark => ['', '', true], :asciimath => ['\\$', '\\$', false], :latexmath => ['\\(', '\\)', false] # Opal can't resolve these constants when referenced here #:asciimath => INLINE_MATH_DELIMITERS[:asciimath] + [false], #:latexmath => INLINE_MATH_DELIMITERS[:latexmath] + [false] }).default = [nil, nil, nil] SvgPreambleRx = /\A.*?(?=])/m SvgStartTagRx = /\A]*>/ DimensionAttributeRx = /\s(?:width|height|style)=(["']).*?\1/ def initialize backend, opts = {} @xml_mode = opts[:htmlsyntax] == 'xml' @void_element_slash = @xml_mode ? '/' : nil @stylesheets = Stylesheets.instance end def document node result = [] slash = @void_element_slash br = %() unless (asset_uri_scheme = (node.attr 'asset-uri-scheme', 'https')).empty? asset_uri_scheme = %(#{asset_uri_scheme}:) end cdn_base = %(#{asset_uri_scheme}//cdnjs.cloudflare.com/ajax/libs) linkcss = node.safe >= SafeMode::SECURE || (node.attr? 'linkcss') result << '' lang_attribute = (node.attr? 'nolang') ? nil : %( lang="#{node.attr 'lang', 'en'}") result << %() result << %( ) result << %() if node.attr? 'app-name' result << %() if node.attr? 'description' result << %() if node.attr? 'keywords' result << %() if node.attr? 'authors' result << %() if node.attr? 'copyright' result << %(#{node.doctitle :sanitize => true, :use_fallback => true}) if DEFAULT_STYLESHEET_KEYS.include?(node.attr 'stylesheet') if (webfonts = node.attr 'webfonts') result << %() end if linkcss result << %() else result << @stylesheets.embed_primary_stylesheet end elsif node.attr? 'stylesheet' if linkcss result << %() else result << %() end end if node.attr? 'icons', 'font' if node.attr? 'iconfont-remote' result << %() else iconfont_stylesheet = %(#{node.attr 'iconfont-name', 'font-awesome'}.css) result << %() end end case (highlighter = node.attr 'source-highlighter') when 'coderay' if (node.attr 'coderay-css', 'class') == 'class' if linkcss result << %() 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 << %() else result << (@stylesheets.embed_pygments_stylesheet pygments_style) end end end unless (docinfo_content = node.docinfo).empty? result << docinfo_content end result << '' body_attrs = [] body_attrs << %(id="#{node.id}") if node.id if (sectioned = node.sections?) && (node.attr? 'toc-class') && (node.attr? 'toc') && (node.attr? 'toc-placement', 'auto') body_attrs << %(class="#{node.doctype} #{node.attr 'toc-class'} toc-#{node.attr 'toc-position', 'header'}") else body_attrs << %(class="#{node.doctype}") end body_attrs << %(style="max-width: #{node.attr 'max-width'};") if node.attr? 'max-width' result << %() unless node.noheader result << '' end result << %(
#{node.content}
) if node.footnotes? && !(node.attr? 'nofootnotes') result << %(
) node.footnotes.each do |footnote| result << %(
#{footnote.index}. #{footnote.text}
) end result << '
' end unless node.nofooter result << '' 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', %(#{cdn_base}/highlight.js/8.9.1) result << %() result << %( ) when 'prettify' prettify_path = node.attr 'prettifydir', %(#{cdn_base}/prettify/r298) result << %() result << %( ) end if node.attr? 'stem' eqnums_val = node.attr 'eqnums', 'none' eqnums_val = 'AMS' if eqnums_val == '' eqnums_opt = %( equationNumbers: { autoNumber: "#{eqnums_val}" } ) # IMPORTANT inspect calls on delimiter arrays are intentional for JavaScript compat (emulates JSON.stringify) result << %( ) end result << '' result << '' result * EOL end def embedded node result = [] if node.doctype == 'manpage' # QUESTION should notitle control the manual page title? unless node.notitle id_attr = node.id ? %( id="#{node.id}") : nil result << %(#{node.doctitle} Manual Page) end # QUESTION should this h2 have an auto-generated id? result << %(

#{node.attr 'manname-title'}

#{node.attr 'manname'} - #{node.attr 'manpurpose'}

) else if node.has_header? && !node.notitle id_attr = node.id ? %( id="#{node.id}") : nil result << %(#{node.header.title}) end end if node.sections? && (node.attr? 'toc') && (toc_p = node.attr 'toc-placement') != 'macro' && toc_p != 'preamble' result << %(
#{node.attr 'toc-title'}
#{outline node}
) end result << node.content if node.footnotes? && !(node.attr? 'nofootnotes') result << %(
) node.footnotes.each do |footnote| result << %(
#{footnote.index}. #{footnote.text}
) end result << '
' end result * EOL end 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 << %(
    ) sections.each do |section| section_num = (section.numbered && !section.caption && section.level <= sectnumlevels) ? %(#{section.sectnum} ) : nil if section.level < toclevels && (child_toc_level = outline section, :toclevels => toclevels, :secnumlevels => sectnumlevels) result << %(
  • #{section_num}#{section.captioned_title}) result << child_toc_level result << '
  • ' else result << %(
  • #{section_num}#{section.captioned_title}
  • ) end end result << '
' result * EOL end def section node slevel = node.level # QUESTION should the check for slevel be done in section? slevel = 1 if slevel == 0 && node.special htag = %(h#{slevel + 1}) id_attr = anchor = link_start = link_end = nil if node.id id_attr = %( id="#{node.id}") if node.document.attr? 'sectanchors' anchor = %() # possible idea - anchor icons GitHub-style #if node.document.attr? 'icons', 'font' # anchor = %() #else elsif node.document.attr? 'sectlinks' link_start = %() link_end = '' end end if slevel == 0 %(#{anchor}#{link_start}#{node.title}#{link_end} #{node.content}) else class_attr = (role = node.role) ? %( class="sect#{slevel} #{role}") : %( class="sect#{slevel}") sectnum = if node.numbered && !node.caption && slevel <= (node.document.attr 'sectnumlevels', 3).to_i %(#{node.sectnum} ) end %( <#{htag}#{id_attr}>#{anchor}#{link_start}#{sectnum}#{node.captioned_title}#{link_end} #{slevel == 1 ? %[
\n#{node.content}\n
] : node.content} ) end end def admonition node id_attr = node.id ? %( id="#{node.id}") : nil name = node.attr 'name' title_element = node.title? ? %(
#{node.title}
\n) : nil caption = if node.document.attr? 'icons' if (node.document.attr? 'icons', 'font') && !(node.attr? 'icon') %() else %(#{node.caption}) end else %(
#{node.caption}
) end %(
#{caption} #{title_element}#{node.content}
) end def audio node xml = node.document.attr? 'htmlsyntax', 'xml' id_attribute = node.id ? %( id="#{node.id}") : nil classes = ['audioblock', node.style, node.role].compact class_attribute = %( class="#{classes * ' '}") title_element = node.title? ? %(
#{node.captioned_title}
\n) : nil %( #{title_element}
) end def colist node result = [] id_attribute = node.id ? %( id="#{node.id}") : nil classes = ['colist', node.style, node.role].compact class_attribute = %( class="#{classes * ' '}") result << %() result << %(
#{node.title}
) if node.title? if node.document.attr? 'icons' result << '' font_icons = node.document.attr? 'icons', 'font' node.items.each_with_index do |item, i| num = i + 1 num_element = if font_icons %(#{num}) else %(#{num}) end result << %() end result << '
#{num_element} #{item.text}
' else result << '
    ' node.items.each do |item| result << %(
  1. #{item.text}

  2. ) end result << '
' end result << '' result * EOL end def dlist node result = [] id_attribute = node.id ? %( 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 = %( class="#{classes * ' '}") result << %() result << %(
#{node.title}
) if node.title? case node.style when 'qanda' result << '
    ' node.items.each do |terms, dd| result << '
  1. ' [*terms].each do |dt| result << %(

    #{dt.text}

    ) end if dd result << %(

    #{dd.text}

    ) if dd.text? result << dd.content if dd.blocks? end result << '
  2. ' end result << '
' when 'horizontal' slash = @void_element_slash result << '' if (node.attr? 'labelwidth') || (node.attr? 'itemwidth') result << '' col_style_attribute = (node.attr? 'labelwidth') ? %( style="width: #{(node.attr 'labelwidth').chomp '%'}%;") : nil result << %() col_style_attribute = (node.attr? 'itemwidth') ? %( style="width: #{(node.attr 'itemwidth').chomp '%'}%;") : nil result << %() result << '' end node.items.each do |terms, dd| result << '' result << %(' result << '' result << '' end result << '
) terms_array = [*terms] last_term = terms_array[-1] terms_array.each do |dt| result << dt.text result << %() if dt != last_term end result << '' if dd result << %(

#{dd.text}

) if dd.text? result << dd.content if dd.blocks? end result << '
' else result << '
' dt_style_attribute = node.style ? nil : ' class="hdlist1"' node.items.each do |terms, dd| [*terms].each do |dt| result << %(#{dt.text}) end if dd result << '
' result << %(

#{dd.text}

) if dd.text? result << dd.content if dd.blocks? result << '
' end end result << '
' end result << '' result * EOL end def example node id_attribute = node.id ? %( id="#{node.id}") : nil title_element = node.title? ? %(
#{node.captioned_title}
\n) : nil %( #{title_element}
#{node.content}
) end def floating_title node tag_name = %(h#{node.level + 1}) id_attribute = node.id ? %( id="#{node.id}") : nil classes = [node.style, node.role].compact %(<#{tag_name}#{id_attribute} class="#{classes * ' '}">#{node.title}) end def image node target = node.attr 'target' width_attr = (node.attr? 'width') ? %( width="#{node.attr 'width'}") : nil height_attr = (node.attr? 'height') ? %( 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) || %(#{node.attr 'alt'}) elsif obj fallback = (node.attr? 'fallback') ? %(#{node.attr 'alt'}) : %(#{node.attr 'alt'}) img = %(#{fallback}) end end img ||= %(#{node.attr 'alt'}) if (link = node.attr 'link') img = %(#{img}) end id_attr = node.id ? %( id="#{node.id}") : nil classes = ['imageblock', node.style, node.role].compact class_attr = %( class="#{classes * ' '}") styles = [] styles << %(text-align: #{node.attr 'align'}) if node.attr? 'align' styles << %(float: #{node.attr 'float'}) if node.attr? 'float' style_attr = styles.empty? ? nil : %( style="#{styles * ';'}") title_el = node.title? ? %(\n
#{node.captioned_title}
) : nil %(
#{img}
#{title_el} ) end def listing node nowrap = !(node.document.attr? 'prewrap') || (node.option? 'nowrap') if node.style == 'source' if (language = node.attr 'language', nil, false) code_attrs = %( data-lang="#{language}") else code_attrs = nil end case node.document.attr 'source-highlighter' when 'coderay' pre_class = %( class="CodeRay highlight#{nowrap ? ' nowrap' : nil}") when 'pygments' pre_class = %( class="pygments highlight#{nowrap ? ' nowrap' : nil}") when 'highlightjs', 'highlight.js' pre_class = %( class="highlightjs highlight#{nowrap ? ' nowrap' : nil}") code_attrs = %( class="language-#{language}"#{code_attrs}) if language when 'prettify' pre_class = %( class="prettyprint highlight#{nowrap ? ' nowrap' : nil}#{(node.attr? 'linenums') ? ' linenums' : nil}") code_attrs = %( class="language-#{language}"#{code_attrs}) if language when 'html-pipeline' pre_class = language ? %( lang="#{language}") : nil code_attrs = nil else pre_class = %( class="highlight#{nowrap ? ' nowrap' : nil}") code_attrs = %( class="language-#{language}"#{code_attrs}) if language end pre_start = %() pre_end = '' else pre_start = %() pre_end = '' end id_attribute = node.id ? %( id="#{node.id}") : nil title_element = node.title? ? %(
#{node.captioned_title}
\n) : nil %( #{title_element}
#{pre_start}#{node.content}#{pre_end}
) end def literal node id_attribute = node.id ? %( id="#{node.id}") : nil title_element = node.title? ? %(
#{node.title}
\n) : nil nowrap = !(node.document.attr? 'prewrap') || (node.option? 'nowrap') %( #{title_element}
#{node.content}
) end def stem node id_attribute = node.id ? %( id="#{node.id}") : nil title_element = node.title? ? %(
#{node.title}
\n) : nil open, close = BLOCK_MATH_DELIMITERS[node.style.to_sym] unless ((equation = node.content).start_with? open) && (equation.end_with? close) equation = %(#{open}#{equation}#{close}) end %( #{title_element}
#{equation}
) end def olist node result = [] id_attribute = node.id ? %( id="#{node.id}") : nil classes = ['olist', node.style, node.role].compact class_attribute = %( class="#{classes * ' '}") result << %() result << %(
#{node.title}
) if node.title? type_attribute = (keyword = node.list_marker_keyword) ? %( type="#{keyword}") : nil start_attribute = (node.attr? 'start') ? %( start="#{node.attr 'start'}") : nil result << %(
    ) node.items.each do |item| result << '
  1. ' result << %(

    #{item.text}

    ) result << item.content if item.blocks? result << '
  2. ' end result << '
' result << '' result * EOL end 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 ? %( id="#{node.id}") : nil title_el = node.title? ? %(
#{node.title}
) : nil %( #{title_el}
#{node.content}
) 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 ? %( id="#{node.id}") : nil title_el = node.title? ? %(
#{node.title}
) : nil %( #{title_el}
#{node.content}
) end end def page_break node '
' end def paragraph node class_attribute = node.role ? %(class="paragraph #{node.role}") : 'class="paragraph"' attributes = node.id ? %(id="#{node.id}" #{class_attribute}) : class_attribute if node.title? %(
#{node.title}

#{node.content}

) else %(

#{node.content}

) end end def preamble node if (doc = node.document).attr?('toc-placement', 'preamble') && doc.sections? && (doc.attr? 'toc') toc = %(
#{doc.attr 'toc-title'}
#{outline doc}
) else toc = nil end %(
#{node.content}
#{toc}
) end def quote node id_attribute = node.id ? %( id="#{node.id}") : nil classes = ['quoteblock', node.role].compact class_attribute = %( class="#{classes * ' '}") title_element = node.title? ? %(\n
#{node.title}
) : nil attribution = (node.attr? 'attribution') ? (node.attr 'attribution') : nil citetitle = (node.attr? 'citetitle') ? (node.attr 'citetitle') : nil if attribution || citetitle cite_element = citetitle ? %(#{citetitle}) : nil attribution_text = attribution ? %(— #{attribution}#{citetitle ? "\n" : nil}) : nil attribution_element = %(\n
\n#{attribution_text}#{cite_element}\n
) else attribution_element = nil end %(#{title_element}
#{node.content}
#{attribution_element} ) end def thematic_break node %() end def sidebar node id_attribute = node.id ? %( id="#{node.id}") : nil title_element = node.title? ? %(
#{node.title}
\n) : nil %(
#{title_element}#{node.content}
) end def table node result = [] id_attribute = node.id ? %( id="#{node.id}") : nil classes = ['tableblock', %(frame-#{node.attr 'frame', 'all'}), %(grid-#{node.attr 'grid', 'all'})] styles = [] unless node.option? 'autowidth' if (tablepcwidth = node.attr 'tablepcwidth') == 100 classes << 'spread' else styles << %(width: #{tablepcwidth}%;) end end if (role = node.role) classes << role end class_attribute = %( class="#{classes * ' '}") styles << %(float: #{node.attr 'float'};) if node.attr? 'float' style_attribute = styles.empty? ? nil : %( style="#{styles * ' '}") result << %() result << %(#{node.captioned_title}) if node.title? if (node.attr 'rowcount') > 0 slash = @void_element_slash result << '' if node.option? 'autowidth' tag = %() node.columns.size.times do result << tag end else node.columns.each do |col| result << %() end end result << '' [:head, :foot, :body].select {|tsec| !node.rows[tsec].empty? }.each do |tsec| result << %() node.rows[tsec].each do |row| result << '' row.each do |cell| if tsec == :head cell_content = cell.text else case cell.style when :asciidoc cell_content = %(
#{cell.content}
) when :verse cell_content = %(
#{cell.text}
) when :literal cell_content = %(
#{cell.text}
) else cell_content = '' cell.content.each do |text| cell_content = %(#{cell_content}

#{text}

) end end end cell_tag_name = (tsec == :head || cell.style == :header ? 'th' : 'td') cell_class_attribute = %( class="tableblock halign-#{cell.attr 'halign'} valign-#{cell.attr 'valign'}") cell_colspan_attribute = cell.colspan ? %( colspan="#{cell.colspan}") : nil cell_rowspan_attribute = cell.rowspan ? %( rowspan="#{cell.rowspan}") : nil cell_style_attribute = (node.document.attr? 'cellbgcolor') ? %( style="background-color: #{node.document.attr 'cellbgcolor'};") : nil result << %(<#{cell_tag_name}#{cell_class_attribute}#{cell_colspan_attribute}#{cell_rowspan_attribute}#{cell_style_attribute}>#{cell_content}) end result << '' end result << %(
) end end result << '' result * EOL end def toc node unless (doc = node.document).attr?('toc-placement', 'macro') && doc.sections? && (doc.attr? 'toc') return '' end if node.id id_attr = %( id="#{node.id}") title_id_attr = %( 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') %( #{title} #{outline doc, :toclevels => levels} ) end def ulist node result = [] id_attribute = node.id ? %( 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 node.document.attr? 'htmlsyntax', 'xml' marker_checked = ' ' marker_unchecked = ' ' else marker_checked = ' ' marker_unchecked = ' ' end else if node.document.attr? 'icons', 'font' marker_checked = ' ' marker_unchecked = ' ' else marker_checked = '✓ ' marker_unchecked = '❏ ' end end else ul_class_attribute = node.style ? %( class="#{node.style}") : nil end result << %() result << %(
#{node.title}
) if node.title? result << %() node.items.each do |item| result << '
  • ' if checklist && (item.attr? 'checkbox') result << %(

    #{(item.attr? 'checked') ? marker_checked : marker_unchecked}#{item.text}

    ) else result << %(

    #{item.text}

    ) end result << item.content if item.blocks? result << '
  • ' end result << '' result << '' result * EOL end def verse node id_attribute = node.id ? %( id="#{node.id}") : nil classes = ['verseblock', node.role].compact class_attribute = %( class="#{classes * ' '}") title_element = node.title? ? %(\n
    #{node.title}
    ) : nil attribution = (node.attr? 'attribution') ? (node.attr 'attribution') : nil citetitle = (node.attr? 'citetitle') ? (node.attr 'citetitle') : nil if attribution || citetitle cite_element = citetitle ? %(#{citetitle}) : nil attribution_text = attribution ? %(— #{attribution}#{citetitle ? "\n" : nil}) : nil attribution_element = %(\n
    \n#{attribution_text}#{cite_element}\n
    ) else attribution_element = nil end %(#{title_element}
    #{node.content}
    #{attribution_element} ) end def video node xml = node.document.attr? 'htmlsyntax', 'xml' id_attribute = node.id ? %( id="#{node.id}") : nil classes = ['videoblock', node.style, node.role].compact class_attribute = %( class="#{classes * ' '}") title_element = node.title? ? %(\n
    #{node.captioned_title}
    ) : nil width_attribute = (node.attr? 'width') ? %( width="#{node.attr 'width'}") : nil height_attribute = (node.attr? 'height') ? %( 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 = %(#{asset_uri_scheme}:) end start_anchor = (node.attr? 'start', nil, false) ? %(#at=#{node.attr 'start'}) : nil delimiter = '?' autoplay_param = (node.option? 'autoplay') ? %(#{delimiter}autoplay=1) : nil delimiter = '&' if autoplay_param loop_param = (node.option? 'loop') ? %(#{delimiter}loop=1) : nil %(#{title_element}
    ) when 'youtube' unless (asset_uri_scheme = (node.document.attr 'asset-uri-scheme', 'https')).empty? asset_uri_scheme = %(#{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) ? %(&start=#{node.attr 'start'}) : nil end_param = (node.attr? 'end', nil, false) ? %(&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) ? %(&theme=#{node.attr 'theme'}) : nil hl_param = (node.attr? 'lang') ? %(&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 = %(&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 = %(&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 ? %(&playlist=#{target}) : nil end end %(#{title_element}
    ) else poster_attribute = %(#{poster = node.attr 'poster'}).empty? ? nil : %( 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) ? %(#t=#{start_t}#{end_t ? ',' : nil}#{end_t}) : nil %(#{title_element}
    ) end end 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] || %([#{refid}])) # FIXME shouldn't target be refid? logic seems confused here %(#{text}) when :ref %() when :link attrs = [] attrs << %( id="#{node.id}") if node.id if (role = node.role) attrs << %( class="#{role}") end attrs << %( title="#{node.attr 'title'}") if node.attr? 'title', nil, false attrs << %( target="#{node.attr 'window'}") if node.attr? 'window', nil, false %(#{node.text}) when :bibref %([#{target}]) else warn %(asciidoctor: WARNING: unknown anchor type: #{node.type.inspect}) end end def inline_break node %(#{node.text}) end def inline_button node %(#{node.text}) end def inline_callout node if node.document.attr? 'icons', 'font' %((#{node.text})) elsif node.document.attr? 'icons' src = node.icon_uri("callouts/#{node.text}") %(#{node.text}) else %((#{node.text})) end end def inline_footnote node if (index = node.attr 'index') if node.type == :xref %([#{index}]) else id_attr = node.id ? %( id="_footnote_#{node.id}") : nil %([#{index}]) end elsif node.type == :xref %([#{node.text}]) end end def inline_image node if (type = node.type) == 'icon' && (node.document.attr? 'icons', 'font') class_attr_val = %(fa fa-#{node.target}) {'size' => 'fa-', 'rotate' => 'fa-rotate-', 'flip' => 'fa-flip-'}.each do |(key, prefix)| class_attr_val = %(#{class_attr_val} #{prefix}#{node.attr key}) if node.attr? key end title_attr = (node.attr? 'title') ? %( title="#{node.attr 'title'}") : nil img = %() elsif type == 'icon' && !(node.document.attr? 'icons') img = %([#{node.attr 'alt'}]) else target = node.target attrs = ['width', 'height', 'title'].map {|name| (node.attr? name) ? %( #{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) || %(#{node.attr 'alt'}) elsif obj fallback = (node.attr? 'fallback') ? %(#{node.attr 'alt'}) : %(#{node.attr 'alt'}) img = %(#{fallback}) end end img ||= %(#{node.attr 'alt'}) end if node.attr? 'link' window_attr = (node.attr? 'window') ? %( target="#{node.attr 'window'}") : nil img = %(#{img}) end class_attr_val = (role = node.role) ? %(#{type} #{role}) : type style_attr = (node.attr? 'float') ? %( style="float: #{node.attr 'float'}") : nil %(#{img}) end def inline_indexterm node node.type == :visible ? node.text : '' end def inline_kbd node if (keys = node.attr 'keys').size == 1 %(#{keys[0]}) else key_combo = keys.map {|key| %(#{key}+) }.join.chop %(#{key_combo}) end end def inline_menu node menu = node.attr 'menu' if !(submenus = node.attr 'submenus').empty? submenu_path = submenus.map {|submenu| %(#{submenu} ▸ ) }.join.chop %(#{menu} ▸ #{submenu_path} #{node.attr 'menuitem'}) elsif (menuitem = node.attr 'menuitem') %(#{menu} ▸ #{menuitem}) else %(#{menu}) end end def inline_quoted node open, close, is_tag = QUOTE_TAGS[node.type] if (role = node.role) if is_tag quoted_text = %(#{open.chop} class="#{role}">#{node.text}#{close}) else quoted_text = %(#{open}#{node.text}#{close}) end else quoted_text = %(#{open}#{node.text}#{close}) end node.id ? %(#{quoted_text}) : quoted_text end def append_boolean_attribute name, xml xml ? %( #{name}="#{name}") : %( #{name}) end 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, '' start_tag = nil ['width', 'height'].each do |dim| if node.attr? dim # NOTE width, height and style attributes are removed if either width or height is specified start_tag ||= (svg.match SvgStartTagRx)[0].gsub DimensionAttributeRx, '' start_tag = %(#{start_tag.chop} #{dim}="#{node.attr dim}px">) end end svg = svg.sub SvgStartTagRx, start_tag if start_tag end svg end end end