asciidoctor 0.1.4 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of asciidoctor might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +209 -25
- data/{LICENSE → LICENSE.adoc} +4 -3
- data/README.adoc +392 -395
- data/Rakefile +94 -137
- data/benchmark/benchmark.rb +127 -0
- data/benchmark/sample-data/mdbasics.adoc +334 -0
- data/bin/asciidoctor +5 -8
- data/bin/asciidoctor-safe +4 -8
- data/compat/asciidoc.conf +78 -11
- data/compat/font-awesome-3-compat.css +397 -0
- data/data/stylesheets/asciidoctor-default.css +399 -0
- data/data/stylesheets/coderay-asciidoctor.css +89 -0
- data/features/open_block.feature +92 -0
- data/features/pass_block.feature +66 -0
- data/features/step_definitions.rb +42 -0
- data/features/text_formatting.feature +55 -0
- data/features/xref.feature +116 -0
- data/lib/asciidoctor.rb +1155 -605
- data/lib/asciidoctor/abstract_block.rb +157 -71
- data/lib/asciidoctor/abstract_node.rb +150 -93
- data/lib/asciidoctor/attribute_list.rb +85 -90
- data/lib/asciidoctor/block.rb +51 -24
- data/lib/asciidoctor/callouts.rb +4 -7
- data/lib/asciidoctor/cli.rb +3 -0
- data/lib/asciidoctor/cli/invoker.rb +86 -76
- data/lib/asciidoctor/cli/options.rb +111 -61
- data/lib/asciidoctor/converter.rb +232 -0
- data/lib/asciidoctor/converter/base.rb +58 -0
- data/lib/asciidoctor/converter/composite.rb +66 -0
- data/lib/asciidoctor/converter/docbook45.rb +94 -0
- data/lib/asciidoctor/converter/docbook5.rb +684 -0
- data/lib/asciidoctor/converter/factory.rb +225 -0
- data/lib/asciidoctor/converter/html5.rb +1081 -0
- data/lib/asciidoctor/converter/template.rb +296 -0
- data/lib/asciidoctor/core_ext.rb +7 -0
- data/lib/asciidoctor/core_ext/object/nil_or_empty.rb +23 -0
- data/lib/asciidoctor/core_ext/string/chr.rb +6 -0
- data/lib/asciidoctor/core_ext/symbol/length.rb +6 -0
- data/lib/asciidoctor/document.rb +590 -304
- data/lib/asciidoctor/extensions.rb +1100 -308
- data/lib/asciidoctor/helpers.rb +109 -46
- data/lib/asciidoctor/inline.rb +16 -9
- data/lib/asciidoctor/list.rb +23 -15
- data/lib/asciidoctor/opal_ext.rb +4 -0
- data/lib/asciidoctor/opal_ext/comparable.rb +38 -0
- data/lib/asciidoctor/opal_ext/dir.rb +13 -0
- data/lib/asciidoctor/opal_ext/error.rb +2 -0
- data/lib/asciidoctor/opal_ext/file.rb +125 -0
- data/lib/asciidoctor/{lexer.rb → parser.rb} +646 -455
- data/lib/asciidoctor/path_resolver.rb +141 -77
- data/lib/asciidoctor/reader.rb +257 -187
- data/lib/asciidoctor/section.rb +12 -16
- data/lib/asciidoctor/stylesheets.rb +91 -0
- data/lib/asciidoctor/substitutors.rb +1548 -0
- data/lib/asciidoctor/table.rb +73 -57
- data/lib/asciidoctor/timings.rb +39 -0
- data/lib/asciidoctor/version.rb +1 -1
- data/man/asciidoctor.1 +22 -14
- data/man/asciidoctor.adoc +18 -10
- data/test/attributes_test.rb +314 -14
- data/test/blocks_test.rb +763 -118
- data/test/converter_test.rb +352 -0
- data/test/document_test.rb +518 -199
- data/test/extensions_test.rb +273 -103
- data/test/fixtures/asciidoc_index.txt +27 -13
- data/test/fixtures/basic-docinfo.xml +1 -1
- data/test/fixtures/chapter-a.adoc +3 -0
- data/test/fixtures/custom-backends/erb/html5/block_paragraph.html.erb +6 -0
- data/test/fixtures/docinfo.xml +1 -1
- data/test/fixtures/include-file.asciidoc +2 -0
- data/test/fixtures/master.adoc +5 -0
- data/test/invoker_test.rb +173 -61
- data/test/links_test.rb +97 -21
- data/test/lists_test.rb +181 -22
- data/test/options_test.rb +86 -2
- data/test/paragraphs_test.rb +47 -5
- data/test/{lexer_test.rb → parser_test.rb} +128 -57
- data/test/paths_test.rb +36 -1
- data/test/preamble_test.rb +25 -17
- data/test/reader_test.rb +404 -249
- data/test/sections_test.rb +623 -58
- data/test/substitutions_test.rb +609 -132
- data/test/tables_test.rb +198 -24
- data/test/test_helper.rb +101 -31
- data/test/text_test.rb +88 -31
- metadata +160 -64
- data/Gemfile +0 -12
- data/Guardfile +0 -18
- data/asciidoctor.gemspec +0 -143
- data/lib/asciidoctor/backends/_stylesheets.rb +0 -466
- data/lib/asciidoctor/backends/base_template.rb +0 -114
- data/lib/asciidoctor/backends/docbook45.rb +0 -774
- data/lib/asciidoctor/backends/docbook5.rb +0 -103
- data/lib/asciidoctor/backends/html5.rb +0 -1214
- data/lib/asciidoctor/renderer.rb +0 -259
- data/lib/asciidoctor/substituters.rb +0 -1083
- data/test/fixtures/asciidoc.txt +0 -105
- data/test/fixtures/ascshort.txt +0 -32
- data/test/fixtures/list_elements.asciidoc +0 -10
- data/test/renderer_test.rb +0 -162
| @@ -0,0 +1,225 @@ | |
| 1 | 
            +
            module Asciidoctor
         | 
| 2 | 
            +
              module Converter
         | 
| 3 | 
            +
                # A factory for instantiating converters that are used to convert a
         | 
| 4 | 
            +
                # {Document} (i.e., a parsed AsciiDoc tree structure) or {AbstractNode} to
         | 
| 5 | 
            +
                # a backend format such as HTML or DocBook. {Factory Converter::Factory} is
         | 
| 6 | 
            +
                # the primary entry point for creating, registering and accessing
         | 
| 7 | 
            +
                # converters.
         | 
| 8 | 
            +
                #
         | 
| 9 | 
            +
                # {Converter} objects are instantiated by passing a String backend name
         | 
| 10 | 
            +
                # and, optionally, an options Hash to the {Factory#create} method. The
         | 
| 11 | 
            +
                # backend can be thought of as an intent to convert a document to a
         | 
| 12 | 
            +
                # specified format. For example:
         | 
| 13 | 
            +
                #
         | 
| 14 | 
            +
                #   converter = Asciidoctor::Converter::Factory.create 'html5', :htmlsyntax => 'xml'
         | 
| 15 | 
            +
                #
         | 
| 16 | 
            +
                # Converter objects are thread safe. They only survive the lifetime of a single conversion.
         | 
| 17 | 
            +
                #
         | 
| 18 | 
            +
                # A singleton instance of {Factory Converter::Factory} can be accessed
         | 
| 19 | 
            +
                # using the {Factory.default} method. This instance maintains the global
         | 
| 20 | 
            +
                # registry of statically registered converters. The registery includes
         | 
| 21 | 
            +
                # built-in converters for {Html5Converter HTML 5}, {DocBook5Converter
         | 
| 22 | 
            +
                # DocBook 5} and {DocBook45Converter DocBook 4.5}, as well as any custom
         | 
| 23 | 
            +
                # converters that have been discovered or explicitly registered.
         | 
| 24 | 
            +
                #
         | 
| 25 | 
            +
                # If the {https://rubygems.org/gems/thread_safe thread_safe} gem is
         | 
| 26 | 
            +
                # installed, access to the default factory is guaranteed to be thread safe.
         | 
| 27 | 
            +
                # Otherwise, a warning is issued to the user.
         | 
| 28 | 
            +
                class Factory
         | 
| 29 | 
            +
                  @__default__ = nil
         | 
| 30 | 
            +
                  class << self
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                    # Public: Retrieves a singleton instance of {Factory Converter::Factory}.
         | 
| 33 | 
            +
                    #
         | 
| 34 | 
            +
                    # If the thread_safe gem is installed, the registry of converters is
         | 
| 35 | 
            +
                    # initialized as a ThreadSafe::Cache. Otherwise, a warning is issued and
         | 
| 36 | 
            +
                    # the registry of converters is initialized using a normal Hash.
         | 
| 37 | 
            +
                    #
         | 
| 38 | 
            +
                    # initialize_singleton - A Boolean to indicate whether the singleton should
         | 
| 39 | 
            +
                    #                        be initialize if it has not already been created.
         | 
| 40 | 
            +
                    #                        If false, and a singleton has not been previously
         | 
| 41 | 
            +
                    #                        initialized, a fresh instance is returned.
         | 
| 42 | 
            +
                    #
         | 
| 43 | 
            +
                    # Returns the default [Factory] singleton instance
         | 
| 44 | 
            +
                    def default initialize_singleton = true
         | 
| 45 | 
            +
                      return @__default__ || new unless initialize_singleton
         | 
| 46 | 
            +
                      # FIXME this assignment is not thread_safe, may need to use a ::Threadsafe helper here
         | 
| 47 | 
            +
                      @__default__ ||= begin
         | 
| 48 | 
            +
                        require 'thread_safe'.to_s unless defined? ::ThreadSafe
         | 
| 49 | 
            +
                        new ::ThreadSafe::Cache.new
         | 
| 50 | 
            +
                      rescue ::LoadError
         | 
| 51 | 
            +
                        warn 'asciidoctor: WARNING: gem \'thread_safe\' is not installed. This gem recommended when registering custom converters.'
         | 
| 52 | 
            +
                        new
         | 
| 53 | 
            +
                      end
         | 
| 54 | 
            +
                    end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                    # Public: Register a custom converter in the global converter factory to
         | 
| 57 | 
            +
                    # handle conversion to the specified backends. If the backend value is an
         | 
| 58 | 
            +
                    # asterisk, the converter is used to handle any backend that does not have
         | 
| 59 | 
            +
                    # an explicit converter.
         | 
| 60 | 
            +
                    #
         | 
| 61 | 
            +
                    # converter - The Converter class to register
         | 
| 62 | 
            +
                    # backends  - A String Array of backend names that this converter should
         | 
| 63 | 
            +
                    #             be registered to handle (optional, default: ['*'])
         | 
| 64 | 
            +
                    #
         | 
| 65 | 
            +
                    # Returns nothing
         | 
| 66 | 
            +
                    def register converter, backends = ['*']
         | 
| 67 | 
            +
                      default.register converter, backends
         | 
| 68 | 
            +
                    end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                    # Public: Lookup the custom converter for the specified backend in the
         | 
| 71 | 
            +
                    # global factory.
         | 
| 72 | 
            +
                    #
         | 
| 73 | 
            +
                    # This method does not resolve the built-in converters.
         | 
| 74 | 
            +
                    #
         | 
| 75 | 
            +
                    # backend - The String backend name
         | 
| 76 | 
            +
                    #
         | 
| 77 | 
            +
                    # Returns the [Converter] class registered to convert the specified backend
         | 
| 78 | 
            +
                    # or nil if no match is found
         | 
| 79 | 
            +
                    def resolve backend
         | 
| 80 | 
            +
                      default.resolve backend
         | 
| 81 | 
            +
                    end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                    # Public: Lookup the converter for the specified backend in the global
         | 
| 84 | 
            +
                    # factory and instantiate it, forwarding the Hash of options to the
         | 
| 85 | 
            +
                    # constructor of the converter class.
         | 
| 86 | 
            +
                    #
         | 
| 87 | 
            +
                    # If the custom converter is not found, an attempt will be made to find
         | 
| 88 | 
            +
                    # and instantiate a built-in converter.
         | 
| 89 | 
            +
                    #
         | 
| 90 | 
            +
                    #
         | 
| 91 | 
            +
                    # backend - The String backend name
         | 
| 92 | 
            +
                    # opts - A Hash of options to pass to the converter
         | 
| 93 | 
            +
                    #
         | 
| 94 | 
            +
                    # Returns an instance of [Converter] for converting the specified backend or
         | 
| 95 | 
            +
                    # nil if no match is found.
         | 
| 96 | 
            +
                    def create backend, opts = {}
         | 
| 97 | 
            +
                      default.create backend, opts
         | 
| 98 | 
            +
                    end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                    # Public: Retrieve the global Hash of custom Converter classes keyed by backend.
         | 
| 101 | 
            +
                    #
         | 
| 102 | 
            +
                    # Returns the the global [Hash] of custom Converter classes
         | 
| 103 | 
            +
                    def converters
         | 
