فهرست منبع

template: add templates/slim/html5 files

Travis 9 سال پیش
والد
کامیت
f61b5e5810
47فایلهای تغییر یافته به همراه974 افزوده شده و 0 حذف شده
  1. 10 0
      src/templates/slim/html5/_attribution.html.slim
  2. 9 0
      src/templates/slim/html5/_footer.html.slim
  3. 6 0
      src/templates/slim/html5/_footnotes.html.slim
  4. 20 0
      src/templates/slim/html5/_hdlist.html.slim
  5. 29 0
      src/templates/slim/html5/_header.html.slim
  6. 11 0
      src/templates/slim/html5/_qanda.html.slim
  7. 4 0
      src/templates/slim/html5/_toc.html.slim
  8. 13 0
      src/templates/slim/html5/block_admonition.html.slim
  9. 8 0
      src/templates/slim/html5/block_audio.html.slim
  10. 16 0
      src/templates/slim/html5/block_colist.html.slim
  11. 17 0
      src/templates/slim/html5/block_dlist.html.slim
  12. 2 0
      src/templates/slim/html5/block_example.html.slim
  13. 1 0
      src/templates/slim/html5/block_floating_title.html.slim
  14. 2 0
      src/templates/slim/html5/block_iframe.html.slim
  15. 4 0
      src/templates/slim/html5/block_image.html.slim
  16. 23 0
      src/templates/slim/html5/block_listing.html.slim
  17. 2 0
      src/templates/slim/html5/block_literal.html.slim
  18. 7 0
      src/templates/slim/html5/block_olist.html.slim
  19. 7 0
      src/templates/slim/html5/block_open.html.slim
  20. 9 0
      src/templates/slim/html5/block_outline.html.slim
  21. 1 0
      src/templates/slim/html5/block_page_break.html.slim
  22. 2 0
      src/templates/slim/html5/block_paragraph.html.slim
  23. 1 0
      src/templates/slim/html5/block_pass.html.slim
  24. 4 0
      src/templates/slim/html5/block_preamble.html.slim
  25. 3 0
      src/templates/slim/html5/block_quote.html.slim
  26. 5 0
      src/templates/slim/html5/block_sidebar.html.slim
  27. 2 0
      src/templates/slim/html5/block_stem.html.slim
  28. 36 0
      src/templates/slim/html5/block_table.html.slim
  29. 1 0
      src/templates/slim/html5/block_thematic_break.html.slim
  30. 8 0
      src/templates/slim/html5/block_toc.html.slim
  31. 24 0
      src/templates/slim/html5/block_ulist.html.slim
  32. 3 0
      src/templates/slim/html5/block_verse.html.slim
  33. 19 0
      src/templates/slim/html5/block_video.html.slim
  34. 28 0
      src/templates/slim/html5/document.html.slim
  35. 5 0
      src/templates/slim/html5/embedded.html.slim
  36. 532 0
      src/templates/slim/html5/helpers.rb
  37. 10 0
      src/templates/slim/html5/inline_anchor.html.slim
  38. 2 0
      src/templates/slim/html5/inline_break.html.slim
  39. 1 0
      src/templates/slim/html5/inline_button.html.slim
  40. 7 0
      src/templates/slim/html5/inline_callout.html.slim
  41. 11 0
      src/templates/slim/html5/inline_footnote.html.slim
  42. 9 0
      src/templates/slim/html5/inline_image.html.slim
  43. 2 0
      src/templates/slim/html5/inline_indexterm.html.slim
  44. 8 0
      src/templates/slim/html5/inline_kbd.html.slim
  45. 10 0
      src/templates/slim/html5/inline_menu.html.slim
  46. 26 0
      src/templates/slim/html5/inline_quoted.html.slim
  47. 14 0
      src/templates/slim/html5/section.html.slim

+ 10 - 0
src/templates/slim/html5/_attribution.html.slim

@@ -0,0 +1,10 @@
+- attribution = attr :attribution
+- citetitle = attr :citetitle
+- if attribution || citetitle
+  .attribution
+    - if attribution
+      |— #{attribution}
+    - if citetitle
+      - if attribution
+        br
+      cite =citetitle

+ 9 - 0
src/templates/slim/html5/_footer.html.slim

@@ -0,0 +1,9 @@
+#footer
+  #footer-text
+    - if attr? :revnumber
+      |#{attr 'version-label'} #{attr :revnumber}
+    - if attr? 'last-update-label'
+      br
+      |#{attr 'last-update-label'} #{attr :docdatetime}
+  - unless (docinfo_content = (docinfo :footer)).empty?
+    =docinfo_content

+ 6 - 0
src/templates/slim/html5/_footnotes.html.slim

@@ -0,0 +1,6 @@
+#footnotes
+  hr
+  - footnotes.each do |fn|
+    .footnote id=(footnote_id fn.index)
+      a href="##{footnoteref_id fn.index}" =fn.index
+      |. #{fn.text}

+ 20 - 0
src/templates/slim/html5/_hdlist.html.slim

@@ -0,0 +1,20 @@
+= block_with_title 'hdlist'
+  table
+    - if (attr? :labelwidth) || (attr? :itemwidth)
+      colgroup
+        col style=style_value(width: [(attr :labelwidth), '%'])
+        col style=style_value(width: [(attr :itemwidth), '%'])
+    - items.each do |terms, dd|
+      tr
+        td class=['hdlist1', ('strong' if option? 'strong')]
+          - terms = [*terms]
+          - terms.each_with_index do |dt, idx|
+            =dt.text
+            - unless idx >= terms.count - 1
+              br
+        td.hdlist2
+          - unless dd.nil?
+            - if dd.text?
+              p =dd.text
+            - if dd.blocks?
+              =dd.content

