lib/asciidoctor-epub3/converter.rb in asciidoctor-epub3-1.5.0.alpha.11 vs lib/asciidoctor-epub3/converter.rb in asciidoctor-epub3-1.5.0.alpha.12

- old
+ new

@@ -19,17 +19,21 @@ basebackend 'html' outfilesuffix '.epub' # dummy outfilesuffix since it may be .mobi htmlsyntax 'xml' @validate = false @extract = false + @kindlegen_path = nil + @epubcheck_path = nil end def convert node, name = nil if (name ||= node.node_name) == 'document' @validate = node.attr? 'ebook-validate' @extract = node.attr? 'ebook-extract' @compress = node.attr 'ebook-compress' + @kindlegen_path = node.attr 'ebook-kindlegen-path' + @epubcheck_path = node.attr 'ebook-epubcheck-path' spine_items = node.references[:spine_items] if spine_items.nil? logger.error %(#{::File.basename node.document.attr('docfile')}: failed to find spine items, produced file will be invalid) spine_items = [] end @@ -42,11 +46,11 @@ end end # FIXME: we have to package in write because we don't have access to target before this point def write packager, target - packager.package validate: @validate, extract: @extract, compress: @compress, target: target + packager.package validate: @validate, extract: @extract, compress: @compress, kindlegen_path: @kindlegen_path, epubcheck_path: @epubcheck_path, target: target nil end end # Public: The converter for the epub3 backend that converts the individual @@ -90,19 +94,20 @@ htmlsyntax 'xml' @xrefs_seen = ::Set.new @icon_names = [] end - def convert node, name = nil - if respond_to? name ||= node.node_name - send name, node + def convert node, name = nil, _opts = {} + method_name = %(convert_#{name ||= node.node_name}) + if respond_to? method_name + send method_name, node else - logger.warn %(conversion missing in epub3 backend for #{name}) + logger.warn %(conversion missing in backend #{@backend} for #{name}) end end - def document node + def convert_document node docid = node.id pubtype = node.attr 'publication-type', 'book' if (doctitle = node.doctitle partition: true, use_fallback: true).subtitle? title = %(#{doctitle.main} ) @@ -191,15 +196,15 @@ lines * LF end # NOTE embedded is used for AsciiDoc table cell content - def embedded node + def convert_embedded node node.content end - def section node + def convert_section node hlevel = node.level + 1 epub_type_attr = node.special ? %( epub:type="#{node.sectname}") : '' div_classes = [%(sect#{node.level}), node.role].compact title = node.title title_sanitized = xml_sanitize title @@ -213,40 +218,40 @@ node.content end end # TODO: support use of quote block as abstract - def preamble node + def convert_preamble node if (first_block = node.blocks[0]) && first_block.style == 'abstract' - abstract first_block + convert_abstract first_block # REVIEW: should we treat the preamble as an abstract in general? elsif first_block && node.blocks.size == 1 - abstract first_block + convert_abstract first_block else node.content end end - def open node + def convert_open node id_attr = node.id ? %( id="#{node.id}") : nil class_attr = node.role ? %( class="#{node.role}") : nil if id_attr || class_attr %(<div#{id_attr}#{class_attr}> -#{convert_content node} +#{output_content node} </div>) else - convert_content node + output_content node end end - def abstract node + def convert_abstract node %(<div class="abstract" epub:type="preamble"> -#{convert_content node} +#{output_content node} </div>) end - def paragraph node + def convert_paragraph node role = node.role # stack-head is the alternative to the default, inline-head (where inline means "run-in") head_stop = node.attr 'head-stop', (role && (node.has_role? 'stack-head') ? nil : '.') head = node.title? ? %(<strong class="head">#{title = node.title}#{head_stop && title !~ TrailingPunctRx ? head_stop : ''}</strong> ) : '' if role @@ -255,20 +260,20 @@ else %(<p>#{head}#{node.content}</p>) end end - def pass node + def convert_pass node content = node.content if content == '<?hard-pagebreak?>' '<hr epub:type="pagebreak" class="pagebreak"/>' else content end end - def admonition node + def convert_admonition node id_attr = node.id ? %( id="#{node.id}") : '' if node.title? title = node.title title_sanitized = xml_sanitize title title_attr = %( title="#{node.caption}: #{title_sanitized}") @@ -288,33 +293,33 @@ when 'important', 'warning', 'caution' 'warning' end %(<aside#{id_attr} class="admonition #{type}"#{title_attr} epub:type="#{epub_type}"> #{title_el}<div class="content"> -#{convert_content node} +#{output_content node} </div> </aside>) end - def example node + def convert_example node id_attr = node.id ? %( id="#{node.id}") : '' title_div = node.title? ? %(<div class="example-title">#{node.title}</div> ) : '' %(<div#{id_attr} class="example"> #{title_div}<div class="example-content"> -#{convert_content node} +#{output_content node} </div> </div>) end - def floating_title node + def convert_floating_title node tag_name = %(h#{node.level + 1}) id_attribute = node.id ? %( id="#{node.id}") : '' %(<#{tag_name}#{id_attribute} class="#{['discrete', node.role].compact * ' '}">#{node.title}</#{tag_name}>) end - def listing node + def convert_listing node figure_classes = ['listing'] figure_classes << 'coalesce' if node.option? 'unbreakable' pre_classes = node.style == 'source' ? ['source', %(language-#{node.attr 'language'})] : ['screen'] title_div = node.title? ? %(<figcaption>#{node.captioned_title}</figcaption> ) : '' @@ -324,23 +329,23 @@ #{title_div}<pre class="#{pre_classes * ' '}"><code>#{(node.content || '').gsub(/(?<! )<i class="conum"| +<i class="conum"/, ' <i class="conum"')}</code></pre> </figure>) end # QUESTION should we wrap the <pre> in either <div> or <figure>? - def literal node + def convert_literal node %(<pre class="screen">#{node.content}</pre>) end - def page_break _node + def convert_page_break _node '<hr epub:type="pagebreak" class="pagebreak"/>' end - def thematic_break _node + def convert_thematic_break _node '<hr class="thematicbreak"/>' end - def quote node + def convert_quote node id_attr = %( id="#{node.id}") if node.id class_attr = (role = node.role) ? %( class="blockquote #{role}") : ' class="blockquote"' footer_content = [] if (attribution = node.attr 'attribution') @@ -354,19 +359,19 @@ footer_content << %(<span class="context">#{node.title}</span>) if node.title? footer_tag = footer_content.empty? ? '' : %( <footer>~ #{footer_content * ' '}</footer>) - content = (convert_content node).strip + content = (output_content node).strip %(<div#{id_attr}#{class_attr}> <blockquote> #{content}#{footer_tag} </blockquote> </div>) end - def verse node + def convert_verse node id_attr = %( id="#{node.id}") if node.id class_attr = (role = node.role) ? %( class="verse #{role}") : ' class="verse"' footer_content = [] if (attribution = node.attr 'attribution') @@ -383,11 +388,11 @@ %(<div#{id_attr}#{class_attr}> <pre>#{node.content}#{footer_tag}</pre> </div>) end - def sidebar node + def convert_sidebar node classes = ['sidebar'] if node.title? classes << 'titled' title = node.title title_sanitized = xml_sanitize title @@ -398,16 +403,16 @@ title_attr = title_el = '' end %(<aside class="#{classes * ' '}"#{title_attr} epub:type="sidebar"> #{title_el}<div class="content"> -#{convert_content node} +#{output_content node} </div> </aside>) end - def table node + def convert_table node lines = [%(<div class="table">)] lines << %(<div class="content">) table_id_attr = node.id ? %( id="#{node.id}") : '' frame_class = { 'all' => 'table-framed', @@ -491,11 +496,11 @@ </div> </div>' lines * LF end - def colist node + def convert_colist node lines = ['<div class="callout-list"> <ol>'] num = CalloutStartNum node.items.each_with_index do |item, i| lines << %(<li><i class="conum" data-value="#{i + 1}">#{num}</i> #{item.text}</li>) @@ -504,11 +509,11 @@ lines << '</ol> </div>' end # TODO: add complex class if list has nested blocks - def dlist node + def convert_dlist node lines = [] case (style = node.style) when 'itemized', 'ordered' list_tag_name = style == 'itemized' ? 'ul' : 'ol' role = node.role @@ -558,11 +563,11 @@ </div>' end lines * LF end - def olist node + def convert_olist node complex = false div_classes = ['ordered-list', node.style, node.role].compact ol_classes = [node.style, ((node.option? 'brief') ? 'brief' : nil)].compact ol_class_attr = ol_classes.empty? ? '' : %( class="#{ol_classes * ' '}") ol_start_attr = (node.attr? 'start') ? %( start="#{node.attr 'start'}") : '' @@ -586,11 +591,11 @@ lines << '</ol> </div>' lines * LF end - def ulist node + def convert_ulist node complex = false div_classes = ['itemized-list', node.style, node.role].compact ul_classes = [node.style, ((node.option? 'brief') ? 'brief' : nil)].compact ul_class_attr = ul_classes.empty? ? '' : %( class="#{ul_classes * ' '}") id_attribute = node.id ? %( id="#{node.id}") : '' @@ -613,11 +618,11 @@ lines << '</ul> </div>' lines * LF end - def image node + def convert_image node target = node.attr 'target' type = (::File.extname target)[1..-1] id_attr = node.id ? %( id="#{node.id}") : '' img_attrs = [%(alt="#{node.attr 'alt'}")] case type @@ -652,11 +657,11 @@ </div>#{node.title? ? %( <figcaption>#{node.captioned_title}</figcaption>) : ''} </figure>) end - def inline_anchor node + def convert_inline_anchor node target = node.target case node.type when :xref # TODO: would be helpful to know what type the target is (e.g., bibref) doc, refid, text, path = node.document, ((node.attr 'refid') || target), node.text, (node.attr 'path') # NOTE if path is non-nil, we have an inter-document xref @@ -720,34 +725,34 @@ %(<a id="#{target}"></a>[#{target}]) end end end - def inline_break node + def convert_inline_break node %(#{node.text}<br/>) end - def inline_button node + def convert_inline_button node %(<b class="button">[<span class="label">#{node.text}</span>]</b>) end - def inline_callout node + def convert_inline_callout node num = CalloutStartNum int_num = node.text.to_i (int_num - 1).times { num = num.next } %(<i class="conum" data-value="#{int_num}">#{num}</i>) end - def inline_footnote node + def convert_inline_footnote node if (index = node.attr 'index') %(<sup class="noteref">[<a id="noteref-#{index}" href="#note-#{index}" epub:type="noteref">#{index}</a>]</sup>) elsif node.type == :xref %(<mark class="noteref" title="Unresolved note reference">#{node.text}</mark>) end end - def inline_image node + def convert_inline_image node if node.type == 'icon' @icon_names << (icon_name = node.target) i_classes = ['icon', %(i-#{icon_name})] i_classes << %(icon-#{node.attr 'size'}) if node.attr? 'size' i_classes << %(icon-flip-#{(node.attr 'flip')[0]}) if node.attr? 'flip' @@ -767,24 +772,24 @@ end %(<img src="#{target}" #{img_attrs * ' '}/>) end end - def inline_indexterm node + def convert_inline_indexterm node node.type == :visible ? node.text : '' end - def inline_kbd node + def convert_inline_kbd node if (keys = node.attr 'keys').size == 1 %(<kbd>#{keys[0]}</kbd>) else key_combo = keys.map {|key| %(<kbd>#{key}</kbd>) }.join '+' %(<span class="keyseq">#{key_combo}</span>) end end - def inline_menu node + def convert_inline_menu node menu = node.attr 'menu' # NOTE we swap right angle quote with chevron right from FontAwesome using CSS caret = %(#{NoBreakSpace}<span class="caret">#{RightAngleQuote}</span> ) if !(submenus = node.attr 'submenus').empty? submenu_path = submenus.map {|submenu| %(<span class="submenu">#{submenu}</span>#{caret}) }.join.chop @@ -794,11 +799,11 @@ else %(<span class="menu">#{menu}</span>) end end - def inline_quoted node + def convert_inline_quoted node case node.type when :strong %(<strong>#{node.text}</strong>) when :emphasis %(<em>#{node.text}</em>) @@ -817,11 +822,11 @@ else node.text end end - def convert_content node + def output_content node node.content_model == :simple ? %(<p>#{node.content}</p>) : node.content end # FIXME: merge into with xml_sanitize helper def xml_sanitize value, target = :attribute @@ -913,10 +918,11 @@ Extensions.register do if (document = @document).backend == 'epub3' document.attributes['spine'] = '' document.set_attribute 'listing-caption', 'Listing' - if !(defined? ::JRuby) && (::Gem.try_activate 'pygments.rb') + # pygments.rb hangs on JRuby for Windows, see https://github.com/asciidoctor/asciidoctor-epub3/issues/253 + if !(::RUBY_ENGINE == 'jruby' && Gem.win_platform?) && (Gem.try_activate 'pygments.rb') if document.set_attribute 'source-highlighter', 'pygments' document.set_attribute 'pygments-css', 'style' document.set_attribute 'pygments-style', 'bw' end end