| 104 | 
            +
                      default.converters
         | 
| 105 | 
            +
                    end
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                    # Public: Unregister all Converter classes in the global factory.
         | 
| 108 | 
            +
                    #
         | 
| 109 | 
            +
                    # Returns nothing
         | 
| 110 | 
            +
                    def unregister_all
         | 
| 111 | 
            +
                      default.unregister_all
         | 
| 112 | 
            +
                    end
         | 
| 113 | 
            +
                  end
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                  # Public: Get the Hash of Converter classes keyed by backend name
         | 
| 116 | 
            +
                  attr_reader :converters
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                  def initialize converters = nil
         | 
| 119 | 
            +
                    @converters = converters || {}
         | 
| 120 | 
            +
                    @star_converter = nil
         | 
| 121 | 
            +
                  end
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                  # Public: Register a custom converter with this factory to handle conversion
         | 
| 124 | 
            +
                  # to the specified backends. If the backend value is an asterisk, the
         | 
| 125 | 
            +
                  # converter is used to handle any backend that does not have an explicit
         | 
| 126 | 
            +
                  # converter.
         | 
| 127 | 
            +
                  #
         | 
| 128 | 
            +
                  # converter - The Converter class to register
         | 
| 129 | 
            +
                  # backends  - A String Array of backend names that this converter should
         | 
| 130 | 
            +
                  #             be registered to handle (optional, default: ['*'])
         | 
| 131 | 
            +
                  #
         | 
| 132 | 
            +
                  # Returns nothing
         | 
| 133 | 
            +
                  def register converter, backends = ['*']
         | 
| 134 | 
            +
                    backends.each do |backend|
         | 
| 135 | 
            +
                      @converters[backend] = converter
         | 
| 136 | 
            +
                      if backend == '*'
         | 
| 137 | 
            +
                        @star_converter = converter
         | 
| 138 | 
            +
                      end
         | 
| 139 | 
            +
                    end
         | 
| 140 | 
            +
                    nil
         | 
| 141 | 
            +
                  end
         | 
| 142 | 
            +
                
         | 
| 143 | 
            +
                  # Public: Lookup the custom converter registered with this factory to handle
         | 
| 144 | 
            +
                  # the specified backend.
         | 
| 145 | 
            +
                  #
         | 
| 146 | 
            +
                  # backend - The String backend name
         | 
| 147 | 
            +
                  #
         | 
| 148 | 
            +
                  # Returns the [Converter] class registered to convert the specified backend
         | 
| 149 | 
            +
                  # or nil if no match is found
         | 
| 150 | 
            +
                  def resolve backend
         | 
| 151 | 
            +
                    @converters && (@converters[backend] || @star_converter)
         | 
| 152 | 
            +
                  end
         | 
| 153 | 
            +
             | 
| 154 | 
            +
                  # Public: Unregister all Converter classes that are registered with this
         | 
| 155 | 
            +
                  # factory.
         | 
| 156 | 
            +
                  #
         | 
| 157 | 
            +
                  # Returns nothing
         | 
| 158 | 
            +
                  def unregister_all
         | 
| 159 | 
            +
                    @converters.clear
         | 
| 160 | 
            +
                    @star_converter = nil
         | 
| 161 | 
            +
                  end
         | 
| 162 | 
            +
             | 
| 163 | 
            +
                  # Public: Create a new Converter object that can be used to convert the
         | 
| 164 | 
            +
                  # {AbstractNode} (typically a {Document}) to the specified String backend.
         | 
| 165 | 
            +
                  # This method accepts an optional Hash of options that are passed to the
         | 
| 166 | 
            +
                  # converter's constructor.
         | 
| 167 | 
            +
                  #
         | 
| 168 | 
            +
                  # If a custom Converter is found to convert the specified backend, it is
         | 
| 169 | 
            +
                  # instantiated (if necessary) and returned immediately. If a custom
         | 
| 170 | 
            +
                  # Converter is not found, an attempt is made to resolve a built-in
         | 
| 171 | 
            +
                  # converter. If the `:template_dirs` key is found in the Hash passed as the
         | 
| 172 | 
            +
                  # second argument, a {CompositeConverter} is created that delegates to a
         | 
| 173 | 
            +
                  # {TemplateConverter} and, if resolved, the built-in converter. If the
         | 
| 174 | 
            +
                  # `:template_dirs` key is not found, the built-in converter is returned
         | 
| 175 | 
            +
                  # or nil if no converter is resolved.
         | 
| 176 | 
            +
                  #
         | 
| 177 | 
            +
                  # backend - the String backend name
         | 
| 178 | 
            +
                  # opts    - an optional Hash of options that get passed on to the converter's
         | 
| 179 | 
            +
                  #           constructor. If the :template_dirs key is found in the options
         | 
| 180 | 
            +
                  #           Hash, this method returns a {CompositeConverter} that delegates
         | 
| 181 | 
            +
                  #           to a {TemplateConverter}. (optional, default: {})
         | 
| 182 | 
            +
                  #
         | 
| 183 | 
            +
                  # Returns the [Converter] object
         | 
| 184 | 
            +
                  def create backend, opts = {}
         | 
| 185 | 
            +
                    if (converter = resolve backend)
         | 
| 186 | 
            +
                      if converter.is_a? ::Class
         | 
| 187 | 
            +
                        return converter.new backend, opts
         | 
| 188 | 
            +
                      else
         | 
| 189 | 
            +
                        return converter
         | 
| 190 | 
            +
                      end
         | 
| 191 | 
            +
                    end
         | 
| 192 | 
            +
                
         | 
| 193 | 
            +
                    base_converter = case backend
         | 
| 194 | 
            +
                    when 'html5'
         | 
| 195 | 
            +
                      unless defined? ::Asciidoctor::Converter::Html5Converter
         | 
| 196 | 
            +
                        require 'asciidoctor/converter/html5'.to_s
         | 
| 197 | 
            +
                      end
         | 
| 198 | 
            +
                      Html5Converter.new backend, opts
         | 
| 199 | 
            +
                    when 'docbook5'
         | 
| 200 | 
            +
                      unless defined? ::Asciidoctor::Converter::DocBook5Converter
         | 
| 201 | 
            +
                        require 'asciidoctor/converter/docbook5'.to_s
         | 
| 202 | 
            +
                      end
         | 
| 203 | 
            +
                      DocBook5Converter.new backend, opts
         | 
| 204 | 
            +
                    when 'docbook45'
         | 
| 205 | 
            +
                      unless defined? ::Asciidoctor::Converter::DocBook45Converter
         | 
| 206 | 
            +
                        require 'asciidoctor/converter/docbook45'.to_s
         | 
| 207 | 
            +
                      end
         | 
| 208 | 
            +
                      DocBook45Converter.new backend, opts
         | 
| 209 | 
            +
                    end
         | 
| 210 | 
            +
             | 
| 211 | 
            +
                    return base_converter unless opts.key? :template_dirs
         | 
| 212 | 
            +
                
         | 
| 213 | 
            +
                    unless defined? ::Asciidoctor::Converter::TemplateConverter
         | 
| 214 | 
            +
                      require 'asciidoctor/converter/template'.to_s
         | 
| 215 | 
            +
                    end
         | 
| 216 | 
            +
                    unless defined? ::Asciidoctor::Converter::CompositeConverter
         | 
| 217 | 
            +
                      require 'asciidoctor/converter/composite'.to_s
         | 
| 218 | 
            +
                    end
         | 
| 219 | 
            +
                    template_converter = TemplateConverter.new backend, opts[:template_dirs], opts
         | 
| 220 | 
            +
                    # QUESTION should we omit the composite converter if built_in_converter is nil?
         | 
| 221 | 
            +
                    CompositeConverter.new backend, template_converter, base_converter
         | 
| 222 | 
            +
                  end
         | 
| 223 | 
            +
                end
         | 
| 224 | 
            +
              end
         | 
| 225 | 
            +
            end
         | 
| @@ -0,0 +1,1081 @@ | |
| 1 | 
            +
            module Asciidoctor
         | 
| 2 | 
            +
              # A built-in {Converter} implementation that generates HTML 5 output
         | 
| 3 | 
            +
              # consistent with the html5 backend from AsciiDoc Python.
         | 
| 4 | 
            +
              class Converter::Html5Converter < Converter::BuiltIn
         | 
| 5 | 
            +
                QUOTE_TAGS = {
         | 
| 6 | 
            +
                  :emphasis    => ['<em>',     '</em>',     true],
         | 
| 7 | 
            +
                  :strong      => ['<strong>', '</strong>', true],
         | 
| 8 | 
            +
                  :monospaced  => ['<code>',   '</code>',   true],
         | 
| 9 | 
            +
                  :superscript => ['<sup>',    '</sup>',    true],
         | 
| 10 | 
            +
                  :subscript   => ['<sub>',    '</sub>',    true],
         | 
| 11 | 
            +
                  :double      => ['“',  '”',   false],
         | 
| 12 | 
            +
                  :single      => ['‘',  '’',   false],
         | 
| 13 | 
            +
                  :mark        => ['<mark>',   '</mark>',   true],
         | 
| 14 | 
            +
                  :asciimath   => ['\\$',      '\\$',       false],
         | 
| 15 | 
            +
                  :latexmath   => ['\\(',      '\\)',       false]
         | 
| 16 | 
            +
                  # Opal can't resolve these constants when referenced here
         | 
| 17 | 
            +
                  #:asciimath   => INLINE_MATH_DELIMITERS[:asciimath] + [false],
         | 
| 18 | 
            +
                  #:latexmath   => INLINE_MATH_DELIMITERS[:latexmath] + [false]
         | 
| 19 | 
            +
                }
         | 
| 20 | 
            +
                QUOTE_TAGS.default = [nil, nil, nil]
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                def initialize backend, opts = {}
         | 
| 23 | 
            +
                  @xml_mode = opts[:htmlsyntax] == 'xml'
         | 
| 24 | 
            +
                  @void_element_slash = @xml_mode ? '/' : nil
         | 
| 25 | 
            +
                  @stylesheets = Stylesheets.instance
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                def document node
         | 
| 29 | 
            +
                  result = []
         | 
| 30 | 
            +
                  slash = @void_element_slash
         | 