+ 29 - 0
src/templates/slim/html5/_header.html.slim

@@ -0,0 +1,29 @@
+/ AsciiDoc leaves an empty header div even if there's no doctitle
+#header
+  - if has_header?
+    - unless notitle
+      h1 = header.title
+    - if [:author, :revnumber, :revdate, :revremark].any? {|a| attr? a }
+      .details
+        - if attr? :author
+          span.author#author =(attr :author)
+          br
+          - if attr? :email
+            span.email#email =sub_macros(attr :email)
+            br
+          - if (authorcount = (attr :authorcount).to_i) > 1
+            - (2..authorcount).each do |idx|
+              span.author id="author#{idx}" =(attr "author_#{idx}")
+              br
+              - if attr? "email_#{idx}"
+                span.email id="email#{idx}" =sub_macros(attr "email_#{idx}")
+        - if attr? :revnumber
+          span#revnumber #{((attr 'version-label') || '').downcase} #{attr :revnumber}#{',' if attr? :revdate}
+          '
+        - if attr? :revdate
+          span#revdate =attr :revdate
+        - if attr? :revremark
+          br
+          span#revremark =(attr :revremark)
+  - if (attr? :toc) && (attr? 'toc-placement', 'auto')
+    include _toc.html

+ 11 - 0
src/templates/slim/html5/_qanda.html.slim

@@ -0,0 +1,11 @@
+= block_with_title 'qlist qanda'
+  ol
+    - items.each do |questions, answer|
+      li
+        - [*questions].each do |question|
+          p: em =question.text
+        - unless answer.nil?
+          - if answer.text?
+            p =answer.text
+          - if answer.blocks?
+            =answer.content

+ 4 - 0
src/templates/slim/html5/_toc.html.slim

@@ -0,0 +1,4 @@
+#toc class=(attr 'toc-class', 'toc')
+  #toctitle =(attr 'toc-title')
+  / Renders block_outline.html.
+  = converter.convert document, 'outline'

+ 13 - 0
src/templates/slim/html5/block_admonition.html.slim