| 31 | 
            +
                  br = %(<br#{slash}>)
         | 
| 32 | 
            +
                  asset_uri_scheme = (node.attr 'asset-uri-scheme', 'https')
         | 
| 33 | 
            +
                  asset_uri_scheme = %(#{asset_uri_scheme}:) unless asset_uri_scheme.empty?
         | 
| 34 | 
            +
                  cdn_base = %(#{asset_uri_scheme}//cdnjs.cloudflare.com/ajax/libs)
         | 
| 35 | 
            +
                  linkcss = node.safe >= SafeMode::SECURE || (node.attr? 'linkcss')
         | 
| 36 | 
            +
                  result << '<!DOCTYPE html>'
         | 
| 37 | 
            +
                  lang_attribute = (node.attr? 'nolang') ? nil : %( lang="#{node.attr 'lang', 'en'}")
         | 
| 38 | 
            +
                  result << %(<html#{@xml_mode ? ' xmlns="http://www.w3.org/1999/xhtml"' : nil}#{lang_attribute}>)
         | 
| 39 | 
            +
                  result << %(<head>
         | 
| 40 | 
            +
            <meta charset="#{node.attr 'encoding', 'UTF-8'}"#{slash}>
         | 
| 41 | 
            +
            <!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"#{slash}><![endif]-->
         | 
| 42 | 
            +
            <meta name="viewport" content="width=device-width, initial-scale=1.0"#{slash}>
         | 
| 43 | 
            +
            <meta name="generator" content="Asciidoctor #{node.attr 'asciidoctor-version'}"#{slash}>)
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                  result << %(<meta name="application-name" content="#{node.attr 'app-name'}"#{slash}>) if node.attr? 'app-name'
         | 
| 46 | 
            +
                  result << %(<meta name="description" content="#{node.attr 'description'}"#{slash}>) if node.attr? 'description'
         | 
| 47 | 
            +
                  result << %(<meta name="keywords" content="#{node.attr 'keywords'}"#{slash}>) if node.attr? 'keywords'
         | 
| 48 | 
            +
                  result << %(<meta name="author" content="#{node.attr 'authors'}"#{slash}>) if node.attr? 'authors'
         | 
| 49 | 
            +
                  result << %(<meta name="copyright" content="#{node.attr 'copyright'}"#{slash}>) if node.attr? 'copyright'
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                  result << %(<title>#{node.doctitle :sanitize => true, :use_fallback => true}</title>) 
         | 
| 52 | 
            +
                  if DEFAULT_STYLESHEET_KEYS.include?(node.attr 'stylesheet')
         | 
| 53 | 
            +
                    if (webfonts = node.attr 'webfonts')
         | 
| 54 | 
            +
                      result << %(<link rel="stylesheet" href="#{asset_uri_scheme}//fonts.googleapis.com/css?family=#{webfonts.empty? ? 'Open+Sans:300,300italic,400,400italic,600,600italic|Noto+Serif:400,400italic,700,700italic|Droid+Sans+Mono:400' : webfonts}"#{slash}>)
         | 
| 55 | 
            +
                    end
         | 
| 56 | 
            +
                    if linkcss
         | 
| 57 | 
            +
                      result << %(<link rel="stylesheet" href="#{node.normalize_web_path DEFAULT_STYLESHEET_NAME, (node.attr 'stylesdir', '')}"#{slash}>)
         | 
| 58 | 
            +
                    else
         | 
| 59 | 
            +
                      result << @stylesheets.embed_primary_stylesheet
         | 
| 60 | 
            +
                    end
         | 
| 61 | 
            +
                  elsif node.attr? 'stylesheet'
         | 
| 62 | 
            +
                    if linkcss
         | 
| 63 | 
            +
                      result << %(<link rel="stylesheet" href="#{node.normalize_web_path((node.attr 'stylesheet'), (node.attr 'stylesdir', ''))}"#{slash}>)
         | 
| 64 | 
            +
                    else
         | 
| 65 | 
            +
                      result << %(<style>
         | 
| 66 | 
            +
            #{node.read_asset node.normalize_system_path((node.attr 'stylesheet'), (node.attr 'stylesdir', '')), true}
         | 
| 67 | 
            +
            </style>)
         | 
| 68 | 
            +
                    end
         | 
| 69 | 
            +
                  end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                  if node.attr? 'icons', 'font'
         | 
| 72 | 
            +
                    if node.attr? 'iconfont-remote'
         | 
| 73 | 
            +
                      result << %(<link rel="stylesheet" href="#{node.attr 'iconfont-cdn', %[#{cdn_base}/font-awesome/4.1.0/css/font-awesome.min.css]}"#{slash}>)
         | 
| 74 | 
            +
                    else
         | 
| 75 | 
            +
                      iconfont_stylesheet = %(#{node.attr 'iconfont-name', 'font-awesome'}.css)
         | 
| 76 | 
            +
                      result << %(<link rel="stylesheet" href="#{node.normalize_web_path iconfont_stylesheet, (node.attr 'stylesdir', '')}"#{slash}>)
         | 
| 77 | 
            +
                    end
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                  case node.attr 'source-highlighter'
         | 
| 81 | 
            +
                  when 'coderay'
         | 
| 82 | 
            +
                    if (node.attr 'coderay-css', 'class') == 'class'
         | 
| 83 | 
            +
                      if linkcss
         | 
| 84 | 
            +
                        result << %(<link rel="stylesheet" href="#{node.normalize_web_path @stylesheets.coderay_stylesheet_name, (node.attr 'stylesdir', '')}"#{slash}>)
         | 
| 85 | 
            +
                      else
         | 
| 86 | 
            +
                        result << @stylesheets.embed_coderay_stylesheet
         | 
| 87 | 
            +
                      end
         | 
| 88 | 
            +
                    end
         | 
| 89 | 
            +
                  when 'pygments'
         | 
| 90 | 
            +
                    if (node.attr 'pygments-css', 'class') == 'class'
         | 
| 91 | 
            +
                      pygments_style = node.attr 'pygments-style'
         | 
| 92 | 
            +
                      if linkcss
         | 
| 93 | 
            +
                        result << %(<link rel="stylesheet" href="#{node.normalize_web_path @stylesheets.pygments_stylesheet_name(pygments_style), (node.attr 'stylesdir', '')}"#{slash}>)
         | 
| 94 | 
            +
                      else
         | 
| 95 | 
            +
                        result << (@stylesheets.embed_pygments_stylesheet pygments_style)
         | 
| 96 | 
            +
                      end
         | 
| 97 | 
            +
                    end
         | 
| 98 | 
            +
                  when 'highlightjs', 'highlight.js'
         | 
| 99 | 
            +
                    highlightjs_path = node.attr 'highlightjsdir', %(#{cdn_base}/highlight.js/8.1)
         | 
| 100 | 
            +
                    result << %(<link rel="stylesheet" href="#{highlightjs_path}/styles/#{node.attr 'highlightjs-theme', 'github'}.min.css"#{slash}>
         | 
| 101 | 
            +
            <script src="#{highlightjs_path}/highlight.min.js"></script>
         | 
| 102 | 
            +
            <script>hljs.initHighlightingOnLoad()</script>)
         | 
| 103 | 
            +
                  when 'prettify'
         | 
| 104 | 
            +
                    prettify_path = node.attr 'prettifydir', %(#{cdn_base}/prettify/r298)
         | 
| 105 | 
            +
                    result << %(<link rel="stylesheet" href="#{prettify_path}/#{node.attr 'prettify-theme', 'prettify'}.min.css"#{slash}>
         | 
| 106 | 
            +
            <script src="#{prettify_path}/prettify.min.js"></script>
         | 
| 107 | 
            +
            <script>document.addEventListener('DOMContentLoaded', prettyPrint)</script>)
         | 
| 108 | 
            +
                  end
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                  if node.attr? 'stem'
         | 
| 111 | 
            +
                    result << %(<script type="text/x-mathjax-config">
         | 
| 112 | 
            +
            MathJax.Hub.Config({
         | 
| 113 | 
            +
              tex2jax: {
         | 
| 114 | 
            +
                inlineMath: [#{INLINE_MATH_DELIMITERS[:latexmath]}],
         | 
| 115 | 
            +
                displayMath: [#{BLOCK_MATH_DELIMITERS[:latexmath]}],
         | 
| 116 | 
            +
                ignoreClass: "nostem|nolatexmath"
         | 
| 117 | 
            +
              },
         | 
| 118 | 
            +
              asciimath2jax: {
         | 
| 119 | 
            +
                delimiters: [#{BLOCK_MATH_DELIMITERS[:asciimath]}],
         | 
| 120 | 
            +
                ignoreClass: "nostem|noasciimath"
         | 
| 121 | 
            +
              }
         | 
| 122 | 
            +
            });
         | 
| 123 | 
            +
            </script>
         | 
| 124 | 
            +
            <script src="#{cdn_base}/mathjax/2.4.0/MathJax.js?config=TeX-MML-AM_HTMLorMML"></script>)
         | 
| 125 | 
            +
                  end
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                  unless (docinfo_content = node.docinfo).empty?
         | 
| 128 | 
            +
                    result << docinfo_content
         | 
| 129 | 
            +
                  end
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                  result << '</head>'
         | 
| 132 | 
            +
                  body_attrs = []
         | 
| 133 | 
            +
                  if node.id
         | 
| 134 | 
            +
                    body_attrs << %(id="#{node.id}")
         | 
| 135 | 
            +
                  end
         | 
| 136 | 
            +
                  if (node.attr? 'toc-class') && (node.attr? 'toc') && (node.attr? 'toc-placement', 'auto')
         | 
| 137 | 
            +
                    body_attrs << %(class="#{node.doctype} #{node.attr 'toc-class'} toc-#{node.attr 'toc-position', 'header'}")
         | 
| 138 | 
            +
                  else
         | 
| 139 | 
            +
                    body_attrs << %(class="#{node.doctype}")
         | 
| 140 | 
            +
                  end
         | 
| 141 | 
            +
                  if node.attr? 'max-width'
         | 
| 142 | 
            +
                    body_attrs << %(style="max-width: #{node.attr 'max-width'};")
         | 
| 143 | 
            +
                  end
         | 
| 144 | 
            +
                  result << %(<body #{body_attrs * ' '}>)
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                  unless node.noheader
         | 
| 147 | 
            +
                    result << '<div id="header">'
         | 
| 148 | 
            +
                    if node.doctype == 'manpage'
         | 
| 149 | 
            +
                      result << %(<h1>#{node.doctitle} Manual Page</h1>)
         | 
| 150 | 
            +
                      if (node.attr? 'toc') && (node.attr? 'toc-placement', 'auto')
         | 
| 151 | 
            +
                        result << %(<div id="toc" class="#{node.attr 'toc-class', 'toc'}">
         | 
| 152 | 
            +
            <div id="toctitle">#{node.attr 'toc-title'}</div>
         | 
| 153 | 
            +
            #{outline node}
         | 
| 154 | 
            +
            </div>)
         | 
| 155 | 
            +
                      end
         | 
| 156 | 
            +
                      result << %(<h2>#{node.attr 'manname-title'}</h2>
         | 
| 157 | 
            +
            <div class="sectionbody">
         | 
| 158 | 
            +
            <p>#{node.attr 'manname'} - #{node.attr 'manpurpose'}</p>
         | 
| 159 | 
            +
            </div>)
         | 
| 160 | 
            +
                    else
         | 
| 161 | 
            +
                      if node.has_header?
         | 
| 162 | 
            +
                        result << %(<h1>#{node.header.title}</h1>) unless node.notitle
         | 
| 163 | 
            +
                        details = []
         | 
| 164 | 
            +
                        if node.attr? 'author'
         | 
| 165 | 
            +
                          details << %(<span id="author" class="author">#{node.attr 'author'}</span>#{br})
         | 
| 166 | 
            +
                          if node.attr? 'email'
         | 
| 167 | 
            +
                            details << %(<span id="email" class="email">#{node.sub_macros(node.attr 'email')}</span>#{br})
         | 
| 168 | 
            +
                          end
         | 
| 169 | 
            +
                          if (authorcount = (node.attr 'authorcount').to_i) > 1
         | 
| 170 | 
            +
                            (2..authorcount).each do |idx|
         | 
| 171 | 
            +
                              details << %(<span id="author#{idx}" class="author">#{node.attr "author_#{idx}"}</span>#{br})
         | 
| 172 | 
            +
                              if node.attr? %(email_#{idx})
         | 
| 173 | 
            +
                                details << %(<span id="email#{idx}" class="email">#{node.sub_macros(node.attr "email_#{idx}")}</span>#{br})
         | 
| 174 | 
            +
                              end
         | 
| 175 | 
            +
                            end
         | 
| 176 | 
            +
                          end
         | 
| 177 | 
            +
                        end
         | 
| 178 | 
            +
                        if node.attr? 'revnumber'
         | 
| 179 | 
            +
                          details << %(<span id="revnumber">#{((node.attr 'version-label') || '').downcase} #{node.attr 'revnumber'}#{(node.attr? 'revdate') ? ',' : ''}</span>)
         | 
| 180 | 
            +
                        end
         | 
| 181 | 
            +
                        if node.attr? 'revdate'
         | 
| 182 | 
            +
                          details << %(<span id="revdate">#{node.attr 'revdate'}</span>)
         | 
| 183 | 
            +
                        end
         | 
| 184 | 
            +
                        if node.attr? 'revremark'
         | 
| 185 | 
            +
                          details << %(#{br}<span id="revremark">#{node.attr 'revremark'}</span>)
         | 
| 186 | 
            +
                        end
         | 
| 187 | 
            +
                        unless details.empty?
         | 
| 188 | 
            +
                          result << '<div class="details">'
         | 
| 189 | 
            +
                          result.concat details
         | 
| 190 | 
            +
                          result << '</div>'
         | 
| 191 | 
            +
                        end
         | 
| 192 | 
            +
                      end
         | 
| 193 | 
            +
             | 
| 194 | 
            +
                      if (node.attr? 'toc') && (node.attr? 'toc-placement', 'auto')
         | 
| 195 | 
            +
                        result << %(<div id="toc" class="#{node.attr 'toc-class', 'toc'}">
         | 
| 196 | 
            +
            <div id="toctitle">#{node.attr 'toc-title'}</div>
         | 
| 197 | 
            +
            #{outline node}
         | 
| 198 | 
            +
            </div>)
         | 
| 199 | 
            +
                      end
         | 
| 200 | 
            +
                    end
         | 
| 201 | 
            +
                    result << '</div>'
         | 
| 202 | 
            +
                  end
         | 
| 203 | 
            +
             | 
| 204 | 
            +
                  result << %(<div id="content">
         | 
| 205 | 
            +
            #{node.content}
         | 
| 206 | 
            +
            </div>)
         | 
| 207 | 
            +
             | 
| 208 | 
            +
                  if node.footnotes? && !(node.attr? 'nofootnotes')
         | 
| 209 | 
            +
                    result << %(<div id="footnotes">
         | 
| 210 | 
            +
            <hr#{slash}>)
         | 
| 211 | 
            +
                    node.footnotes.each do |footnote|
         | 
| 212 | 
            +
                      result << %(<div class="footnote" id="_footnote_#{footnote.index}">
         | 
| 213 | 
            +
            <a href="#_footnoteref_#{footnote.index}">#{footnote.index}</a>. #{footnote.text}
         | 
| 214 | 
            +
            </div>)
         | 
| 215 | 
            +
                    end
         | 
| 216 | 
            +
                    result << '</div>'
         | 
| 217 | 
            +
                  end
         | 
| 218 | 
            +
                  unless node.nofooter
         | 
| 219 | 
            +
                    result << '<div id="footer">'
         | 
| 220 | 
            +
                    result << '<div id="footer-text">'
         | 
| 221 | 
            +
                    if node.attr? 'revnumber'
         | 
| 222 | 
            +
                      result << %(#{node.attr 'version-label'} #{node.attr 'revnumber'}#{br})
         | 
| 223 | 
            +
                    end
         | 
| 224 | 
            +
                    if node.attr? 'last-update-label'
         | 
| 225 | 
            +
                      result << %(#{node.attr 'last-update-label'} #{node.attr 'docdatetime'})
         | 
| 226 | 
            +
                    end
         | 
| 227 | 
            +
                    result << '</div>'
         | 
| 228 | 
            +
                    unless (docinfo_content = node.docinfo :footer).empty?
         | 
| 229 | 
            +
                      result << docinfo_content
         | 
| 230 | 
            +
                    end
         | 
| 231 | 
            +
                    result << '</div>'
         | 
| 232 | 
            +
                  end
         | 
| 233 | 
            +
             | 
| 234 | 
            +
                  result << '</body>'
         | 
| 235 | 
            +
                  result << '</html>'
         | 
| 236 | 
            +
                  result * EOL
         | 
| 237 | 
            +
                end
         | 
| 238 | 
            +
             | 
| 239 | 
            +
                def embedded node
         | 
| 240 | 
            +
                  result = []
         | 
| 241 | 
            +
                  if !node.notitle && node.has_header?
         | 
| 242 | 
            +
                    id_attr = node.id ? %( id="#{node.id}") : nil
         | 
| 243 | 
            +
                    result << %(<h1#{id_attr}>#{node.header.title}</h1>)
         | 
| 244 | 
            +
                  end
         | 
| 245 | 
            +
             | 
| 246 | 
            +
                  result << node.content
         | 
| 247 | 
            +
             | 
| 248 | 
            +
                  if node.footnotes? && !(node.attr? 'nofootnotes')
         | 
| 249 | 
            +
                    result << %(<div id="footnotes">
         | 
| 250 | 
            +
            <hr#{@void_element_slash}>)
         | 
| 251 | 
            +
                    node.footnotes.each do |footnote|
         | 
| 252 | 
            +
                      result << %(<div class="footnote" id="_footnote_#{footnote.index}">
         | 
| 253 | 
            +
            <a href="#_footnoteref_#{footnote.index}">#{footnote.index}</a> #{footnote.text}
         | 
| 254 | 
            +
            </div>)
         | 
| 255 | 
            +
                    end
         | 
| 256 | 
            +
             | 
| 257 | 
            +
                    result << '</div>'
         | 
| 258 | 
            +
                  end
         | 
| 259 | 
            +
             | 
| 260 | 
            +
                  result * EOL
         | 
| 261 | 
            +
                end
         | 
| 262 | 
            +
             | 
| 263 | 
            +
                def outline node, opts = {}
         | 
| 264 | 
            +
                  return if (sections = node.sections).empty?
         | 
| 265 | 
            +
                  sectnumlevels = opts[:sectnumlevels] || (node.document.attr 'sectnumlevels', 3).to_i
         | 
| 266 | 
            +
                  toclevels = opts[:toclevels] || (node.document.attr 'toclevels', 2).to_i
         | 
| 267 | 
            +
                  result = []
         | 
| 268 | 
            +
                  # FIXME the level for special sections should be set correctly in the model
         | 
| 269 | 
            +
                  # slevel will only be 0 if we have a book doctype with parts
         | 
| 270 | 
            +
                  slevel = (first_section = sections[0]).level
         | 
| 271 | 
            +
                  slevel = 1 if slevel == 0 && first_section.special
         | 
| 272 | 
            +
                  result << %(<ul class="sectlevel#{slevel}">)
         | 
| 273 | 
            +
                  sections.each do |section|
         | 
| 274 | 
            +
                    section_num = (section.numbered && !section.caption && section.level <= sectnumlevels) ? %(#{section.sectnum} ) : nil
         | 
| 275 | 
            +
                    if section.level < toclevels && (child_toc_level = outline section, :toclevels => toclevels, :secnumlevels => sectnumlevels)
         | 
| 276 | 
            +
                      result << %(<li><a href="##{section.id}">#{section_num}#{section.captioned_title}</a>)
         | 
| 277 | 
            +
                      result << child_toc_level
         | 
| 278 | 
            +
                      result << '</li>'
         | 
| 279 | 
            +
                    else
         | 
| 280 | 
            +
                      result << %(<li><a href="##{section.id}">#{section_num}#{section.captioned_title}</a></li>)
         | 
| 281 | 
            +
                    end
         | 
| 282 | 
            +
                  end
         | 
| 283 | 
            +
                  result << '</ul>'
         | 
| 284 | 
            +
                  result * EOL
         | 
| 285 | 
            +
                end
         | 
| 286 | 
            +
             | 
| 287 | 
            +
                def section node
         | 
| 288 | 
            +
                  slevel = node.level
         | 
| 289 | 
            +
                  # QUESTION should the check for slevel be done in section?
         | 
| 290 | 
            +
                  slevel = 1 if slevel == 0 && node.special
         | 
| 291 | 
            +
                  htag = %(h#{slevel + 1})
         | 
| 292 | 
            +
                  id_attr = anchor = link_start = link_end = nil
         | 
| 293 | 
            +
                  if node.id
         | 
| 294 | 
            +
                    id_attr = %( id="#{node.id}")
         | 
| 295 | 
            +
                    if node.document.attr? 'sectanchors'
         | 
| 296 | 
            +
                      anchor = %(<a class="anchor" href="##{node.id}"></a>)
         | 
| 297 | 
            +
                      # possible idea - anchor icons GitHub-style
         | 
| 298 | 
            +
                      #if node.document.attr? 'icons', 'font'
         | 
| 299 | 
            +
                      #  anchor = %(<a class="anchor" href="##{node.id}"><i class="fa fa-anchor"></i></a>)
         | 
| 300 | 
            +
                      #else
         | 
| 301 | 
            +
                    elsif node.document.attr? 'sectlinks'
         | 
| 302 | 
            +
                      link_start = %(<a class="link" href="##{node.id}">)
         | 
| 303 | 
            +
                      link_end = '</a>'
         | 
| 304 | 
            +
                    end
         | 
| 305 | 
            +
                  end
         | 
| 306 | 
            +
             | 
| 307 | 
            +
                  if slevel == 0
         | 
| 308 | 
            +
                    %(<h1#{id_attr} class="sect0">#{anchor}#{link_start}#{node.title}#{link_end}</h1>
         | 
| 309 | 
            +
            #{node.content})
         | 
| 310 | 
            +
                  else
         | 
| 311 | 
            +
                    class_attr = (role = node.role) ? %( class="sect#{slevel} #{role}") : %( class="sect#{slevel}")
         | 
| 312 | 
            +
                    sectnum = if node.numbered && !node.caption && slevel <= (node.document.attr 'sectnumlevels', 3).to_i
         | 
| 313 | 
            +
                      %(#{node.sectnum} )
         | 
| 314 | 
            +
                    end
         | 
| 315 | 
            +
                    %(<div#{class_attr}>
         | 
| 316 | 
            +
            <#{htag}#{id_attr}>#{anchor}#{link_start}#{sectnum}#{node.captioned_title}#{link_end}</#{htag}>
         | 
| 317 | 
            +
            #{slevel == 1 ? %[<div class="sectionbody">\n#{node.content}\n</div>] : node.content}
         | 
| 318 | 
            +
            </div>)
         | 
| 319 | 
            +
                  end
         | 
| 320 | 
            +
                end
         | 
| 321 | 
            +
             | 
| 322 | 
            +
                def admonition node
         | 
| 323 | 
            +
                  id_attr = node.id ? %( id="#{node.id}") : nil
         | 
| 324 | 
            +
                  name = node.attr 'name'
         | 
| 325 | 
            +
                  title_element = node.title? ? %(<div class="title">#{node.title}</div>\n) : nil
         | 
| 326 | 
            +
                  caption = if node.document.attr? 'icons'
         | 
| 327 | 
            +
                    if node.document.attr? 'icons', 'font'
         | 
| 328 | 
            +
                      %(<i class="fa icon-#{name}" title="#{node.caption}"></i>)
         | 
| 329 | 
            +
                    else
         | 
| 330 | 
            +
                      %(<img src="#{node.icon_uri name}" alt="#{node.caption}"#{@void_element_slash}>)
         | 
| 331 | 
            +
                    end
         | 
| 332 | 
            +
                  else
         | 
| 333 | 
            +
                    %(<div class="title">#{node.caption}</div>)
         | 
| 334 | 
            +
                  end
         | 
| 335 | 
            +
                  %(<div#{id_attr} class="admonitionblock #{name}#{(role = node.role) && " #{role}"}">
         | 
| 336 | 
            +
            <table>
         | 
| 337 | 
            +
            <tr>
         | 
| 338 | 
            +
            <td class="icon">
         | 
| 339 | 
            +
            #{caption}
         | 
| 340 | 
            +
            </td>
         | 
| 341 | 
            +
            <td class="content">
         | 
| 342 | 
            +
            #{title_element}#{node.content}
         | 
| 343 | 
            +
            </td>
         | 
| 344 | 
            +
            </tr>
         | 
| 345 | 
            +
            </table>
         | 
| 346 | 
            +
            </div>)
         | 
| 347 | 
            +
                end
         | 
| 348 | 
            +
             | 
| 349 | 
            +
                def audio node
         | 
| 350 | 
            +
                  xml = node.document.attr? 'htmlsyntax', 'xml'
         | 
| 351 | 
            +
                  id_attribute = node.id ? %( id="#{node.id}") : nil
         | 
| 352 | 
            +
                  classes = ['audioblock', node.style, node.role].compact
         | 
| 353 | 
            +
                  class_attribute = %( class="#{classes * ' '}")
         | 
| 354 | 
            +
                  title_element = node.title? ? %(<div class="title">#{node.captioned_title}</div>\n) : nil
         | 
| 355 | 
            +
                  %(<div#{id_attribute}#{class_attribute}>
         | 
| 356 | 
            +
            #{title_element}<div class="content">
         | 
| 357 | 
            +
            <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}>
         | 
| 358 | 
            +
            Your browser does not support the audio tag.
         | 
| 359 | 
            +
            </audio>
         | 
| 360 | 
            +
            </div>
         | 
| 361 | 
            +
            </div>)
         | 
| 362 | 
            +
                end
         | 
| 363 | 
            +
             | 
| 364 | 
            +
                def colist node
         | 
| 365 | 
            +
                  result = []
         | 
| 366 | 
            +
                  id_attribute = node.id ? %( id="#{node.id}") : nil
         | 
| 367 | 
            +
                  classes = ['colist', node.style, node.role].compact
         | 
| 368 | 
            +
                  class_attribute = %( class="#{classes * ' '}")
         | 
| 369 | 
            +
             | 
| 370 | 
            +
                  result << %(<div#{id_attribute}#{class_attribute}>)
         | 
| 371 | 
            +
                  result << %(<div class="title">#{node.title}</div>) if node.title?
         | 
| 372 | 
            +
             | 
| 373 | 
            +
                  if node.document.attr? 'icons'
         | 
| 374 | 
            +
                    result << '<table>'
         | 
| 375 | 
            +
             | 
| 376 | 
            +
                    font_icons = node.document.attr? 'icons', 'font'
         | 
| 377 | 
            +
                    node.items.each_with_index do |item, i|
         | 
| 378 | 
            +
                      num = i + 1
         | 
| 379 | 
            +
                      num_element = if font_icons
         | 
| 380 | 
            +
                        %(<i class="conum" data-value="#{num}"></i><b>#{num}</b>)
         | 
| 381 | 
            +
                      else
         | 
| 382 | 
            +
                        %(<img src="#{node.icon_uri "callouts/#{num}"}" alt="#{num}"#{@void_element_slash}>)
         | 
| 383 | 
            +
                      end
         | 
| 384 | 
            +
                      result << %(<tr>
         | 
| 385 | 
            +
            <td>#{num_element}</td>
         | 
| 386 | 
            +
            <td>#{item.text}</td>
         | 
| 387 | 
            +
            </tr>)
         | 
| 388 | 
            +
                    end
         | 
| 389 | 
            +
             | 
| 390 | 
            +
                    result << '</table>'
         | 
| 391 | 
            +
                  else
         | 
| 392 | 
            +
                    result << '<ol>'
         | 
| 393 | 
            +
                    node.items.each do |item|
         | 
| 394 | 
            +
                      result << %(<li>
         | 
| 395 | 
            +
            <p>#{item.text}</p>
         | 
| 396 | 
            +
            </li>)
         | 
| 397 | 
            +
                    end
         | 
| 398 | 
            +
                    result << '</ol>'
         | 
| 399 | 
            +
                  end
         | 
| 400 | 
            +
             | 
| 401 | 
            +
                  result << '</div>'
         | 
| 402 | 
            +
                  result * EOL
         | 
| 403 | 
            +
                end
         | 
| 404 | 
            +
             | 
| 405 | 
            +
                def dlist node
         | 
| 406 | 
            +
                  result = []
         | 
| 407 | 
            +
                  id_attribute = node.id ? %( id="#{node.id}") : nil
         | 
| 408 | 
            +
             | 
| 409 | 
            +
                  classes = case node.style
         | 
| 410 | 
            +
                  when 'qanda'
         | 
| 411 | 
            +
                    ['qlist', 'qanda', node.role]
         | 
| 412 | 
            +
                  when 'horizontal'
         | 
| 413 | 
            +
                    ['hdlist', node.role]
         | 
| 414 | 
            +
                  else
         | 
| 415 | 
            +
                    ['dlist', node.style, node.role]
         | 
| 416 | 
            +
                  end.compact
         | 
| 417 | 
            +
             | 
| 418 | 
            +
                  class_attribute = %( class="#{classes * ' '}")
         | 
| 419 | 
            +
             | 
| 420 | 
            +
                  result << %(<div#{id_attribute}#{class_attribute}>)
         | 
| 421 | 
            +
                  result << %(<div class="title">#{node.title}</div>) if node.title?
         | 
| 422 | 
            +
                  case node.style
         | 
| 423 | 
            +
                  when 'qanda'
         | 
| 424 | 
            +
                    result << '<ol>'
         | 
| 425 | 
            +
                    node.items.each do |terms, dd|
         | 
| 426 | 
            +
                      result << '<li>'
         | 
| 427 | 
            +
                      [*terms].each do |dt|
         | 
| 428 | 
            +
                        result << %(<p><em>#{dt.text}</em></p>)
         | 
| 429 | 
            +
                      end
         | 
| 430 | 
            +
                      if dd
         | 
| 431 | 
            +
                        result << %(<p>#{dd.text}</p>) if dd.text?
         | 
| 432 | 
            +
                        result << dd.content if dd.blocks?
         | 
| 433 | 
            +
                      end
         | 
| 434 | 
            +
                      result << '</li>'
         | 
| 435 | 
            +
                    end
         | 
| 436 | 
            +
                    result << '</ol>'
         | 
| 437 | 
            +
                  when 'horizontal'
         | 
| 438 | 
            +
                    slash = @void_element_slash
         | 
| 439 | 
            +
                    result << '<table>'
         | 
| 440 | 
            +
                    if (node.attr? 'labelwidth') || (node.attr? 'itemwidth')
         | 
| 441 | 
            +
                      result << '<colgroup>'
         | 
| 442 | 
            +
                      col_style_attribute = (node.attr? 'labelwidth') ? %( style="width: #{(node.attr 'labelwidth').chomp '%'}%;") : nil
         | 
| 443 | 
            +
                      result << %(<col#{col_style_attribute}#{slash}>)
         | 
| 444 | 
            +
                      col_style_attribute = (node.attr? 'itemwidth') ? %( style="width: #{(node.attr 'itemwidth').chomp '%'}%;") : nil
         | 
| 445 | 
            +
                      result << %(<col#{col_style_attribute}#{slash}>)
         | 
| 446 | 
            +
                      result << '</colgroup>'
         | 
| 447 | 
            +
                    end
         | 
| 448 | 
            +
                    node.items.each do |terms, dd|
         | 
| 449 | 
            +
                      result << '<tr>'
         | 
| 450 | 
            +
                      result << %(<td class="hdlist1#{(node.option? 'strong') ? ' strong' : nil}">)
         | 
| 451 | 
            +
                      terms_array = [*terms]
         | 
| 452 | 
            +
                      last_term = terms_array[-1]
         | 
| 453 | 
            +
                      terms_array.each do |dt|
         | 
| 454 | 
            +
                        result << dt.text
         | 
| 455 | 
            +
                        result << %(<br#{slash}>) if dt != last_term
         | 
| 456 | 
            +
                      end
         | 
| 457 | 
            +
                      result << '</td>'
         | 
| 458 | 
            +
                      result << '<td class="hdlist2">'
         | 
| 459 | 
            +
                      if dd
         | 
| 460 | 
            +
                        result << %(<p>#{dd.text}</p>) if dd.text?
         | 
| 461 | 
            +
                        result << dd.content if dd.blocks?
         | 
| 462 | 
            +
                      end
         | 
| 463 | 
            +
                      result << '</td>'
         | 
| 464 | 
            +
                      result << '</tr>'
         | 
| 465 | 
            +
                    end
         | 
| 466 | 
            +
                    result << '</table>'
         | 
| 467 | 
            +
                  else
         | 
| 468 | 
            +
                    result << '<dl>'
         | 
| 469 | 
            +
                    dt_style_attribute = node.style ? nil : ' class="hdlist1"'
         | 
| 470 | 
            +
                    node.items.each do |terms, dd|
         | 
| 471 | 
            +
                      [*terms].each do |dt|
         | 
| 472 | 
            +
                        result << %(<dt#{dt_style_attribute}>#{dt.text}</dt>)
         | 
| 473 | 
            +
                      end
         | 
| 474 | 
            +
                      if dd
         | 
| 475 | 
            +
                        result << '<dd>'
         | 
| 476 | 
            +
                        result << %(<p>#{dd.text}</p>) if dd.text?
         | 
| 477 | 
            +
                        result << dd.content if dd.blocks?
         | 
| 478 | 
            +
                        result << '</dd>'
         | 
| 479 | 
            +
                      end
         | 
| 480 | 
            +
                    end
         | 
| 481 | 
            +
                    result << '</dl>'
         | 
| 482 | 
            +
                  end
         | 
| 483 | 
            +
             | 
| 484 | 
            +
                  result << '</div>'
         | 
| 485 | 
            +
                  result * EOL
         | 
| 486 | 
            +
                end
         | 
| 487 | 
            +
             | 
| 488 | 
            +
                def example node
         | 
| 489 | 
            +
                  id_attribute = node.id ? %( id="#{node.id}") : nil
         | 
| 490 | 
            +
                  title_element = node.title? ? %(<div class="title">#{node.captioned_title}</div>\n) : nil
         | 
| 491 | 
            +
             | 
| 492 | 
            +
                  %(<div#{id_attribute} class="#{(role = node.role) ? ['exampleblock', role] * ' ' : 'exampleblock'}">
         | 
| 493 | 
            +
            #{title_element}<div class="content">
         | 
| 494 | 
            +
            #{node.content}
         | 
| 495 | 
            +
            </div>
         | 
| 496 | 
            +
            </div>)
         | 
| 497 | 
            +
                end
         | 
| 498 | 
            +
             | 
| 499 | 
            +
                def floating_title node
         | 
| 500 | 
            +
                  tag_name = %(h#{node.level + 1})
         | 
| 501 | 
            +
                  id_attribute = node.id ? %( id="#{node.id}") : nil
         | 
| 502 | 
            +
                  classes = [node.style, node.role].compact
         | 
| 503 | 
            +
                  %(<#{tag_name}#{id_attribute} class="#{classes * ' '}">#{node.title}</#{tag_name}>)
         | 
| 504 | 
            +
                end
         | 
| 505 | 
            +
             | 
| 506 | 
            +
                def image node
         | 
| 507 | 
            +
                  align = (node.attr? 'align') ? (node.attr 'align') : nil
         | 
| 508 | 
            +
                  float = (node.attr? 'float') ? (node.attr 'float') : nil 
         | 
| 509 | 
            +
                  style_attribute = if align || float
         | 
| 510 | 
            +
                    styles = [align ? %(text-align: #{align}) : nil, float ? %(float: #{float}) : nil].compact
         | 
| 511 | 
            +
                    %( style="#{styles * ';'}")
         | 
| 512 | 
            +
                  end
         | 
| 513 | 
            +
             | 
| 514 | 
            +
                  width_attribute = (node.attr? 'width') ? %( width="#{node.attr 'width'}") : nil
         | 
| 515 | 
            +
                  height_attribute = (node.attr? 'height') ? %( height="#{node.attr 'height'}") : nil
         | 
| 516 | 
            +
             | 
| 517 | 
            +
                  img_element = %(<img src="#{node.image_uri node.attr('target')}" alt="#{node.attr 'alt'}"#{width_attribute}#{height_attribute}#{@void_element_slash}>)
         | 
| 518 | 
            +
                  if (link = node.attr 'link')
         | 
| 519 | 
            +
                    img_element = %(<a class="image" href="#{link}">#{img_element}</a>)
         | 
| 520 | 
            +
                  end
         | 
| 521 | 
            +
                  id_attribute = node.id ? %( id="#{node.id}") : nil
         | 
| 522 | 
            +
                  classes = ['imageblock', node.style, node.role].compact
         | 
| 523 | 
            +
                  class_attribute = %( class="#{classes * ' '}")
         | 
| 524 | 
            +
                  title_element = node.title? ? %(\n<div class="title">#{node.captioned_title}</div>) : nil
         | 
| 525 | 
            +
             | 
| 526 | 
            +
                  %(<div#{id_attribute}#{class_attribute}#{style_attribute}>
         | 
| 527 | 
            +
            <div class="content">
         | 
| 528 | 
            +
            #{img_element}
         | 
| 529 | 
            +
            </div>#{title_element}
         | 
| 530 | 
            +
            </div>)
         | 
| 531 | 
            +
                end
         | 
| 532 | 
            +
             | 
| 533 | 
            +
                def listing node
         | 
| 534 | 
            +
                  nowrap = !(node.document.attr? 'prewrap') || (node.option? 'nowrap')
         | 
| 535 | 
            +
                  if node.style == 'source'
         | 
| 536 | 
            +
                    if (language = node.attr 'language', nil, false)
         | 
| 537 | 
            +
                      code_attrs = %( data-lang="#{language}")
         | 
| 538 | 
            +
                    else
         | 
| 539 | 
            +
                      code_attrs = nil
         | 
| 540 | 
            +
                    end
         | 
| 541 | 
            +
                    case node.document.attr 'source-highlighter'
         | 
| 542 | 
            +
                    when 'coderay'
         | 
| 543 | 
            +
                      pre_class = %( class="CodeRay highlight#{nowrap ? ' nowrap' : nil}")
         | 
| 544 | 
            +
                    when 'pygments'
         | 
| 545 | 
            +
                      pre_class = %( class="pygments highlight#{nowrap ? ' nowrap' : nil}")
         | 
| 546 | 
            +
                    when 'highlightjs', 'highlight.js'
         | 
| 547 | 
            +
                      pre_class = %( class="highlightjs highlight#{nowrap ? ' nowrap' : nil}")
         | 
| 548 | 
            +
                      code_attrs = %( class="language-#{language}"#{code_attrs}) if language
         | 
| 549 | 
            +
                    when 'prettify'
         | 
| 550 | 
            +
                      pre_class = %( class="prettyprint highlight#{nowrap ? ' nowrap' : nil}#{(node.attr? 'linenums') ? ' linenums' : nil}")
         | 
| 551 | 
            +
                      code_attrs = %( class="language-#{language}"#{code_attrs}) if language
         | 
| 552 | 
            +
                    when 'html-pipeline'
         | 
| 553 | 
            +
                      pre_class = language ? %( lang="#{language}") : nil
         | 
| 554 | 
            +
                      code_attrs = nil
         | 
| 555 | 
            +
                    else
         | 
| 556 | 
            +
                      pre_class = %( class="highlight#{nowrap ? ' nowrap' : nil}")
         | 
| 557 | 
            +
                      code_attrs = %( class="language-#{language}"#{code_attrs}) if language
         | 
| 558 | 
            +
                    end
         | 
| 559 | 
            +
                    pre_start = %(<pre#{pre_class}><code#{code_attrs}>)
         | 
| 560 | 
            +
                    pre_end = '</code></pre>'
         | 
| 561 | 
            +
                  else
         | 
| 562 | 
            +
                    pre_start = %(<pre#{nowrap ? ' class="nowrap"' : nil}>)
         | 
| 563 | 
            +
                    pre_end = '</pre>'
         | 
| 564 | 
            +
                  end
         | 
| 565 | 
            +
             | 
| 566 | 
            +
                  id_attribute = node.id ? %( id="#{node.id}") : nil
         | 
| 567 | 
            +
                  title_element = node.title? ? %(<div class="title">#{node.captioned_title}</div>\n) : nil
         | 
| 568 | 
            +
                  %(<div#{id_attribute} class="listingblock#{(role = node.role) && " #{role}"}">
         | 
| 569 | 
            +
            #{title_element}<div class="content">
         | 
| 570 | 
            +
            #{pre_start}#{node.content}#{pre_end}
         | 
| 571 | 
            +
            </div>
         | 
| 572 | 
            +
            </div>)
         | 
| 573 | 
            +
                end
         | 
| 574 | 
            +
             | 
| 575 | 
            +
                def literal node
         | 
| 576 | 
            +
                  id_attribute = node.id ? %( id="#{node.id}") : nil
         | 
| 577 | 
            +
                  title_element = node.title? ? %(<div class="title">#{node.title}</div>\n) : nil
         | 
| 578 | 
            +
                  nowrap = !(node.document.attr? 'prewrap') || (node.option? 'nowrap')
         | 
| 579 | 
            +
                  %(<div#{id_attribute} class="literalblock#{(role = node.role) && " #{role}"}">
         | 
| 580 | 
            +
            #{title_element}<div class="content">
         | 
| 581 | 
            +
            <pre#{nowrap ? ' class="nowrap"' : nil}>#{node.content}</pre>
         | 
| 582 | 
            +
            </div>
         | 
| 583 | 
            +
            </div>)
         | 
| 584 | 
            +
                end
         | 
| 585 | 
            +
             | 
| 586 | 
            +
                def stem node
         | 
| 587 | 
            +
                  id_attribute = node.id ? %( id="#{node.id}") : nil
         | 
| 588 | 
            +
                  title_element = node.title? ? %(<div class="title">#{node.title}</div>\n) : nil
         | 
| 589 | 
            +
                  open, close = BLOCK_MATH_DELIMITERS[node.style.to_sym]
         | 
| 590 | 
            +
             | 
| 591 | 
            +
                  unless ((equation = node.content).start_with? open) && (equation.end_with? close)
         | 
| 592 | 
            +
                    equation = %(#{open}#{equation}#{close})
         | 
| 593 | 
            +
                  end
         | 
| 594 | 
            +
                  
         | 
| 595 | 
            +
                  %(<div#{id_attribute} class="#{(role = node.role) ? ['stemblock', role] * ' ' : 'stemblock'}">
         | 
| 596 | 
            +
            #{title_element}<div class="content">
         | 
| 597 | 
            +
            #{equation}
         | 
| 598 | 
            +
            </div>
         | 
| 599 | 
            +
            </div>)
         | 
| 600 | 
            +
                end
         | 
| 601 | 
            +
             | 
| 602 | 
            +
                def olist node
         | 
| 603 | 
            +
                  result = []
         | 
| 604 | 
            +
                  id_attribute = node.id ? %( id="#{node.id}") : nil
         | 
| 605 | 
            +
                  classes = ['olist', node.style, node.role].compact
         | 
| 606 | 
            +
                  class_attribute = %( class="#{classes * ' '}")
         | 
| 607 | 
            +
             | 
| 608 | 
            +
                  result << %(<div#{id_attribute}#{class_attribute}>)
         | 
| 609 | 
            +
                  result << %(<div class="title">#{node.title}</div>) if node.title?
         | 
| 610 | 
            +
             | 
| 611 | 
            +
                  type_attribute = (keyword = node.list_marker_keyword) ? %( type="#{keyword}") : nil
         | 
| 612 | 
            +
                  start_attribute = (node.attr? 'start') ? %( start="#{node.attr 'start'}") : nil
         | 
| 613 | 
            +
                  result << %(<ol class="#{node.style}"#{type_attribute}#{start_attribute}>)
         | 
| 614 | 
            +
             | 
| 615 | 
            +
                  node.items.each do |item|
         | 
| 616 | 
            +
                    result << '<li>'
         | 
| 617 | 
            +
                    result << %(<p>#{item.text}</p>)
         | 
| 618 | 
            +
                    result << item.content if item.blocks?
         | 
| 619 | 
            +
                    result << '</li>'
         | 
| 620 | 
            +
                  end
         | 
| 621 | 
            +
             | 
| 622 | 
            +
                  result << '</ol>'
         | 
| 623 | 
            +
                  result << '</div>'
         | 
| 624 | 
            +
                  result * EOL
         | 
| 625 | 
            +
                end
         | 
| 626 | 
            +
             | 
| 627 | 
            +
                def open node
         | 
| 628 | 
            +
                  if (style = node.style) == 'abstract'
         | 
| 629 | 
            +
                    if node.parent == node.document && node.document.doctype == 'book'
         | 
| 630 | 
            +
                      warn 'asciidoctor: WARNING: abstract block cannot be used in a document without a title when doctype is book. Excluding block content.'
         | 
| 631 | 
            +
                      ''
         | 
| 632 | 
            +
                    else
         | 
| 633 | 
            +
                      id_attr = node.id ? %( id="#{node.id}") : nil
         | 
| 634 | 
            +
                      title_el = node.title? ? %(<div class="title">#{node.title}</div>) : nil
         | 
| 635 | 
            +
                      %(<div#{id_attr} class="quoteblock abstract#{(role = node.role) && " #{role}"}">
         | 
| 636 | 
            +
            #{title_el}<blockquote>
         | 
| 637 | 
            +
            #{node.content}
         | 
| 638 | 
            +
            </blockquote>
         | 
| 639 | 
            +
            </div>)
         | 
| 640 | 
            +
                    end
         | 
| 641 | 
            +
                  elsif style == 'partintro' && (node.level != 0 || node.parent.context != :section || node.document.doctype != 'book')
         | 
| 642 | 
            +
                    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.'
         | 
| 643 | 
            +
                    ''
         | 
| 644 | 
            +
                  else
         | 
| 645 | 
            +
                      id_attr = node.id ? %( id="#{node.id}") : nil
         | 
| 646 | 
            +
                      title_el = node.title? ? %(<div class="title">#{node.title}</div>) : nil
         | 
| 647 | 
            +
                    %(<div#{id_attr} class="openblock#{style && style != 'open' ? " #{style}" : ''}#{(role = node.role) && " #{role}"}">
         | 
| 648 | 
            +
            #{title_el}<div class="content">
         | 
| 649 | 
            +
            #{node.content}
         | 
| 650 | 
            +
            </div>
         | 
| 651 | 
            +
            </div>)
         | 
| 652 | 
            +
                  end
         | 
| 653 | 
            +
                end
         | 
| 654 | 
            +
             | 
| 655 | 
            +
                def page_break node
         | 
| 656 | 
            +
                  '<div style="page-break-after: always;"></div>'
         | 
| 657 | 
            +
                end
         | 
| 658 | 
            +
             | 
| 659 | 
            +
                def paragraph node
         | 
| 660 | 
            +
                  attributes = if node.id
         | 
| 661 | 
            +
                    if node.role
         | 
| 662 | 
            +
                      %( id="#{node.id}" class="paragraph #{node.role}")
         | 
| 663 | 
            +
                    else
         | 
| 664 | 
            +
                      %( id="#{node.id}" class="paragraph")
         | 
| 665 | 
            +
                    end
         | 
| 666 | 
            +
                  elsif node.role
         | 
| 667 | 
            +
                    %( class="paragraph #{node.role}")
         | 
| 668 | 
            +
                  else
         | 
| 669 | 
            +
                    ' class="paragraph"'
         | 
| 670 | 
            +
                  end
         | 
| 671 | 
            +
             | 
| 672 | 
            +
                  if node.title?
         | 
| 673 | 
            +
                    %(<div#{attributes}>
         | 
| 674 | 
            +
            <div class="title">#{node.title}</div>
         | 
| 675 | 
            +
            <p>#{node.content}</p>
         | 
| 676 | 
            +
            </div>)
         | 
| 677 | 
            +
                  else
         | 
| 678 | 
            +
                    %(<div#{attributes}>
         | 
| 679 | 
            +
            <p>#{node.content}</p>
         | 
| 680 | 
            +
            </div>)
         | 
| 681 | 
            +
                  end
         | 
| 682 | 
            +
                end
         | 
| 683 | 
            +
             | 
| 684 | 
            +
                def preamble node
         | 
| 685 | 
            +
                  toc = if (node.attr? 'toc') && (node.attr? 'toc-placement', 'preamble')
         | 
| 686 | 
            +
                    %(\n<div id="toc" class="#{node.attr 'toc-class', 'toc'}">
         | 
| 687 | 
            +
            <div id="toctitle">#{node.attr 'toc-title'}</div>
         | 
| 688 | 
            +
            #{outline node.document}
         | 
| 689 | 
            +
            </div>)
         | 
| 690 | 
            +
                  end
         | 
| 691 | 
            +
             | 
| 692 | 
            +
                  %(<div id="preamble">
         | 
| 693 | 
            +
            <div class="sectionbody">
         | 
| 694 | 
            +
            #{node.content}
         | 
| 695 | 
            +
            </div>#{toc}
         | 
| 696 | 
            +
            </div>)
         | 
| 697 | 
            +
                end
         | 
| 698 | 
            +
             | 
| 699 | 
            +
                def quote node
         | 
| 700 | 
            +
                  id_attribute = node.id ? %( id="#{node.id}") : nil
         | 
| 701 | 
            +
                  classes = ['quoteblock', node.role].compact
         | 
| 702 | 
            +
                  class_attribute = %( class="#{classes * ' '}")
         | 
| 703 | 
            +
                  title_element = node.title? ? %(\n<div class="title">#{node.title}</div>) : nil
         | 
| 704 | 
            +
                  attribution = (node.attr? 'attribution') ? (node.attr 'attribution') : nil
         | 
| 705 | 
            +
                  citetitle = (node.attr? 'citetitle') ? (node.attr 'citetitle') : nil
         | 
| 706 | 
            +
                  if attribution || citetitle
         | 
| 707 | 
            +
                    cite_element = citetitle ? %(<cite>#{citetitle}</cite>) : nil
         | 
| 708 | 
            +
                    attribution_text = attribution ? %(— #{attribution}#{citetitle ? "<br#{@void_element_slash}>\n" : nil}) : nil
         | 
| 709 | 
            +
                    attribution_element = %(\n<div class="attribution">\n#{attribution_text}#{cite_element}\n</div>)
         | 
| 710 | 
            +
                  else
         | 
| 711 | 
            +
                    attribution_element = nil
         | 
| 712 | 
            +
                  end
         | 
| 713 | 
            +
             | 
| 714 | 
            +
                  %(<div#{id_attribute}#{class_attribute}>#{title_element}
         | 
| 715 | 
            +
            <blockquote>
         | 
| 716 | 
            +
            #{node.content}
         | 
| 717 | 
            +
            </blockquote>#{attribution_element}
         | 
| 718 | 
            +
            </div>)
         | 
| 719 | 
            +
                end
         | 
| 720 | 
            +
             | 
| 721 | 
            +
                def thematic_break node
         | 
| 722 | 
            +
                  %(<hr#{@void_element_slash}>)
         | 
| 723 | 
            +
                end
         | 
| 724 | 
            +
             | 
| 725 | 
            +
                def sidebar node
         | 
| 726 | 
            +
                  id_attribute = node.id ? %( id="#{node.id}") : nil
         | 
| 727 | 
            +
                  title_element = node.title? ? %(<div class="title">#{node.title}</div>\n) : nil
         | 
| 728 | 
            +
                  %(<div#{id_attribute} class="#{(role = node.role) ? ['sidebarblock', role] * ' ' : 'sidebarblock'}">
         | 
| 729 | 
            +
            <div class="content">
         | 
| 730 | 
            +
            #{title_element}#{node.content}
         | 
| 731 | 
            +
            </div>
         | 
| 732 | 
            +
            </div>)
         | 
| 733 | 
            +
                end
         | 
| 734 | 
            +
             | 
| 735 | 
            +
                def table node
         | 
| 736 | 
            +
                  result = [] 
         | 
| 737 | 
            +
                  id_attribute = node.id ? %( id="#{node.id}") : nil
         | 
| 738 | 
            +
                  classes = ['tableblock', %(frame-#{node.attr 'frame', 'all'}), %(grid-#{node.attr 'grid', 'all'})]
         | 
| 739 | 
            +
                  styles = []
         | 
| 740 | 
            +
                  unless node.option? 'autowidth'
         | 
| 741 | 
            +
                    if (tablepcwidth = node.attr 'tablepcwidth') == 100
         | 
| 742 | 
            +
                      classes << 'spread'
         | 
| 743 | 
            +
                    else
         | 
| 744 | 
            +
                      styles << %(width: #{tablepcwidth}%;)
         | 
| 745 | 
            +
                    end
         | 
| 746 | 
            +
                  end
         | 
| 747 | 
            +
                  if (role = node.role)
         | 
| 748 | 
            +
                    classes << role
         | 
| 749 | 
            +
                  end
         | 
| 750 | 
            +
                  class_attribute = %( class="#{classes * ' '}")
         | 
| 751 | 
            +
                  styles << %(float: #{node.attr 'float'};) if node.attr? 'float'
         | 
| 752 | 
            +
                  style_attribute = styles.empty? ? nil : %( style="#{styles * ' '}")
         | 
| 753 | 
            +
             | 
| 754 | 
            +
                  result << %(<table#{id_attribute}#{class_attribute}#{style_attribute}>)
         | 
| 755 | 
            +
                  result << %(<caption class="title">#{node.captioned_title}</caption>) if node.title?
         | 
| 756 | 
            +
                  if (node.attr 'rowcount') > 0
         | 
| 757 | 
            +
                    slash = @void_element_slash
         | 
| 758 | 
            +
                    result << '<colgroup>'
         | 
| 759 | 
            +
                    if node.option? 'autowidth'
         | 
| 760 | 
            +
                      tag = %(<col#{slash}>)
         | 
| 761 | 
            +
                      node.columns.size.times do
         | 
| 762 | 
            +
                        result << tag
         | 
| 763 | 
            +
                      end
         | 
| 764 | 
            +
                    else
         | 
| 765 | 
            +
                      node.columns.each do |col|
         | 
| 766 | 
            +
                        result << %(<col style="width: #{col.attr 'colpcwidth'}%;"#{slash}>)
         | 
| 767 | 
            +
                      end
         | 
| 768 | 
            +
                    end
         | 
| 769 | 
            +
                    result << '</colgroup>'
         | 
| 770 | 
            +
                    [:head, :foot, :body].select {|tsec| !node.rows[tsec].empty? }.each do |tsec|
         | 
| 771 | 
            +
                      result << %(<t#{tsec}>)
         | 
| 772 | 
            +
                      node.rows[tsec].each do |row|
         | 
| 773 | 
            +
                        result << '<tr>'
         | 
| 774 | 
            +
                        row.each do |cell|
         | 
| 775 | 
            +
                          if tsec == :head
         | 
| 776 | 
            +
                            cell_content = cell.text
         | 
| 777 | 
            +
                          else
         | 
| 778 | 
            +
                            case cell.style
         | 
| 779 | 
            +
                            when :asciidoc
         | 
| 780 | 
            +
                              cell_content = %(<div>#{cell.content}</div>)
         | 
| 781 | 
            +
                            when :verse
         | 
| 782 | 
            +
                              cell_content = %(<div class="verse">#{cell.text}</div>)
         | 
| 783 | 
            +
                            when :literal
         | 
| 784 | 
            +
                              cell_content = %(<div class="literal"><pre>#{cell.text}</pre></div>)
         | 
| 785 | 
            +
                            else
         | 
| 786 | 
            +
                              cell_content = ''
         | 
| 787 | 
            +
                              cell.content.each do |text|
         | 
| 788 | 
            +
                                cell_content = %(#{cell_content}<p class="tableblock">#{text}</p>)
         | 
| 789 | 
            +
                              end
         | 
| 790 | 
            +
                            end
         | 
| 791 | 
            +
                          end
         | 
| 792 | 
            +
             | 
| 793 | 
            +
                          cell_tag_name = (tsec == :head || cell.style == :header ? 'th' : 'td')
         | 
| 794 | 
            +
                          cell_class_attribute = %( class="tableblock halign-#{cell.attr 'halign'} valign-#{cell.attr 'valign'}")
         | 
| 795 | 
            +
                          cell_colspan_attribute = cell.colspan ? %( colspan="#{cell.colspan}") : nil
         | 
| 796 | 
            +
                          cell_rowspan_attribute = cell.rowspan ? %( rowspan="#{cell.rowspan}") : nil
         | 
| 797 | 
            +
                          cell_style_attribute = (node.document.attr? 'cellbgcolor') ? %( style="background-color: #{node.document.attr 'cellbgcolor'};") : nil
         | 
| 798 | 
            +
                          result << %(<#{cell_tag_name}#{cell_class_attribute}#{cell_colspan_attribute}#{cell_rowspan_attribute}#{cell_style_attribute}>#{cell_content}</#{cell_tag_name}>)
         | 
| 799 | 
            +
                        end
         | 
| 800 | 
            +
                        result << '</tr>'
         | 
| 801 | 
            +
                      end
         | 
| 802 | 
            +
                      result << %(</t#{tsec}>)
         | 
| 803 | 
            +
                    end
         | 
| 804 | 
            +
                  end
         | 
| 805 | 
            +
                  result << '</table>'
         | 
| 806 | 
            +
                  result * EOL
         | 
| 807 | 
            +
                end
         | 
| 808 | 
            +
             | 
| 809 | 
            +
                def toc node
         | 
| 810 | 
            +
                  return '<!-- toc disabled -->' unless (doc = node.document).attr?('toc-placement', 'macro') && doc.attr?('toc')
         | 
| 811 | 
            +
             | 
| 812 | 
            +
                  if node.id
         | 
| 813 | 
            +
                    id_attr = %( id="#{node.id}")
         | 
| 814 | 
            +
                    title_id_attr = %( id="#{node.id}title")
         | 
| 815 | 
            +
                  else
         | 
| 816 | 
            +
                    id_attr = ' id="toc"'
         | 
| 817 | 
            +
                    title_id_attr = ' id="toctitle"'
         | 
| 818 | 
            +
                  end
         | 
| 819 | 
            +
                  title = node.title? ? node.title : (doc.attr 'toc-title')
         | 
| 820 | 
            +
                  levels = (node.attr? 'levels') ? (node.attr 'levels').to_i : nil
         | 
| 821 | 
            +
                  role = node.role? ? node.role : (doc.attr 'toc-class', 'toc')
         | 
| 822 | 
            +
             | 
| 823 | 
            +
                  %(<div#{id_attr} class="#{role}">
         | 
| 824 | 
            +
            <div#{title_id_attr} class="title">#{title}</div>
         | 
| 825 | 
            +
            #{outline doc, :toclevels => levels}
         | 
| 826 | 
            +
            </div>)
         | 
| 827 | 
            +
                end
         | 
| 828 | 
            +
             | 
| 829 | 
            +
                def ulist node
         | 
| 830 | 
            +
                  result = []
         | 
| 831 | 
            +
                  id_attribute = node.id ? %( id="#{node.id}") : nil
         | 
| 832 | 
            +
                  div_classes = ['ulist', node.style, node.role].compact
         | 
| 833 | 
            +
                  marker_checked = nil
         | 
| 834 | 
            +
                  marker_unchecked = nil
         | 
| 835 | 
            +
                  if (checklist = node.option? 'checklist')
         | 
| 836 | 
            +
                    div_classes.insert 1, 'checklist'
         | 
| 837 | 
            +
                    ul_class_attribute = ' class="checklist"'
         | 
| 838 | 
            +
                    if node.option? 'interactive'
         | 
| 839 | 
            +
                      if node.document.attr? 'htmlsyntax', 'xml'
         | 
| 840 | 
            +
                        marker_checked = '<input type="checkbox" data-item-complete="1" checked="checked"/> '
         | 
| 841 | 
            +
                        marker_unchecked = '<input type="checkbox" data-item-complete="0"/> '
         | 
| 842 | 
            +
                      else
         | 
| 843 | 
            +
                        marker_checked = '<input type="checkbox" data-item-complete="1" checked> '
         | 
| 844 | 
            +
                        marker_unchecked = '<input type="checkbox" data-item-complete="0"> '
         | 
| 845 | 
            +
                      end
         | 
| 846 | 
            +
                    else
         | 
| 847 | 
            +
                      if node.document.attr? 'icons', 'font'
         | 
| 848 | 
            +
                        marker_checked = '<i class="fa fa-check-square-o"></i> '
         | 
| 849 | 
            +
                        marker_unchecked = '<i class="fa fa-square-o"></i> '
         | 
| 850 | 
            +
                      else
         | 
| 851 | 
            +
                        marker_checked = '✓ '
         | 
| 852 | 
            +
                        marker_unchecked = '❏ '
         | 
| 853 | 
            +
                      end
         | 
| 854 | 
            +
                    end
         | 
| 855 | 
            +
                  else
         | 
| 856 | 
            +
                    ul_class_attribute = node.style ? %( class="#{node.style}") : nil
         | 
| 857 | 
            +
                  end
         | 
| 858 | 
            +
                  result << %(<div#{id_attribute} class="#{div_classes * ' '}">)
         | 
| 859 | 
            +
                  result << %(<div class="title">#{node.title}</div>) if node.title?
         | 
| 860 | 
            +
                  result << %(<ul#{ul_class_attribute}>)
         | 
| 861 | 
            +
             | 
| 862 | 
            +
                  node.items.each do |item|
         | 
| 863 | 
            +
                    result << '<li>'
         | 
| 864 | 
            +
                    if checklist && (item.attr? 'checkbox')
         | 
| 865 | 
            +
                      result << %(<p>#{(item.attr? 'checked') ? marker_checked : marker_unchecked}#{item.text}</p>)
         | 
| 866 | 
            +
                    else
         | 
| 867 | 
            +
                      result << %(<p>#{item.text}</p>)
         | 
| 868 | 
            +
                    end
         | 
| 869 | 
            +
                    result << item.content if item.blocks?
         | 
| 870 | 
            +
                    result << '</li>'
         | 
| 871 | 
            +
                  end
         | 
| 872 | 
            +
             | 
| 873 | 
            +
                  result << '</ul>'
         | 
| 874 | 
            +
                  result << '</div>'
         | 
| 875 | 
            +
                  result * EOL
         | 
| 876 | 
            +
                end
         | 
| 877 | 
            +
             | 
| 878 | 
            +
                def verse node
         | 
| 879 | 
            +
                  id_attribute = node.id ? %( id="#{node.id}") : nil
         | 
| 880 | 
            +
                  classes = ['verseblock', node.role].compact
         | 
| 881 | 
            +
                  class_attribute = %( class="#{classes * ' '}")
         | 
| 882 | 
            +
                  title_element = node.title? ? %(\n<div class="title">#{node.title}</div>) : nil
         | 
| 883 | 
            +
                  attribution = (node.attr? 'attribution') ? (node.attr 'attribution') : nil
         | 
| 884 | 
            +
                  citetitle = (node.attr? 'citetitle') ? (node.attr 'citetitle') : nil
         | 
| 885 | 
            +
                  if attribution || citetitle
         | 
| 886 | 
            +
                    cite_element = citetitle ? %(<cite>#{citetitle}</cite>) : nil
         | 
| 887 | 
            +
                    attribution_text = attribution ? %(— #{attribution}#{citetitle ? "<br#{@void_element_slash}>\n" : nil}) : nil
         | 
| 888 | 
            +
                    attribution_element = %(\n<div class="attribution">\n#{attribution_text}#{cite_element}\n</div>)
         | 
| 889 | 
            +
                  else
         | 
| 890 | 
            +
                    attribution_element = nil
         | 
| 891 | 
            +
                  end
         | 
| 892 | 
            +
             | 
| 893 | 
            +
                  %(<div#{id_attribute}#{class_attribute}>#{title_element}
         | 
| 894 | 
            +
            <pre class="content">#{node.content}</pre>#{attribution_element}
         | 
| 895 | 
            +
            </div>)
         | 
| 896 | 
            +
                end
         | 
| 897 | 
            +
             | 
| 898 | 
            +
                def video node
         | 
| 899 | 
            +
                  xml = node.document.attr? 'htmlsyntax', 'xml'
         | 
| 900 | 
            +
                  id_attribute = node.id ? %( id="#{node.id}") : nil
         | 
| 901 | 
            +
                  classes = ['videoblock', node.style, node.role].compact
         | 
| 902 | 
            +
                  class_attribute = %( class="#{classes * ' '}")
         | 
| 903 | 
            +
                  title_element = node.title? ? %(\n<div class="title">#{node.captioned_title}</div>) : nil
         | 
| 904 | 
            +
                  width_attribute = (node.attr? 'width') ? %( width="#{node.attr 'width'}") : nil
         | 
| 905 | 
            +
                  height_attribute = (node.attr? 'height') ? %( height="#{node.attr 'height'}") : nil
         | 
| 906 | 
            +
                  case node.attr 'poster'
         | 
| 907 | 
            +
                  when 'vimeo'
         | 
| 908 | 
            +
                    start_anchor = (node.attr? 'start') ? "#at=#{node.attr 'start'}" : nil
         | 
| 909 | 
            +
                    delimiter = '?'
         | 
| 910 | 
            +
                    autoplay_param = (node.option? 'autoplay') ? "#{delimiter}autoplay=1" : nil
         | 
| 911 | 
            +
                    delimiter = '&' if autoplay_param
         | 
| 912 | 
            +
                    loop_param = (node.option? 'loop') ? "#{delimiter}loop=1" : nil
         | 
| 913 | 
            +
                    %(<div#{id_attribute}#{class_attribute}>#{title_element}
         | 
| 914 | 
            +
            <div class="content">
         | 
| 915 | 
            +
            <iframe#{width_attribute}#{height_attribute} src="//player.vimeo.com/video/#{node.attr 'target'}#{start_anchor}#{autoplay_param}#{loop_param}" frameborder="0"#{append_boolean_attribute 'webkitAllowFullScreen', xml}#{append_boolean_attribute 'mozallowfullscreen', xml}#{append_boolean_attribute 'allowFullScreen', xml}></iframe>
         | 
| 916 | 
            +
            </div>
         | 
| 917 | 
            +
            </div>)
         | 
| 918 | 
            +
                  when 'youtube'
         | 
| 919 | 
            +
                    start_param = (node.attr? 'start') ? "&start=#{node.attr 'start'}" : nil
         | 
| 920 | 
            +
                    end_param = (node.attr? 'end') ? "&end=#{node.attr 'end'}" : nil
         | 
| 921 | 
            +
                    autoplay_param = (node.option? 'autoplay') ? '&autoplay=1' : nil
         | 
| 922 | 
            +
                    loop_param = (node.option? 'loop') ? '&loop=1' : nil
         | 
| 923 | 
            +
                    controls_param = (node.option? 'nocontrols') ? '&controls=0' : nil
         | 
| 924 | 
            +
                    %(<div#{id_attribute}#{class_attribute}>#{title_element}
         | 
| 925 | 
            +
            <div class="content">
         | 
| 926 | 
            +
            <iframe#{width_attribute}#{height_attribute} src="//www.youtube.com/embed/#{node.attr 'target'}?rel=0#{start_param}#{end_param}#{autoplay_param}#{loop_param}#{controls_param}" frameborder="0"#{(node.option? 'nofullscreen') ? nil : (append_boolean_attribute 'allowfullscreen', xml)}></iframe>
         | 
| 927 | 
            +
            </div>
         | 
| 928 | 
            +
            </div>)
         | 
| 929 | 
            +
                  else 
         | 
| 930 | 
            +
                    poster_attribute = %(#{poster = node.attr 'poster'}).empty? ? nil : %( poster="#{node.media_uri poster}")
         | 
| 931 | 
            +
                    time_anchor = ((node.attr? 'start') || (node.attr? 'end')) ? %(#t=#{node.attr 'start'}#{(node.attr? 'end') ? ',' : nil}#{node.attr 'end'}) : nil
         | 
| 932 | 
            +
                    %(<div#{id_attribute}#{class_attribute}>#{title_element}
         | 
| 933 | 
            +
            <div class="content">
         | 
| 934 | 
            +
            <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}>
         | 
| 935 | 
            +
            Your browser does not support the video tag.
         | 
| 936 | 
            +
            </video>
         | 
| 937 | 
            +
            </div>
         | 
| 938 | 
            +
            </div>)
         | 
| 939 | 
            +
                  end
         | 
| 940 | 
            +
                end
         | 
| 941 | 
            +
             | 
| 942 | 
            +
                def inline_anchor node
         | 
| 943 | 
            +
                  target = node.target
         | 
| 944 | 
            +
                  case node.type
         | 
| 945 | 
            +
                  when :xref
         | 
| 946 | 
            +
                    refid = (node.attr 'refid') || target
         | 
| 947 | 
            +
                    # NOTE we lookup text in converter because DocBook doesn't need this logic
         | 
| 948 | 
            +
                    text = node.text || (node.document.references[:ids][refid] || %([#{refid}]))
         | 
| 949 | 
            +
                    %(<a href="#{target}">#{text}</a>)
         | 
| 950 | 
            +
                  when :ref
         | 
| 951 | 
            +
                    %(<a id="#{target}"></a>)
         | 
| 952 | 
            +
                  when :link
         | 
| 953 | 
            +
                    attrs = []
         | 
| 954 | 
            +
                    attrs << %( id="#{node.id}") if node.id
         | 
| 955 | 
            +
                    if (role = node.role)
         | 
| 956 | 
            +
                      attrs << %( class="#{role}")
         | 
| 957 | 
            +
                    end
         | 
| 958 | 
            +
                    attrs << %( title="#{node.attr 'title'}") if node.attr? 'title'
         | 
| 959 | 
            +
                    attrs << %( target="#{node.attr 'window'}") if node.attr? 'window'
         | 
| 960 | 
            +
                    %(<a href="#{target}"#{attrs.join}>#{node.text}</a>)
         | 
| 961 | 
            +
                  when :bibref
         | 
| 962 | 
            +
                    %(<a id="#{target}"></a>[#{target}])
         | 
| 963 | 
            +
                  else
         | 
| 964 | 
            +
                    warn %(asciidoctor: WARNING: unknown anchor type: #{node.type.inspect})
         | 
| 965 | 
            +
                  end
         | 
| 966 | 
            +
                end
         | 
| 967 | 
            +
             | 
| 968 | 
            +
                def inline_break node
         | 
| 969 | 
            +
                  %(#{node.text}<br#{@void_element_slash}>)
         | 
| 970 | 
            +
                end
         | 
| 971 | 
            +
             | 
| 972 | 
            +
                def inline_button node
         | 
| 973 | 
            +
                  %(<b class="button">#{node.text}</b>)
         | 
| 974 | 
            +
                end
         | 
| 975 | 
            +
             | 
| 976 | 
            +
                def inline_callout node
         | 
| 977 | 
            +
                  if node.document.attr? 'icons', 'font'
         | 
| 978 | 
            +
                    %(<i class="conum" data-value="#{node.text}"></i><b>(#{node.text})</b>)
         | 
| 979 | 
            +
                  elsif node.document.attr? 'icons'
         | 
| 980 | 
            +
                    src = node.icon_uri("callouts/#{node.text}")
         | 
| 981 | 
            +
                    %(<img src="#{src}" alt="#{node.text}"#{@void_element_slash}>)
         | 
| 982 | 
            +
                  else
         | 
| 983 | 
            +
                    %(<b class="conum">(#{node.text})</b>)
         | 
| 984 | 
            +
                  end
         | 
| 985 | 
            +
                end
         | 
| 986 | 
            +
             | 
| 987 | 
            +
                def inline_footnote node
         | 
| 988 | 
            +
                  if (index = node.attr 'index')
         | 
| 989 | 
            +
                    if node.type == :xref
         | 
| 990 | 
            +
                      %(<span class="footnoteref">[<a class="footnote" href="#_footnote_#{index}" title="View footnote.">#{index}</a>]</span>)
         | 
| 991 | 
            +
                    else
         | 
| 992 | 
            +
                      id_attr = node.id ? %( id="_footnote_#{node.id}") : nil
         | 
| 993 | 
            +
                      %(<span class="footnote"#{id_attr}>[<a id="_footnoteref_#{index}" class="footnote" href="#_footnote_#{index}" title="View footnote.">#{index}</a>]</span>)
         | 
| 994 | 
            +
                    end
         | 
| 995 | 
            +
                  elsif node.type == :xref
         | 
| 996 | 
            +
                    %(<span class="footnoteref red" title="Unresolved footnote reference.">[#{node.text}]</span>)
         | 
| 997 | 
            +
                  end
         | 
| 998 | 
            +
                end
         | 
| 999 | 
            +
             | 
| 1000 | 
            +
                def inline_image node
         | 
| 1001 | 
            +
                  if (type = node.type) == 'icon' && (node.document.attr? 'icons', 'font')
         | 
| 1002 | 
            +
                    style_class = %(fa fa-#{node.target})
         | 
| 1003 | 
            +
                    if node.attr? 'size'
         | 
| 1004 | 
            +
                      style_class = %(#{style_class} fa-#{node.attr 'size'})
         | 
| 1005 | 
            +
                    end
         | 
| 1006 | 
            +
                    if node.attr? 'rotate'
         | 
| 1007 | 
            +
                      style_class = %(#{style_class} fa-rotate-#{node.attr 'rotate'})
         | 
| 1008 | 
            +
                    end
         | 
| 1009 | 
            +
                    if node.attr? 'flip'
         | 
| 1010 | 
            +
                      style_class = %(#{style_class} fa-flip-#{node.attr 'flip'})
         | 
| 1011 | 
            +
                    end
         | 
| 1012 | 
            +
                    title_attribute = (node.attr? 'title') ? %( title="#{node.attr 'title'}") : nil
         | 
| 1013 | 
            +
                    img = %(<i class="#{style_class}"#{title_attribute}></i>)
         | 
| 1014 | 
            +
                  elsif type == 'icon' && !(node.document.attr? 'icons')
         | 
| 1015 | 
            +
                    img = %([#{node.attr 'alt'}])
         | 
| 1016 | 
            +
                  else
         | 
| 1017 | 
            +
                    resolved_target = (type == 'icon') ? (node.icon_uri node.target) : (node.image_uri node.target)
         | 
| 1018 | 
            +
             | 
| 1019 | 
            +
                    attrs = ['alt', 'width', 'height', 'title'].map {|name|
         | 
| 1020 | 
            +
                      (node.attr? name) ? %( #{name}="#{node.attr name}") : nil
         | 
| 1021 | 
            +
                    }.join
         | 
| 1022 | 
            +
             | 
| 1023 | 
            +
                    img = %(<img src="#{resolved_target}"#{attrs}#{@void_element_slash}>)
         | 
| 1024 | 
            +
                  end
         | 
| 1025 | 
            +
             | 
| 1026 | 
            +
                  if node.attr? 'link'
         | 
| 1027 | 
            +
                    window_attr = (node.attr? 'window') ? %( target="#{node.attr 'window'}") : nil
         | 
| 1028 | 
            +
                    img = %(<a class="image" href="#{node.attr 'link'}"#{window_attr}>#{img}</a>)
         | 
| 1029 | 
            +
                  end
         | 
| 1030 | 
            +
             | 
| 1031 | 
            +
                  style_classes = (role = node.role) ? %(#{type} #{role}) : type
         | 
| 1032 | 
            +
                  style_attr = (node.attr? 'float') ? %( style="float: #{node.attr 'float'}") : nil
         | 
| 1033 | 
            +
             | 
| 1034 | 
            +
                  %(<span class="#{style_classes}"#{style_attr}>#{img}</span>)
         | 
| 1035 | 
            +
                end
         | 
| 1036 | 
            +
             | 
| 1037 | 
            +
                def inline_indexterm node
         | 
| 1038 | 
            +
                  node.type == :visible ? node.text : ''
         | 
| 1039 | 
            +
                end
         | 
| 1040 | 
            +
             | 
| 1041 | 
            +
                def inline_kbd node
         | 
| 1042 | 
            +
                  if (keys = node.attr 'keys').size == 1
         | 
| 1043 | 
            +
                    %(<kbd>#{keys[0]}</kbd>)
         | 
| 1044 | 
            +
                  else
         | 
| 1045 | 
            +
                    key_combo = keys.map {|key| %(<kbd>#{key}</kbd>+) }.join.chop
         | 
| 1046 | 
            +
                    %(<span class="keyseq">#{key_combo}</span>)
         | 
| 1047 | 
            +
                  end
         | 
| 1048 | 
            +
                end
         | 
| 1049 | 
            +
             | 
| 1050 | 
            +
                def inline_menu node
         | 
| 1051 | 
            +
                  menu = node.attr 'menu'
         | 
| 1052 | 
            +
                  if !(submenus = node.attr 'submenus').empty?
         | 
| 1053 | 
            +
                    submenu_path = submenus.map {|submenu| %(<span class="submenu">#{submenu}</span> ▸ ) }.join.chop
         | 
| 1054 | 
            +
                    %(<span class="menuseq"><span class="menu">#{menu}</span> ▸ #{submenu_path} <span class="menuitem">#{node.attr 'menuitem'}</span></span>)
         | 
| 1055 | 
            +
                  elsif (menuitem = node.attr 'menuitem')
         | 
| 1056 | 
            +
                    %(<span class="menuseq"><span class="menu">#{menu}</span> ▸ <span class="menuitem">#{menuitem}</span></span>)
         | 
| 1057 | 
            +
                  else
         | 
| 1058 | 
            +
                    %(<span class="menu">#{menu}</span>)
         | 
| 1059 | 
            +
                  end
         | 
| 1060 | 
            +
                end
         | 
| 1061 | 
            +
             | 
| 1062 | 
            +
                def inline_quoted node
         | 
| 1063 | 
            +
                  open, close, is_tag = QUOTE_TAGS[node.type]
         | 
| 1064 | 
            +
                  if (role = node.role)
         | 
| 1065 | 
            +
                    if is_tag
         | 
| 1066 | 
            +
                      quoted_text = %(#{open.chop} class="#{role}">#{node.text}#{close})
         | 
| 1067 | 
            +
                    else
         | 
| 1068 | 
            +
                      quoted_text = %(<span class="#{role}">#{open}#{node.text}#{close}</span>)
         | 
| 1069 | 
            +
                    end
         | 
| 1070 | 
            +
                  else
         | 
| 1071 | 
            +
                    quoted_text = %(#{open}#{node.text}#{close})
         | 
| 1072 | 
            +
                  end
         | 
| 1073 | 
            +
             | 
| 1074 | 
            +
                  node.id ? %(<a id="#{node.id}"></a>#{quoted_text}) : quoted_text
         | 
| 1075 | 
            +
                end
         | 
| 1076 | 
            +
             | 
| 1077 | 
            +
                def append_boolean_attribute name, xml
         | 
| 1078 | 
            +
                  xml ? %( #{name}="#{name}") : %( #{name})
         | 
| 1079 | 
            +
                end
         | 
| 1080 | 
            +
              end
         | 
| 1081 | 
            +
            end
         |