@@ -0,0 +1,13 @@
+.admonitionblock id=id class=[(attr :name), role]
+  table: tr
+    td.icon
+      - if font_icons?
+        i class=%(fa icon-#{attr :name}) title=caption
+      - elsif icons?
+        img src=icon_uri(attr :name) alt=caption
+      - else
+        .title =caption
+    td.content
+      - if title?
+        .title =title
+      =content

+ 8 - 0
src/templates/slim/html5/block_audio.html.slim

@@ -0,0 +1,8 @@
+= block_with_title class: ['audioblock', style]
+  .content
+    audio(
+        src=media_uri(attr :target)
+        autoplay=(option? 'autoplay')
+        controls=!(option? 'nocontrols')
+        loop=(option? 'loop'))
+      |Your browser does not support the audio tag.

+ 16 - 0
src/templates/slim/html5/block_colist.html.slim

@@ -0,0 +1,16 @@
+= block_with_title class: ['colist', style]
+  - if icons?
+    table
+      - items.to_enum.with_index 1 do |item, num|
+        tr
+          td
+            - if font_icons?
+              i.conum data-value=num
+              b =num
+            - else
+              img src=(icon_uri "callouts/#{num}") alt=num
+          td =item.text
+  - else
+    ol
+      - items.each do |item|
+        li: p =item.text

+ 17 - 0
src/templates/slim/html5/block_dlist.html.slim

@@ -0,0 +1,17 @@
+- case style
+- when 'qanda'
+  include _qanda.html
+- when 'horizontal'
+  include _hdlist.html
+- else
+  = block_with_title class: ['dlist', style]
+    dl
+      - items.each do |terms, dd|
+        - [*terms].each do |dt|
+          dt class=('hdlist1' unless style) =dt.text
+        - unless dd.nil?
+          dd
+            - if dd.text?
+              p =dd.text
+            - if dd.blocks?
+              =dd.content

+ 2 - 0
src/templates/slim/html5/block_example.html.slim

@@ -0,0 +1,2 @@
+= block_with_title 'exampleblock'
+  .content =content

+ 1 - 0
src/templates/slim/html5/block_floating_title.html.slim

@@ -0,0 +1 @@
+*{tag: %(h#{level + 1}), id: id, class: [style, role].compact} =title

+ 2 - 0
src/templates/slim/html5/block_iframe.html.slim

@@ -0,0 +1,2 @@
+= html_tag_if (attr? :link), :a, {class: 'iframe', href: (attr :link)}
+  iframe src=image_uri(attr :target) alt=(attr :alt) width=(attr :width) height=(attr :height) scroll=(attr :scroll) border=(attr :border) align=(attr: align)

+ 4 - 0
src/templates/slim/html5/block_image.html.slim

@@ -0,0 +1,4 @@
+= block_with_title({class: 'imageblock', style: (style_value text_align: (attr :align), float: (attr :float))}, :bottom)
+  .content
+    = html_tag_if (attr? :link), :a, {class: 'image', href: (attr :link)}
+      img src=image_uri(attr :target) alt=(attr :alt) width=(attr :width) height=(attr :height)

+ 23 - 0
src/templates/slim/html5/block_listing.html.slim

@@ -0,0 +1,23 @@
+= block_with_title 'listingblock'
+  .content
+    - highlighter = document.attr 'source-highlighter'
+    - if style == 'source' && highlighter == 'html-pipeline'
+      pre lang=source_lang
+        code =content
+    - elsif style == 'source'
+      - code_class = "language-#{source_lang}" if source_lang
+      - case highlighter
+      - when 'coderay'
+        - pre_class = 'CodeRay'
+        - code_class = nil
+      - when 'highlight.js'
+        - pre_class = 'highlightjs'
+      - when 'prettify'
+        - pre_class = 'prettyprint'
+      - when 'pygments'
+        - pre_class = 'pygments'
+        - code_class = nil
+      pre class=[pre_class, 'highlight', ('linenums' if attr? :linenums), nowrap?]
+        code class=code_class data-lang=source_lang =content
+    - else
+      pre class=nowrap? =content

+ 2 - 0
src/templates/slim/html5/block_literal.html.slim

@@ -0,0 +1,2 @@
+= block_with_title 'literalblock'
+  .content: pre class=nowrap? =content

+ 7 - 0
src/templates/slim/html5/block_olist.html.slim

@@ -0,0 +1,7 @@
+= block_with_title class: ['olist', style]
+  ol class=style start=(attr :start) type=list_marker_keyword
+    - items.each do |item|
+      li
+        p =item.text
+        - if item.blocks?
+          =item.content

+ 7 - 0
src/templates/slim/html5/block_open.html.slim

@@ -0,0 +1,7 @@
+- if style == 'abstract'
+  - if abstract_allowed?
+    = block_with_title 'quoteblock abstract'
+      blockquote =content
+- elsif style != 'partintro' || partintro_allowed?
+  = block_with_title class: ['openblock', (style if style != 'open')]
+    .content =content

+ 9 - 0
src/templates/slim/html5/block_outline.html.slim

@@ -0,0 +1,9 @@
+- unless sections.empty?
+  - toclevels ||= (document.attr 'toclevels', DEFAULT_TOCLEVELS).to_i
+  - slevel = section_level sections.first
+  ul class="sectlevel#{slevel}"
+    - sections.each do |sec|
+      li
+        a href="##{sec.id}" =section_title sec
+        - if (sec.level < toclevels) && (child_toc = converter.convert sec, 'outline')
+          = child_toc

+ 1 - 0
src/templates/slim/html5/block_page_break.html.slim

@@ -0,0 +1 @@
+div style='page-break-after: always;'

+ 2 - 0
src/templates/slim/html5/block_paragraph.html.slim

@@ -0,0 +1,2 @@
+= block_with_title 'paragraph'
+  p =content

+ 1 - 0
src/templates/slim/html5/block_pass.html.slim

@@ -0,0 +1 @@
+=content

+ 4 - 0
src/templates/slim/html5/block_preamble.html.slim

@@ -0,0 +1,4 @@
+#preamble
+  .sectionbody =content
+  - if (attr? :toc) && (attr? 'toc-placement', 'preamble')
+    include _toc.html

+ 3 - 0
src/templates/slim/html5/block_quote.html.slim

@@ -0,0 +1,3 @@
+= block_with_title 'quoteblock'
+  blockquote =content
+  include _attribution.html

+ 5 - 0
src/templates/slim/html5/block_sidebar.html.slim

@@ -0,0 +1,5 @@
+.sidebarblock id=id class=role
+  .content
+    - if title?
+      .title =title
+    =content

+ 2 - 0
src/templates/slim/html5/block_stem.html.slim

@@ -0,0 +1,2 @@
+= block_with_title 'stemblock'
+  .content =(delimit_stem content, style)

+ 36 - 0
src/templates/slim/html5/block_table.html.slim

@@ -0,0 +1,36 @@
+table(id=id
+      class=['tableblock', "frame-#{attr :frame, 'all'}", "grid-#{attr :grid, 'all'}", spread?, role]
+      style=style_value(width: ("#{attr :tablepcwidth}%" unless autowidth? || spread?), float: (attr :float)))
+  - if title?
+    caption.title =captioned_title
+  - unless (attr :rowcount).zero?
+    colgroup
+      - if autowidth?
+        - columns.each do
+          col
+      - else
+        - columns.each do |col|
+          col style="width: #{col.attr :colpcwidth}%;"
+    - [:head, :foot, :body].reject { |tblsec| rows[tblsec].empty? }.each do |tblsec|
+      *{tag: %(t#{tblsec})}
+        - rows[tblsec].each do |row|
+          tr
+            - row.each do |cell|
+              *{tag: (tblsec == :head || cell.style == :header ? 'th' : 'td'),
+                  class: ['tableblock', "halign-#{cell.attr :halign}", "valign-#{cell.attr :valign}"],
+                  colspan: cell.colspan,
+                  rowspan: cell.rowspan,
+                  style: style_value(background_color: (document.attr :cellbgcolor))}
+                - if tblsec == :head
+                  =cell.text
+                - else
+                  - case cell.style
+                  - when :asciidoc
+                    div =cell.content
+                  - when :verse
+                    .verse =cell.text
+                  - when :literal
+                    .literal: pre =cell.text
+                  - else
+                    - cell.content.each do |text|
+                      p.tableblock =text

+ 1 - 0
src/templates/slim/html5/block_thematic_break.html.slim

@@ -0,0 +1 @@
+hr

+ 8 - 0
src/templates/slim/html5/block_toc.html.slim

@@ -0,0 +1,8 @@
+/ This template is used only for toc::[] macro; for document and preamble TOC
+/ see document.html, preamble.html and _toc.html.
+- if document.attr? :toc
+  - toc_id = id || ('toc' if document.embedded? || !document.attr?('toc-placement'))
+  div id=toc_id class=(attr :role, (document.attr 'toc-class', 'toc'))
+    .title id=(%(#{toc_id}title) if toc_id) =(title || (document.attr 'toc-title'))
+    / Renders block_outline.html.
+    = converter.convert_with_options document, 'outline', toclevels: ((attr :levels).to_i if attr? :levels)

+ 24 - 0
src/templates/slim/html5/block_ulist.html.slim

@@ -0,0 +1,24 @@
+- if (checklist = 'checklist' if option? 'checklist')
+  - if option? 'interactive'
+    - marker_checked = html_tag 'input', :type=>'checkbox', 'data-item-complete'=>'1', :checked=>true
+    - marker_unchecked = html_tag 'input', :type=>'checkbox', 'data-item-complete'=>'0'
+  - elsif font_icons?
+    - marker_checked = html_tag 'i', class: 'fa fa-check-square-o'
+    - marker_unchecked = html_tag 'i', class: 'fa fa-square-o'
+  - else
+    - marker_checked = '&#10003;'
+    - marker_unchecked = '&#10063;'
+= block_with_title class: ['ulist', checklist, style]
+  ul class=(checklist || style)
+    - items.each do |item|
+      li
+        p
+          - if checklist && (item.attr? :checkbox)
+            - if item.attr? :checked
+              |#{marker_checked} #{item.text}
+            - else
+              |#{marker_unchecked} #{item.text}
+          - else
+            =item.text
+        - if item.blocks?
+          =item.content

+ 3 - 0
src/templates/slim/html5/block_verse.html.slim

@@ -0,0 +1,3 @@
+= block_with_title 'verseblock'
+  pre.content =content
+  include _attribution.html

+ 19 - 0
src/templates/slim/html5/block_video.html.slim

@@ -0,0 +1,19 @@
+= block_with_title class: ['videoblock', style]
+  .content
+    - if video_iframe?
+      iframe(
+          src=video_uri
+          width=(attr :width)
+          height=(attr :height)
+          frameborder=0
+          allowfullscreen=!(option? 'nofullscreen'))
+    - else
+      video(
+          src=video_uri
+          width=(attr :width)
+          height=(attr :height)
+          poster=(media_uri(attr :poster) if attr? :poster)
+          autoplay=(option? 'autoplay')
+          controls=!(option? 'nocontrols')
+          loop=(option? 'loop'))
+        |Your browser does not support the video tag.

+ 28 - 0
src/templates/slim/html5/document.html.slim

@@ -0,0 +1,28 @@
+doctype 5
+html lang=(attr :lang, 'en' unless attr? :nolang)
+  head
+    meta charset=(attr :encoding, 'UTF-8')
+    /[if IE]
+      meta http-equiv="X-UA-Compatible" content="IE=edge"
+    meta name='viewport' content='width=device-width, initial-scale=1.0'
+    meta name='generator' content="Asciidoctor #{attr 'asciidoctor-version'}"
+    = html_meta_if 'application-name', (attr 'app-name')
+    = html_meta_if 'author', (attr :authors)
+    = html_meta_if 'copyright', (attr :copyright)
+    = html_meta_if 'description', (attr :description)
+    = html_meta_if 'keywords', (attr :keywords)
+    title=((doctitle sanitize: true) || (attr 'untitled-label'))
+    = styles_and_scripts
+    - unless (docinfo_content = docinfo).empty?
+      =docinfo_content
+  body(
+    id=id
+    class=[(attr :doctype), ("#{attr 'toc-class'} toc-#{attr 'toc-position', 'left'}" if (attr? 'toc-class') && (attr? :toc) && (attr? 'toc-placement', 'auto'))]
+    style=style_value(max_width: (attr 'max-width')))
+    - unless noheader
+      include _header.html
+    #content =content
+    - unless !footnotes? || (attr? :nofootnotes)
+      include _footnotes.html
+    - unless nofooter
+      include _footer.html

+ 5 - 0
src/templates/slim/html5/embedded.html.slim

@@ -0,0 +1,5 @@
+- unless notitle || !has_header?
+  h1 id=id =header.title
+=content
+- unless !footnotes? || (attr? :nofootnotes)
+  include _footnotes.html

+ 532 - 0
src/templates/slim/html5/helpers.rb

@@ -0,0 +1,532 @@
+require 'asciidoctor'
+require 'json'
+
+if Gem::Version.new(Asciidoctor::VERSION) <= Gem::Version.new('1.5.1')
+  fail 'asciidoctor: FAILED: HTML5/Slim backend needs Asciidoctor >=1.5.2!'
+end
+
+unless defined? Slim::Include
+  fail 'asciidoctor: FAILED: HTML5/Slim backend needs Slim >= 2.1.0!'
+end
+
+# Add custom functions to this module that you want to use in your Slim
+# templates. Within the template you can invoke them as top-level functions
+# just like in Haml.
+module Slim::Helpers
+
+  # URIs of external assets.
+  FONT_AWESOME_URI     = '//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.5.0/css/font-awesome.min.css'
+  HIGHLIGHTJS_BASE_URI = '//cdnjs.cloudflare.com/ajax/libs/highlight.js/7.4'
+  MATHJAX_JS_URI       = '//cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-MML-AM_HTMLorMML'
+  PRETTIFY_BASE_URI    = '//cdnjs.cloudflare.com/ajax/libs/prettify/r298'
+
+  # Defaults
+  DEFAULT_HIGHLIGHTJS_THEME = 'github'
+  DEFAULT_PRETTIFY_THEME = 'prettify'
+  DEFAULT_SECTNUMLEVELS = 3
+  DEFAULT_TOCLEVELS = 2
+
+  # The MathJax configuration.
+  MATHJAX_CONFIG = {
+    tex2jax: {
+      inlineMath:  [::Asciidoctor::INLINE_MATH_DELIMITERS[:latexmath]],
+      displayMath: [::Asciidoctor::BLOCK_MATH_DELIMITERS[:latexmath]],
+      ignoreClass: 'nostem|nolatexmath'
+    },
+    asciimath2jax: {
+      delimiters:  [::Asciidoctor::BLOCK_MATH_DELIMITERS[:asciimath]],
+      ignoreClass: 'nostem|noasciimath'
+    }
+  }.to_json
+
+  VOID_ELEMENTS = %w(area base br col command embed hr img input keygen link meta param source track wbr)
+
+
+  ##
+  # Creates an HTML tag with the given name and optionally attributes. Can take
+  # a block that will run between the opening and closing tags.
+  #
+  # @param name [#to_s] the name of the tag.
+  # @param attributes [Hash]
+  # @param content [#to_s] the content; +nil+ to call the block.
+  # @yield The block of Slim/HTML code within the tag (optional).
+  # @return [String] a rendered HTML element.
+  #
+  def html_tag(name, attributes = {}, content = nil)
+    attrs = attributes.reject { |_, v|
+      v.nil? || (v.respond_to?(:empty?) && v.empty?)
+    }.map do |k, v|
+      v = v.compact.join(' ') if v.is_a? Array
+      v = nil if v == true
+      v = %("#{v}") if v
+      [k, v] * '='
+    end
+    attrs_str = attrs.empty? ? '' : attrs.join(' ').prepend(' ')
+
+    if VOID_ELEMENTS.include? name.to_s
+      %(<#{name}#{attrs_str}>)
+    else
+      content ||= yield if block_given?
+      %(<#{name}#{attrs_str}>#{content}</#{name}>)
+    end
+  end
+
+  ##
+  # Conditionally wraps a block in an element. If condition is +true+ then it
+  # renders the specified tag with optional attributes and the given
+  # block inside, otherwise it just renders the block.
+  #
+  # For example:
+  #
+  #    = html_tag_if link?, 'a', {class: 'image', href: (attr :link)}
+  #      img src='./img/tux.png'
+  #
+  # will produce:
+  #
+  #    <a href="http://example.org" class="image">
+  #      <img src="./img/tux.png">
+  #    </a>
+  #
+  # if +link?+ is truthy, and just
+  #
+  #   <img src="./img/tux.png">
+  #
+  # otherwise.
+  #
+  # @param condition [Boolean] the condition to test to determine whether to
+  #        render the enclosing tag.
+  # @param name (see #html_tag)
+  # @param attributes (see #html_tag)
+  # @yield (see #html_tag)
+  # @return [String] a rendered HTML fragment.
+  #
+  def html_tag_if(condition, name, attributes = {}, &block)
+    if condition
+      html_tag name, attributes, &block
+    else
+      yield
+    end
+  end
+
+  ##
+  # Surrounds a block with strings, with no whitespace in between.
+  #
+  # @example
+  #   = surround '[', ']' do
+  #     a href="#_footnote_1" 1
+  #
+  #   [<a href="#_footnote_1">1</a>]
+  #
+  # @param front [String] the string to add before the block.
+  # @param back [String] the string to add after the block.
+  # @yield The block of Slim/HTML code to surround.
+  # @return [String] a rendered HTML fragment.
+  #
+  def surround(front, back = front)
+    [front, yield.chomp, back].join
+  end
+
+  ##
+  # Wraps a block in a div element with the specified class and optionally
+  # the node's +id+ and +role+(s). If the node's +captioned_title+ is not
+  # empty, than a nested div with the class "title" and the title's content
+  # is added as well.
+  #
+  # Note: Every node has method +captioned_title+; if it doesn't have a
+  # caption, then this method returns just a naked title.
+  #
+  # @example When @id, @role and @title attributes are set.
+  #   = block_with_title class: ['quoteblock', 'center']
+  #     blockquote =content
+  #
+  #   <div id="myid" class="quoteblock center myrole1 myrole2">
+  #     <div class="title">Block Title</div>
+  #     <blockquote>Lorem ipsum</blockquote>
+  #   </div>
+  #
+  # @example When @id, @role and @title attributes are empty.
+  #   = block_with_title class: 'quoteblock center', style: style_value(float: 'left')
+  #     blockquote =content
+  #
+  #   <div class="quoteblock center" style="float: left;">
+  #     <blockquote>Lorem ipsum</blockquote>
+  #   </div>
+  #
+  # @example When shorthand style for class attribute is used.
+  #   = block_with_title 'quoteblock center'
+  #     blockquote =content
+  #
+  #   <div class="quoteblock center">
+  #     <blockquote>Lorem ipsum</blockquote>
+  #   </div>
+  #
+  # @param attributes [Hash, String] the tag's attributes as Hash),
+  #        or the tag's class if it's not a Hash.
+  # @param title_position [:top, :bottom] position of the title element.
+  # @yield The block of Slim/HTML code within the tag (optional).
+  # @return [String] a rendered HTML fragment.
+  #
+  def block_with_title(attributes = {}, title_position = :top, &block)
+    if attributes.is_a? Hash
+      klass = attributes.delete(:class)
+    else
+      klass = attributes
+      attributes = {}
+    end
+    klass = klass.split(' ') if klass.is_a? String
+    attributes[:class] = [klass, role].flatten.uniq
+    attributes[:id] = id
+
+    html_tag 'div', attributes do
+      if captioned_title.nil_or_empty?
+        yield
+      else
+        ary = [ html_tag('div', {class: 'title'}, captioned_title), yield ]
+        ary.reverse! if title_position == :bottom
+        ary.compact.join "\n"
+      end
+    end
+  end
+
+  ##
+  # Delimite the given equation as a STEM of the specified type.
+  #
+  # @param equation [String] the equation to delimite.
+  # @param type [#to_sym] the type of the STEM renderer (latexmath, or asciimath).
+  # @return [String] the delimited equation.
+  #
+  def delimit_stem(equation, type)
+    if is_a? ::Asciidoctor::Block
+      open, close = ::Asciidoctor::BLOCK_MATH_DELIMITERS[type.to_sym]
+    else
+      open, close = ::Asciidoctor::INLINE_MATH_DELIMITERS[type.to_sym]
+    end
+
+    unless equation.start_with?(open) && equation.end_with?(close)
+      equation = [open, equation, close].join
+    end
+    equation
+  end
+
+  ##
+  # Formats the given hash as CSS declarations for an inline style.
+  #
+  # @example
+  #   style_value(text_align: 'right', float: 'left')
+  #   => "text-align: right; float: left;"
+  #
+  #   style_value(text_align: nil, float: 'left')
+  #   => "float: left;"
+  #
+  #   style_value(width: [90, '%'], height: '50px')
+  #   => "width: 90%; height: 50px;"
+  #
+  #   style_value(width: ['120px', 'px'])
+  #   => "width: 90px;"
+  #
+  #   style_value(width: [nil, 'px'])
+  #   => nil
+  #
+  # @param declarations [Hash]
+  # @return [String, nil]
+  #
+  def style_value(declarations)
+    decls = []
+
+    declarations.each do |prop, value|
+      next if value.nil?
+
+      if value.is_a? Array
+        value, unit = value
+        next if value.nil?
+        value = value.to_s + unit unless value.end_with? unit
+      end
+      prop = prop.to_s.gsub('_', '-')
+      decls << %(#{prop}: #{value})
+    end
+
+    decls.empty? ? nil : decls.join('; ') + ';'
+  end
+
+  def urlize(*segments)
+    path = segments * '/'
+    if path.start_with? '//'
+      @_uri_scheme ||= document.attr 'asset-uri-scheme', 'https'
+      path = %(#{@_uri_scheme}:#{path}) unless @_uri_scheme.empty?
+    end
+    normalize_web_path path
+  end
+
+
+  ##
+  # @param index [Integer] the footnote's index.
+  # @return [String] footnote id to be used in a link.
+  def footnote_id(index = (attr :index))
+    %(_footnote_#{index})
+  end
+
+  ##
+  # @param index (see #footnote_id)
+  # @return [String] footnoteref id to be used in a link.
+  def footnoteref_id(index = (attr :index))
+    %(_footnoteref_#{index})
+  end
+
+  def icons?
+    document.attr? :icons
+  end
+
+  def font_icons?
+    document.attr? :icons, 'font'
+  end
+
+  def nowrap?
+    'nowrap' if !document.attr?(:prewrap) || option?('nowrap')
+  end
+
+  ##
+  # Returns corrected section level.
+  #
+  # @param sec [Asciidoctor::Section] the section node (default: self).
+  # @return [Integer]
+  #
+  def section_level(sec = self)
+    @_section_level ||= (sec.level == 0 && sec.special) ? 1 : sec.level
+  end
+
+  ##
+  # Returns the captioned section's title, optionally numbered.
+  #
+  # @param sec [Asciidoctor::Section] the section node (default: self).
+  # @return [String]
+  #
+  def section_title(sec = self)
+    sectnumlevels = document.attr(:sectnumlevels, DEFAULT_SECTNUMLEVELS).to_i
+
+    if sec.numbered && !sec.caption && sec.level <= sectnumlevels
+      [sec.sectnum, sec.captioned_title].join(' ')
+    else
+      sec.captioned_title
+    end
+  end
+
+  #--------------------------------------------------------
+  # block_listing
+  #
+
+  def source_lang
+    attr :language, nil, false
+  end
+
+  #--------------------------------------------------------
+  # block_open
+  #
+
+  ##
+  # Returns +true+ if an abstract block is allowed in this document type,
+  # otherwise prints warning and returns +false+.
+  def abstract_allowed?
+    if result = (parent == document && document.doctype == 'book')
+      puts 'asciidoctor: WARNING: abstract block cannot be used in a document without a title when doctype is book. Excluding block content.'
+    end
+    !result
+  end
+
+  ##
+  # Returns +true+ if a partintro block is allowed in this context, otherwise
+  # prints warning and returns +false+.
+  def partintro_allowed?
+    if result = (level != 0 || parent.context != :section || document.doctype != 'book')
+      puts 'asciidoctor: ERROR: partintro block can only be used when doctype is book and it\'s a child of a book part. Excluding block content.'
+    end
+    !result
+  end
+
+  #--------------------------------------------------------
+  # block_table
+  #
+
+  def autowidth?
+    option? :autowidth
+  end
+
+  def spread?
+    'spread' if !(option? 'autowidth') && (attr :tablepcwidth) == 100
+  end
+
+  #--------------------------------------------------------
+  # block_video
+  #
+
+  # @return [Boolean] +true+ if the video should be embedded in an iframe.
+  def video_iframe?
+    ['vimeo', 'youtube'].include?(attr :poster)
+  end
+
+  def video_uri
+    case (attr :poster, '').to_sym
+    when :vimeo
+      params = {
+        autoplay: (1 if option? 'autoplay'),
+        loop: (1 if option? 'loop')
+      }
+      start_anchor = %(#at=#{attr :start}) if attr? :start
+      %(//player.vimeo.com/video/#{attr :target}#{start_anchor}#{url_query params})
+
+    when :youtube
+      video_id, list_id = (attr :target).split('/', 2)
+      params = {
+        rel: 0,
+        start: (attr :start),
+        end: (attr :end),
+        list: (attr :list, list_id),
+        autoplay: (1 if option? 'autoplay'),
+        loop: (1 if option? 'loop'),
+        controls: (0 if option? 'nocontrols')
+      }
+      %(//www.youtube.com/embed/#{video_id}#{url_query params})
+    else
+      anchor = [(attr :start), (attr :end)].join(',').chomp(',')
+      anchor.prepend '#t=' unless anchor.empty?
+      media_uri %(#{attr :target}#{anchor})
+    end
+  end
+
+  # Formats URL query parameters.
+  def url_query(params)
+    str = params.map { |k, v|
+      next if v.nil? || v.to_s.empty?
+      [k, v] * '='
+    }.compact.join('&amp;')
+
+    str.prepend('?') unless str.empty?
+  end
+
+  #--------------------------------------------------------
+  # document
+  #
+
+  ##
+  # Returns HTML meta tag if the given +content+ is not +nil+.
+  #
+  # @param name [#to_s] the name for the metadata.
+  # @param content [#to_s, nil] the value of the metadata, or +nil+.
+  # @return [String, nil] the meta tag, or +nil+ if the +content+ is +nil+.
+  #
+  def html_meta_if(name, content)
+    %(<meta name="#{name}" content="#{content}">) if content
+  end
+
+  # Returns formatted style/link and script tags for header.
+  def styles_and_scripts
+    scripts = []
+    styles = []
+    tags = []
+
+    stylesheet = attr :stylesheet
+    stylesdir = attr :stylesdir, ''
+    default_style = ::Asciidoctor::DEFAULT_STYLESHEET_KEYS.include? stylesheet
+    linkcss = (attr? :linkcss) || safe >= ::Asciidoctor::SafeMode::SECURE
+    ss = ::Asciidoctor::Stylesheets.instance
+
+    if linkcss
+      path = default_style ? ::Asciidoctor::DEFAULT_STYLESHEET_NAME : stylesheet
+      styles << { href: [stylesdir, path] }
+    elsif default_style
+      styles << { text: ss.primary_stylesheet_data }
+    else
+      styles << { text: read_asset(normalize_system_path(stylesheet, stylesdir), true) }
+    end
+
+    if attr? :icons, 'font'
+      if attr? 'iconfont-remote'
+        styles << { href: (attr 'iconfont-cdn', FONT_AWESOME_URI) }
+      else
+        styles << { href: [stylesdir, %(#{attr 'iconfont-name', 'font-awesome'}.css)] }
+      end
+    end
+
+    if attr? 'stem'
+      scripts << { src: MATHJAX_JS_URI }
+      scripts << { type: 'text/x-mathjax-config', text: %(MathJax.Hub.Config(#{MATHJAX_CONFIG});) }
+    end
+
+    case attr 'source-highlighter'
+    when 'coderay'
+      if (attr 'coderay-css', 'class') == 'class'
+        if linkcss
+          styles << { href: [stylesdir, ss.coderay_stylesheet_name] }
+        else
+          styles << { text: ss.coderay_stylesheet_data }
+        end
+      end
+
+    when 'pygments'
+      if (attr 'pygments-css', 'class') == 'class'
+        if linkcss
+          styles << { href: [stylesdir, ss.pygments_stylesheet_name(attr 'pygments-style')] }
+        else
+          styles << { text: ss.pygments_stylesheet_data(attr 'pygments-style') }
+        end
+      end
+
+    when 'highlightjs'
+      hjs_base = attr :highlightjsdir, HIGHLIGHTJS_BASE_URI
+      hjs_theme = attr 'highlightjs-theme', DEFAULT_HIGHLIGHTJS_THEME
+
+      scripts << { src: [hjs_base, 'highlight.min.js'] }
+      scripts << { src: [hjs_base, 'lang/common.min.js'] }
+      scripts << { text: 'hljs.initHighlightingOnLoad()' }
+      styles  << { href: [hjs_base, %(styles/#{hjs_theme}.min.css)] }
+
+    when 'prettify'
+      prettify_base = attr :prettifydir, PRETTIFY_BASE_URI
+      prettify_theme = attr 'prettify-theme', DEFAULT_PRETTIFY_THEME
+
+      scripts << { src: [prettify_base, 'prettify.min.js'] }
+      scripts << { text: 'document.addEventListener("DOMContentLoaded", prettyPrint)' }
+      styles  << { href: [prettify_base, %(#{prettify_theme}.min.css)] }
+    end
+
+    styles.each do |item|
+      if item.key?(:text)
+        tags << html_tag(:style, {}, item[:text])
+      else
+        tags << html_tag(:link, rel: 'stylesheet', href: urlize(*item[:href]))
+      end
+    end
+
+    scripts.each do |item|
+      if item.key? :text
+        tags << html_tag(:script, {type: item[:type]}, item[:text])
+      else
+        tags << html_tag(:script, type: item[:type], src: urlize(*item[:src]))
+      end
+    end
+
+    tags.join "\n"
+  end
+
+  #--------------------------------------------------------
+  # inline_anchor
+  #
+
+  # @return [String, nil] text of the xref anchor, or +nil+ if not found.
+  def xref_text
+    str = text || document.references[:ids][attr :refid || target]
+    str.tr_s("\n", ' ') if str
+  end
+
+  #--------------------------------------------------------
+  # inline_image
+  #
+
+  # @return [Array] style classes for a Font Awesome icon.
+  def icon_fa_classes
+    [ %(fa fa-#{target}),
+      (%(fa-#{attr :size}) if attr? :size),
+      (%(fa-rotate-#{attr :rotate}) if attr? :rotate),
+      (%(fa-flip-#{attr :flip}) if attr? :flip)
+    ].compact
+  end
+end

+ 10 - 0
src/templates/slim/html5/inline_anchor.html.slim

@@ -0,0 +1,10 @@
+- case type
+- when :xref
+  a href=target =(xref_text || %([#{attr :refid}]))
+- when :ref
+  a id=target
+- when :bibref
+  a id=target
+  |[#{@target}]
+- else
+  a id=id class=role href=target target=(attr :window) title=(attr :title) =text

+ 2 - 0
src/templates/slim/html5/inline_break.html.slim

@@ -0,0 +1,2 @@
+=text
+br

+ 1 - 0
src/templates/slim/html5/inline_button.html.slim

@@ -0,0 +1 @@
+b.button =text

+ 7 - 0
src/templates/slim/html5/inline_callout.html.slim

@@ -0,0 +1,7 @@
+- if font_icons?
+  i.conum data-value=text
+  b ="(#{text})"
+- elsif icons?
+  img src=icon_uri("callouts/#{text}") alt=text
+- else
+  b.conum ="(#{text})"

+ 11 - 0
src/templates/slim/html5/inline_footnote.html.slim

@@ -0,0 +1,11 @@
+- if type == :xref
+  - if attr :index
+    span.footnoteref
+      = surround '[', ']'
+        a.footnote href="##{footnote_id}" title="View footnote." =(attr :index)
+  - else
+    span.footnoteref.red title="Unresolved footnote reference." [#{text}]
+- else
+  span.footnote id=(footnote_id id if id)
+    = surround '[', ']'
+      a.footnote id=footnoteref_id href="##{footnote_id}" title="View footnote." =(attr :index)

+ 9 - 0
src/templates/slim/html5/inline_image.html.slim

@@ -0,0 +1,9 @@
+span class=[type, role] style=style_value(float: (attr :float))
+  = html_tag_if (attr? :link), :a, {class: 'image', href: (attr :link), target: (attr :window)}
+    - if type == 'icon' && font_icons?
+      i class=icon_fa_classes title=(attr :title)
+    - elsif type == 'icon' && !icons?
+      |[#{attr :alt}]
+    - else
+      - src = (type == 'icon' ? (icon_uri target) : (image_uri target))
+      img src=src alt=(attr :alt) width=(attr :width) height=(attr :height) title=(attr :title)

+ 2 - 0
src/templates/slim/html5/inline_indexterm.html.slim

@@ -0,0 +1,2 @@
+- if type == :visible
+  =text

+ 8 - 0
src/templates/slim/html5/inline_kbd.html.slim

@@ -0,0 +1,8 @@
+- if (keys = attr 'keys').size == 1
+  kbd =keys.first
+- else
+  kbd.keyseq
+    - keys.each_with_index do |key, idx|
+      - unless idx.zero?
+        |+
+      kbd =key

+ 10 - 0
src/templates/slim/html5/inline_menu.html.slim

@@ -0,0 +1,10 @@
+- if attr :menuitem
+  span.menuseq
+    span.menu =(attr :menu)
+    '&#160;&#9656;
+    - (attr 'submenus').each do |submenu|
+      span.submenu =submenu
+      '&#160;&#9656;
+    span.menuitem =(attr :menuitem)
+- else
+  span.menu =(attr :menu)

+ 26 - 0
src/templates/slim/html5/inline_quoted.html.slim

@@ -0,0 +1,26 @@
+- unless id.nil?
+  a id=id
+- case type
+- when :emphasis
+  em class=role =text
+- when :strong
+  strong class=role =text
+- when :monospaced
+  code class=role =text
+- when :superscript
+  sup class=role =text
+- when :subscript
+  sub class=role =text
+- when :mark
+  mark class=role =text
+- when :double
+  = html_tag_if role?, :span, class: role
+    |&#8220;#{text}&#8221;
+- when :single
+  = html_tag_if role?, :span, class: role
+    |&#8216;#{text}&#8217;
+- when :asciimath, :latexmath
+  =delimit_stem text, type
+- else
+  = html_tag_if role?, :span, class: role
+    =text

+ 14 - 0
src/templates/slim/html5/section.html.slim

@@ -0,0 +1,14 @@
+- sect0 = section_level == 0
+= html_tag_if !sect0, :div, class: [%(sect#{section_level}), role]
+  *{tag: %(h#{section_level + 1}), id: id, class: ('sect0' if sect0)}
+    - if id && (document.attr? :sectanchors)
+      a.anchor href="##{id}"
+      =section_title
+    - elsif id && (document.attr? :sectlinks)
+      a.link href="##{id}" =section_title
+    - else
+      =section_title
+  - if section_level == 1
+    .sectionbody =content
+  - else
+    =content