asciidoctor 1.5.8 → 2.0.0.rc.1

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.
Files changed (158) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.adoc +162 -17
  3. data/LICENSE +1 -1
  4. data/README-de.adoc +12 -13
  5. data/README-fr.adoc +11 -12
  6. data/README-jp.adoc +11 -12
  7. data/README-zh_CN.adoc +12 -13
  8. data/README.adoc +6 -7
  9. data/asciidoctor.gemspec +19 -24
  10. data/bin/asciidoctor +5 -4
  11. data/data/reference/syntax.adoc +283 -0
  12. data/data/stylesheets/asciidoctor-default.css +56 -52
  13. data/data/stylesheets/coderay-asciidoctor.css +7 -9
  14. data/lib/asciidoctor.rb +171 -232
  15. data/lib/asciidoctor/abstract_block.rb +96 -105
  16. data/lib/asciidoctor/abstract_node.rb +118 -139
  17. data/lib/asciidoctor/attribute_list.rb +10 -14
  18. data/lib/asciidoctor/block.rb +20 -19
  19. data/lib/asciidoctor/callouts.rb +4 -2
  20. data/lib/asciidoctor/cli.rb +3 -2
  21. data/lib/asciidoctor/cli/invoker.rb +14 -21
  22. data/lib/asciidoctor/cli/options.rb +64 -54
  23. data/lib/asciidoctor/converter.rb +357 -185
  24. data/lib/asciidoctor/converter/composite.rb +40 -48
  25. data/lib/asciidoctor/converter/docbook5.rb +604 -640
  26. data/lib/asciidoctor/converter/html5.rb +949 -963
  27. data/lib/asciidoctor/converter/manpage.rb +569 -548
  28. data/lib/asciidoctor/converter/template.rb +231 -272
  29. data/lib/asciidoctor/core_ext.rb +5 -18
  30. data/lib/asciidoctor/core_ext/float/truncate.rb +19 -0
  31. data/lib/asciidoctor/core_ext/match_data/names.rb +7 -0
  32. data/lib/asciidoctor/core_ext/nil_or_empty.rb +1 -0
  33. data/lib/asciidoctor/core_ext/regexp/is_match.rb +4 -2
  34. data/lib/asciidoctor/document.rb +399 -377
  35. data/lib/asciidoctor/extensions.rb +72 -140
  36. data/lib/asciidoctor/helpers.rb +122 -83
  37. data/lib/asciidoctor/inline.rb +5 -1
  38. data/lib/asciidoctor/list.rb +13 -11
  39. data/lib/asciidoctor/logging.rb +17 -16
  40. data/lib/asciidoctor/parser.rb +390 -423
  41. data/lib/asciidoctor/path_resolver.rb +10 -5
  42. data/lib/asciidoctor/reader.rb +286 -263
  43. data/lib/asciidoctor/rouge_ext.rb +39 -0
  44. data/lib/asciidoctor/section.rb +9 -8
  45. data/lib/asciidoctor/stylesheets.rb +19 -37
  46. data/lib/asciidoctor/substitutors.rb +364 -509
  47. data/lib/asciidoctor/syntax_highlighter.rb +238 -0
  48. data/lib/asciidoctor/syntax_highlighter/coderay.rb +87 -0
  49. data/lib/asciidoctor/syntax_highlighter/highlightjs.rb +26 -0
  50. data/lib/asciidoctor/syntax_highlighter/html_pipeline.rb +10 -0
  51. data/lib/asciidoctor/syntax_highlighter/prettify.rb +27 -0
  52. data/lib/asciidoctor/syntax_highlighter/pygments.rb +149 -0
  53. data/lib/asciidoctor/syntax_highlighter/rouge.rb +129 -0
  54. data/lib/asciidoctor/table.rb +73 -66
  55. data/lib/asciidoctor/timings.rb +4 -2
  56. data/lib/asciidoctor/version.rb +2 -1
  57. data/lib/asciidoctor/writer.rb +30 -0
  58. data/man/asciidoctor.1 +19 -15
  59. data/man/asciidoctor.adoc +14 -12
  60. metadata +69 -216
  61. data/CONTRIBUTING.adoc +0 -185
  62. data/Gemfile +0 -60
  63. data/Rakefile +0 -129
  64. data/bin/asciidoctor-safe +0 -15
  65. data/features/open_block.feature +0 -92
  66. data/features/pass_block.feature +0 -66
  67. data/features/step_definitions.rb +0 -49
  68. data/features/text_formatting.feature +0 -57
  69. data/features/xref.feature +0 -1039
  70. data/lib/asciidoctor/converter/base.rb +0 -59
  71. data/lib/asciidoctor/converter/docbook45.rb +0 -93
  72. data/lib/asciidoctor/converter/factory.rb +0 -226
  73. data/lib/asciidoctor/core_ext/1.8.7/base64/strict_encode64.rb +0 -6
  74. data/lib/asciidoctor/core_ext/1.8.7/concurrent/hash.rb +0 -5
  75. data/lib/asciidoctor/core_ext/1.8.7/hash/key.rb +0 -4
  76. data/lib/asciidoctor/core_ext/1.8.7/io/binread.rb +0 -6
  77. data/lib/asciidoctor/core_ext/1.8.7/io/write.rb +0 -5
  78. data/lib/asciidoctor/core_ext/1.8.7/string/chr.rb +0 -6
  79. data/lib/asciidoctor/core_ext/1.8.7/string/limit_bytesize.rb +0 -29
  80. data/lib/asciidoctor/core_ext/1.8.7/symbol/empty.rb +0 -6
  81. data/lib/asciidoctor/core_ext/1.8.7/symbol/length.rb +0 -6
  82. data/lib/asciidoctor/core_ext/string/limit_bytesize.rb +0 -10
  83. data/test/api_test.rb +0 -1240
  84. data/test/attribute_list_test.rb +0 -242
  85. data/test/attributes_test.rb +0 -1623
  86. data/test/blocks_test.rb +0 -3870
  87. data/test/converter_test.rb +0 -470
  88. data/test/document_test.rb +0 -1853
  89. data/test/extensions_test.rb +0 -1560
  90. data/test/fixtures/asciidoc_index.txt +0 -521
  91. data/test/fixtures/basic-docinfo-footer.html +0 -6
  92. data/test/fixtures/basic-docinfo-footer.xml +0 -8
  93. data/test/fixtures/basic-docinfo.html +0 -1
  94. data/test/fixtures/basic-docinfo.xml +0 -4
  95. data/test/fixtures/basic.asciidoc +0 -5
  96. data/test/fixtures/chapter-a.adoc +0 -3
  97. data/test/fixtures/child-include.adoc +0 -5
  98. data/test/fixtures/circle.svg +0 -9
  99. data/test/fixtures/custom-backends/erb/html5/block_paragraph.html.erb +0 -6
  100. data/test/fixtures/custom-backends/haml/docbook45/block_paragraph.xml.haml +0 -6
  101. data/test/fixtures/custom-backends/haml/html5-tweaks/block_paragraph.html.haml +0 -1
  102. data/test/fixtures/custom-backends/haml/html5/block_paragraph.html.haml +0 -3
  103. data/test/fixtures/custom-backends/haml/html5/block_sidebar.html.haml +0 -5
  104. data/test/fixtures/custom-backends/slim/docbook45/block_paragraph.xml.slim +0 -6
  105. data/test/fixtures/custom-backends/slim/html5/block_paragraph.html.slim +0 -3
  106. data/test/fixtures/custom-backends/slim/html5/block_sidebar.html.slim +0 -5
  107. data/test/fixtures/custom-docinfodir/basic-docinfo.html +0 -1
  108. data/test/fixtures/custom-docinfodir/docinfo.html +0 -1
  109. data/test/fixtures/docinfo-footer.html +0 -1
  110. data/test/fixtures/docinfo-footer.xml +0 -9
  111. data/test/fixtures/docinfo.html +0 -1
  112. data/test/fixtures/docinfo.xml +0 -3
  113. data/test/fixtures/doctime-localtime.adoc +0 -2
  114. data/test/fixtures/dot.gif +0 -0
  115. data/test/fixtures/encoding.asciidoc +0 -13
  116. data/test/fixtures/file-with-missing-include.adoc +0 -1
  117. data/test/fixtures/grandchild-include.adoc +0 -3
  118. data/test/fixtures/hello-asciidoctor.pdf +0 -69
  119. data/test/fixtures/include-file.asciidoc +0 -24
  120. data/test/fixtures/include-file.jsx +0 -8
  121. data/test/fixtures/include-file.ml +0 -3
  122. data/test/fixtures/include-file.xml +0 -5
  123. data/test/fixtures/lists.adoc +0 -96
  124. data/test/fixtures/master.adoc +0 -5
  125. data/test/fixtures/mismatched-end-tag.adoc +0 -7
  126. data/test/fixtures/other-chapters.adoc +0 -11
  127. data/test/fixtures/outer-include.adoc +0 -5
  128. data/test/fixtures/parent-include-restricted.adoc +0 -5
  129. data/test/fixtures/parent-include.adoc +0 -5
  130. data/test/fixtures/sample.asciidoc +0 -30
  131. data/test/fixtures/section-a.adoc +0 -4
  132. data/test/fixtures/stylesheets/custom.css +0 -3
  133. data/test/fixtures/subdir/index.adoc +0 -3
  134. data/test/fixtures/subdir/inner-include.adoc +0 -3
  135. data/test/fixtures/subdir/middle-include.adoc +0 -5
  136. data/test/fixtures/subs-docinfo.html +0 -2
  137. data/test/fixtures/subs.adoc +0 -6
  138. data/test/fixtures/tagged-class-enclosed.rb +0 -25
  139. data/test/fixtures/tagged-class.rb +0 -23
  140. data/test/fixtures/tip.gif +0 -0
  141. data/test/fixtures/unclosed-tag.adoc +0 -3
  142. data/test/fixtures/unexpected-end-tag.adoc +0 -4
  143. data/test/invoker_test.rb +0 -745
  144. data/test/links_test.rb +0 -855
  145. data/test/lists_test.rb +0 -5151
  146. data/test/logger_test.rb +0 -211
  147. data/test/manpage_test.rb +0 -660
  148. data/test/options_test.rb +0 -262
  149. data/test/paragraphs_test.rb +0 -562
  150. data/test/parser_test.rb +0 -742
  151. data/test/paths_test.rb +0 -395
  152. data/test/preamble_test.rb +0 -173
  153. data/test/reader_test.rb +0 -2161
  154. data/test/sections_test.rb +0 -3575
  155. data/test/substitutions_test.rb +0 -2066
  156. data/test/tables_test.rb +0 -2036
  157. data/test/test_helper.rb +0 -447
  158. data/test/text_test.rb +0 -309
@@ -1,390 +1,379 @@
1
- # encoding: UTF-8
1
+ # frozen_string_literal: true
2
2
  module Asciidoctor
3
- # A built-in {Converter} implementation that generates HTML 5 output
4
- # consistent with the html5 backend from AsciiDoc Python.
5
- class Converter::Html5Converter < Converter::BuiltIn
6
- (QUOTE_TAGS = {
7
- :monospaced => ['<code>', '</code>', true],
8
- :emphasis => ['<em>', '</em>', true],
9
- :strong => ['<strong>', '</strong>', true],
10
- :double => ['&#8220;', '&#8221;', false],
11
- :single => ['&#8216;', '&#8217;', false],
12
- :mark => ['<mark>', '</mark>', true],
13
- :superscript => ['<sup>', '</sup>', true],
14
- :subscript => ['<sub>', '</sub>', true],
15
- :asciimath => ['\$', '\$', false],
16
- :latexmath => ['\(', '\)', false]
17
- # Opal can't resolve these constants when referenced here
18
- #:asciimath => INLINE_MATH_DELIMITERS[:asciimath] + [false],
19
- #:latexmath => INLINE_MATH_DELIMITERS[:latexmath] + [false]
20
- }).default = ['', '', false]
21
-
22
- DropAnchorRx = /<(?:a[^>+]+|\/a)>/
23
- StemBreakRx = / *\\\n(?:\\?\n)*|\n\n+/
24
- SvgPreambleRx = /\A.*?(?=<svg\b)/m
25
- SvgStartTagRx = /\A<svg[^>]*>/
26
- DimensionAttributeRx = /\s(?:width|height|style)=(["']).*?\1/
27
-
28
- def initialize backend, opts = {}
29
- @xml_mode = opts[:htmlsyntax] == 'xml'
30
- @void_element_slash = @xml_mode ? '/' : nil
31
- @stylesheets = Stylesheets.instance
3
+ # A built-in {Converter} implementation that generates HTML 5 output
4
+ # consistent with the html5 backend from AsciiDoc Python.
5
+ class Converter::Html5Converter < Converter::Base
6
+ register_for 'html5'
7
+
8
+ (QUOTE_TAGS = {
9
+ monospaced: ['<code>', '</code>', true],
10
+ emphasis: ['<em>', '</em>', true],
11
+ strong: ['<strong>', '</strong>', true],
12
+ double: ['&#8220;', '&#8221;'],
13
+ single: ['&#8216;', '&#8217;'],
14
+ mark: ['<mark>', '</mark>', true],
15
+ superscript: ['<sup>', '</sup>', true],
16
+ subscript: ['<sub>', '</sub>', true],
17
+ asciimath: ['\$', '\$'],
18
+ latexmath: ['\(', '\)'],
19
+ # Opal can't resolve these constants when referenced here
20
+ #asciimath: INLINE_MATH_DELIMITERS[:asciimath] + [false],
21
+ #latexmath: INLINE_MATH_DELIMITERS[:latexmath] + [false],
22
+ }).default = ['', '']
23
+
24
+ DropAnchorRx = /<(?:a[^>+]+|\/a)>/
25
+ StemBreakRx = / *\\\n(?:\\?\n)*|\n\n+/
26
+ SvgPreambleRx = /\A.*?(?=<svg\b)/m
27
+ SvgStartTagRx = /\A<svg[^>]*>/
28
+ DimensionAttributeRx = /\s(?:width|height|style)=(["']).*?\1/
29
+
30
+ def initialize backend, opts = {}
31
+ @backend = backend
32
+ if opts[:htmlsyntax] == 'xml'
33
+ syntax = 'xml'
34
+ @xml_mode = true
35
+ @void_element_slash = '/'
36
+ else
37
+ syntax = 'html'
38
+ @xml_mode = nil
39
+ @void_element_slash = ''
32
40
  end
41
+ init_backend_traits basebackend: 'html', filetype: 'html', htmlsyntax: syntax, outfilesuffix: '.html', supports_templates: true
42
+ end
33
43
 
34
- def document node
35
- slash = @void_element_slash
36
- br = %(<br#{slash}>)
37
- unless (asset_uri_scheme = (node.attr 'asset-uri-scheme', 'https')).empty?
38
- asset_uri_scheme = %(#{asset_uri_scheme}:)
39
- end
40
- cdn_base = %(#{asset_uri_scheme}//cdnjs.cloudflare.com/ajax/libs)
41
- linkcss = node.attr? 'linkcss'
42
- result = ['<!DOCTYPE html>']
43
- lang_attribute = (node.attr? 'nolang') ? '' : %( lang="#{node.attr 'lang', 'en'}")
44
- result << %(<html#{@xml_mode ? ' xmlns="http://www.w3.org/1999/xhtml"' : ''}#{lang_attribute}>)
45
- result << %(<head>
44
+ def document node
45
+ br = %(<br#{slash = @void_element_slash}>)
46
+ unless (asset_uri_scheme = (node.attr 'asset-uri-scheme', 'https')).empty?
47
+ asset_uri_scheme = %(#{asset_uri_scheme}:)
48
+ end
49
+ cdn_base_url = %(#{asset_uri_scheme}//cdnjs.cloudflare.com/ajax/libs)
50
+ linkcss = node.attr? 'linkcss'
51
+ result = ['<!DOCTYPE html>']
52
+ lang_attribute = (node.attr? 'nolang') ? '' : %( lang="#{node.attr 'lang', 'en'}")
53
+ result << %(<html#{@xml_mode ? ' xmlns="http://www.w3.org/1999/xhtml"' : ''}#{lang_attribute}>)
54
+ result << %(<head>
46
55
  <meta charset="#{node.attr 'encoding', 'UTF-8'}"#{slash}>
47
- <!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"#{slash}><![endif]-->
56
+ <meta http-equiv="X-UA-Compatible" content="IE=edge"#{slash}>
48
57
  <meta name="viewport" content="width=device-width, initial-scale=1.0"#{slash}>
49
58
  <meta name="generator" content="Asciidoctor #{node.attr 'asciidoctor-version'}"#{slash}>)
50
- result << %(<meta name="application-name" content="#{node.attr 'app-name'}"#{slash}>) if node.attr? 'app-name'
51
- result << %(<meta name="description" content="#{node.attr 'description'}"#{slash}>) if node.attr? 'description'
52
- result << %(<meta name="keywords" content="#{node.attr 'keywords'}"#{slash}>) if node.attr? 'keywords'
53
- result << %(<meta name="author" content="#{((authors = node.attr 'authors').include? '<') ? (authors.gsub XmlSanitizeRx, '') : authors}"#{slash}>) if node.attr? 'authors'
54
- result << %(<meta name="copyright" content="#{node.attr 'copyright'}"#{slash}>) if node.attr? 'copyright'
55
- if node.attr? 'favicon'
56
- if (icon_href = node.attr 'favicon').empty?
57
- icon_href, icon_type = 'favicon.ico', 'image/x-icon'
58
- else
59
- icon_type = (icon_ext = ::File.extname icon_href) == '.ico' ? 'image/x-icon' : %(image/#{icon_ext.slice 1, icon_ext.length})
60
- end
61
- result << %(<link rel="icon" type="#{icon_type}" href="#{icon_href}"#{slash}>)
59
+ result << %(<meta name="application-name" content="#{node.attr 'app-name'}"#{slash}>) if node.attr? 'app-name'
60
+ result << %(<meta name="description" content="#{node.attr 'description'}"#{slash}>) if node.attr? 'description'
61
+ result << %(<meta name="keywords" content="#{node.attr 'keywords'}"#{slash}>) if node.attr? 'keywords'
62
+ result << %(<meta name="author" content="#{((authors = node.attr 'authors').include? '<') ? (authors.gsub XmlSanitizeRx, '') : authors}"#{slash}>) if node.attr? 'authors'
63
+ result << %(<meta name="copyright" content="#{node.attr 'copyright'}"#{slash}>) if node.attr? 'copyright'
64
+ if node.attr? 'favicon'
65
+ if (icon_href = node.attr 'favicon').empty?
66
+ icon_href, icon_type = 'favicon.ico', 'image/x-icon'
67
+ else
68
+ icon_type = (icon_ext = ::File.extname icon_href) == '.ico' ? 'image/x-icon' : %(image/#{icon_ext.slice 1, icon_ext.length})
62
69
  end
63
- result << %(<title>#{node.doctitle :sanitize => true, :use_fallback => true}</title>)
70
+ result << %(<link rel="icon" type="#{icon_type}" href="#{icon_href}"#{slash}>)
71
+ end
72
+ result << %(<title>#{node.doctitle sanitize: true, use_fallback: true}</title>)
64
73
 
65
- if DEFAULT_STYLESHEET_KEYS.include?(node.attr 'stylesheet')
66
- if (webfonts = node.attr 'webfonts')
67
- result << %(<link rel="stylesheet" href="#{asset_uri_scheme}//fonts.googleapis.com/css?family=#{webfonts.empty? ? 'Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700' : webfonts}"#{slash}>)
68
- end
69
- if linkcss
70
- result << %(<link rel="stylesheet" href="#{node.normalize_web_path DEFAULT_STYLESHEET_NAME, (node.attr 'stylesdir', ''), false}"#{slash}>)
71
- else
72
- result << @stylesheets.embed_primary_stylesheet
73
- end
74
- elsif node.attr? 'stylesheet'
75
- if linkcss
76
- result << %(<link rel="stylesheet" href="#{node.normalize_web_path((node.attr 'stylesheet'), (node.attr 'stylesdir', ''))}"#{slash}>)
77
- else
78
- result << %(<style>
79
- #{node.read_asset node.normalize_system_path((node.attr 'stylesheet'), (node.attr 'stylesdir', '')), :warn_on_failure => true, :label => 'stylesheet'}
74
+ if DEFAULT_STYLESHEET_KEYS.include?(node.attr 'stylesheet')
75
+ if (webfonts = node.attr 'webfonts')
76
+ result << %(<link rel="stylesheet" href="#{asset_uri_scheme}//fonts.googleapis.com/css?family=#{webfonts.empty? ? 'Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700' : webfonts}"#{slash}>)
77
+ end
78
+ if linkcss
79
+ result << %(<link rel="stylesheet" href="#{node.normalize_web_path DEFAULT_STYLESHEET_NAME, (node.attr 'stylesdir', ''), false}"#{slash}>)
80
+ else
81
+ result << %(<style>
82
+ #{Stylesheets.instance.primary_stylesheet_data}
80
83
  </style>)
81
- end
82
84
  end
83
-
84
- if node.attr? 'icons', 'font'
85
- if node.attr? 'iconfont-remote'
86
- result << %(<link rel="stylesheet" href="#{node.attr 'iconfont-cdn', %[#{cdn_base}/font-awesome/#{FONT_AWESOME_VERSION}/css/font-awesome.min.css]}"#{slash}>)
87
- else
88
- iconfont_stylesheet = %(#{node.attr 'iconfont-name', 'font-awesome'}.css)
89
- result << %(<link rel="stylesheet" href="#{node.normalize_web_path iconfont_stylesheet, (node.attr 'stylesdir', ''), false}"#{slash}>)
90
- end
85
+ elsif node.attr? 'stylesheet'
86
+ if linkcss
87
+ result << %(<link rel="stylesheet" href="#{node.normalize_web_path((node.attr 'stylesheet'), (node.attr 'stylesdir', ''))}"#{slash}>)
88
+ else
89
+ result << %(<style>
90
+ #{node.read_asset node.normalize_system_path((node.attr 'stylesheet'), (node.attr 'stylesdir', '')), warn_on_failure: true, label: 'stylesheet'}
91
+ </style>)
91
92
  end
93
+ end
92
94
 
93
- case (highlighter = node.attr 'source-highlighter')
94
- when 'coderay'
95
- if (node.attr 'coderay-css', 'class') == 'class'
96
- if linkcss
97
- result << %(<link rel="stylesheet" href="#{node.normalize_web_path @stylesheets.coderay_stylesheet_name, (node.attr 'stylesdir', ''), false}"#{slash}>)
98
- else
99
- result << @stylesheets.embed_coderay_stylesheet
100
- end
101
- end
102
- when 'pygments'
103
- if (node.attr 'pygments-css', 'class') == 'class'
104
- pygments_style = node.attr 'pygments-style'
105
- if linkcss
106
- result << %(<link rel="stylesheet" href="#{node.normalize_web_path @stylesheets.pygments_stylesheet_name(pygments_style), (node.attr 'stylesdir', ''), false}"#{slash}>)
107
- else
108
- result << (@stylesheets.embed_pygments_stylesheet pygments_style)
109
- end
110
- end
95
+ if node.attr? 'icons', 'font'
96
+ if node.attr? 'iconfont-remote'
97
+ result << %(<link rel="stylesheet" href="#{node.attr 'iconfont-cdn', %[#{cdn_base_url}/font-awesome/#{FONT_AWESOME_VERSION}/css/font-awesome.min.css]}"#{slash}>)
98
+ else
99
+ iconfont_stylesheet = %(#{node.attr 'iconfont-name', 'font-awesome'}.css)
100
+ result << %(<link rel="stylesheet" href="#{node.normalize_web_path iconfont_stylesheet, (node.attr 'stylesdir', ''), false}"#{slash}>)
111
101
  end
102
+ end
112
103
 
113
- unless (docinfo_content = node.docinfo).empty?
114
- result << docinfo_content
115
- end
104
+ if (syntax_hl = node.syntax_highlighter) && (syntax_hl.docinfo? :head)
105
+ result << (syntax_hl.docinfo :head, node, linkcss: linkcss)
106
+ end
116
107
 
117
- result << '</head>'
118
- body_attrs = node.id ? [%(id="#{node.id}")] : []
119
- if (sectioned = node.sections?) && (node.attr? 'toc-class') && (node.attr? 'toc') && (node.attr? 'toc-placement', 'auto')
120
- classes = [node.doctype, (node.attr 'toc-class'), %(toc-#{node.attr 'toc-position', 'header'})]
121
- else
122
- classes = [node.doctype]
123
- end
124
- classes << (node.attr 'docrole') if node.attr? 'docrole'
125
- body_attrs << %(class="#{classes.join ' '}")
126
- body_attrs << %(style="max-width: #{node.attr 'max-width'};") if node.attr? 'max-width'
127
- result << %(<body #{body_attrs.join ' '}>)
128
-
129
- unless node.noheader
130
- result << '<div id="header">'
131
- if node.doctype == 'manpage'
132
- result << %(<h1>#{node.doctitle} Manual Page</h1>)
133
- if sectioned && (node.attr? 'toc') && (node.attr? 'toc-placement', 'auto')
134
- result << %(<div id="toc" class="#{node.attr 'toc-class', 'toc'}">
108
+ unless (docinfo_content = node.docinfo).empty?
109
+ result << docinfo_content
110
+ end
111
+
112
+ result << '</head>'
113
+ body_attrs = node.id ? [%(id="#{node.id}")] : []
114
+ if (sectioned = node.sections?) && (node.attr? 'toc-class') && (node.attr? 'toc') && (node.attr? 'toc-placement', 'auto')
115
+ classes = [node.doctype, (node.attr 'toc-class'), %(toc-#{node.attr 'toc-position', 'header'})]
116
+ else
117
+ classes = [node.doctype]
118
+ end
119
+ classes << node.role if node.role?
120
+ body_attrs << %(class="#{classes.join ' '}")
121
+ body_attrs << %(style="max-width: #{node.attr 'max-width'};") if node.attr? 'max-width'
122
+ result << %(<body #{body_attrs.join ' '}>)
123
+
124
+ unless (docinfo_content = node.docinfo :header).empty?
125
+ result << docinfo_content
126
+ end
127
+
128
+ unless node.noheader
129
+ result << '<div id="header">'
130
+ if node.doctype == 'manpage'
131
+ result << %(<h1>#{node.doctitle} Manual Page</h1>)
132
+ if sectioned && (node.attr? 'toc') && (node.attr? 'toc-placement', 'auto')
133
+ result << %(<div id="toc" class="#{node.attr 'toc-class', 'toc'}">
135
134
  <div id="toctitle">#{node.attr 'toc-title'}</div>
136
135
  #{outline node}
137
136
  </div>)
137
+ end
138
+ result << (_generate_manname_section node) if node.attr? 'manpurpose'
139
+ else
140
+ if node.header?
141
+ result << %(<h1>#{node.header.title}</h1>) unless node.notitle
142
+ details = []
143
+ idx = 1
144
+ node.authors.each do |author|
145
+ details << %(<span id="author#{idx > 1 ? idx : ''}" class="author">#{author.name}</span>#{br})
146
+ details << %(<span id="email#{idx > 1 ? idx : ''}" class="email">#{node.sub_macros author.email}</span>#{br}) if author.email
147
+ idx += 1
138
148
  end
139
- result << (generate_manname_section node) if node.attr? 'manpurpose'
140
- else
141
- if node.has_header?
142
- result << %(<h1>#{node.header.title}</h1>) unless node.notitle
143
- details = []
144
- idx = 1
145
- node.authors.each do |author|
146
- details << %(<span id="author#{idx > 1 ? idx : ''}" class="author">#{author.name}</span>#{br})
147
- details << %(<span id="email#{idx > 1 ? idx : ''}" class="email">#{node.sub_macros author.email}</span>#{br}) if author.email
148
- idx += 1
149
- end
150
- if node.attr? 'revnumber'
151
- details << %(<span id="revnumber">#{((node.attr 'version-label') || '').downcase} #{node.attr 'revnumber'}#{(node.attr? 'revdate') ? ',' : ''}</span>)
152
- end
153
- if node.attr? 'revdate'
154
- details << %(<span id="revdate">#{node.attr 'revdate'}</span>)
155
- end
156
- if node.attr? 'revremark'
157
- details << %(#{br}<span id="revremark">#{node.attr 'revremark'}</span>)
158
- end
159
- unless details.empty?
160
- result << '<div class="details">'
161
- result.concat details
162
- result << '</div>'
163
- end
149
+ if node.attr? 'revnumber'
150
+ details << %(<span id="revnumber">#{((node.attr 'version-label') || '').downcase} #{node.attr 'revnumber'}#{(node.attr? 'revdate') ? ',' : ''}</span>)
151
+ end
152
+ if node.attr? 'revdate'
153
+ details << %(<span id="revdate">#{node.attr 'revdate'}</span>)
154
+ end
155
+ if node.attr? 'revremark'
156
+ details << %(#{br}<span id="revremark">#{node.attr 'revremark'}</span>)
164
157
  end
158
+ unless details.empty?
159
+ result << '<div class="details">'
160
+ result.concat details
161
+ result << '</div>'
162
+ end
163
+ end
165
164
 
166
- if sectioned && (node.attr? 'toc') && (node.attr? 'toc-placement', 'auto')
167
- result << %(<div id="toc" class="#{node.attr 'toc-class', 'toc'}">
165
+ if sectioned && (node.attr? 'toc') && (node.attr? 'toc-placement', 'auto')
166
+ result << %(<div id="toc" class="#{node.attr 'toc-class', 'toc'}">
168
167
  <div id="toctitle">#{node.attr 'toc-title'}</div>
169
168
  #{outline node}
170
169
  </div>)
171
- end
172
170
  end
173
- result << '</div>'
174
171
  end
172
+ result << '</div>'
173
+ end
175
174
 
176
- result << %(<div id="content">
175
+ result << %(<div id="content">
177
176
  #{node.content}
178
177
  </div>)
179
178
 
180
- if node.footnotes? && !(node.attr? 'nofootnotes')
181
- result << %(<div id="footnotes">
179
+ if node.footnotes? && !(node.attr? 'nofootnotes')
180
+ result << %(<div id="footnotes">
182
181
  <hr#{slash}>)
183
- node.footnotes.each do |footnote|
184
- result << %(<div class="footnote" id="_footnotedef_#{footnote.index}">
182
+ node.footnotes.each do |footnote|
183
+ result << %(<div class="footnote" id="_footnotedef_#{footnote.index}">
185
184
  <a href="#_footnoteref_#{footnote.index}">#{footnote.index}</a>. #{footnote.text}
186
185
  </div>)
187
- end
188
- result << '</div>'
189
186
  end
187
+ result << '</div>'
188
+ end
190
189
 
191
- unless node.nofooter
192
- result << '<div id="footer">'
193
- result << '<div id="footer-text">'
194
- result << %(#{node.attr 'version-label'} #{node.attr 'revnumber'}#{br}) if node.attr? 'revnumber'
195
- result << %(#{node.attr 'last-update-label'} #{node.attr 'docdatetime'}) if (node.attr? 'last-update-label') && !(node.attr? 'reproducible')
196
- result << '</div>'
197
- result << '</div>'
198
- end
190
+ unless node.nofooter
191
+ result << '<div id="footer">'
192
+ result << '<div id="footer-text">'
193
+ result << %(#{node.attr 'version-label'} #{node.attr 'revnumber'}#{br}) if node.attr? 'revnumber'
194
+ result << %(#{node.attr 'last-update-label'} #{node.attr 'docdatetime'}) if (node.attr? 'last-update-label') && !(node.attr? 'reproducible')
195
+ result << '</div>'
196
+ result << '</div>'
197
+ end
199
198
 
200
- unless (docinfo_content = node.docinfo :footer).empty?
201
- result << docinfo_content
202
- end
199
+ # JavaScript (and auxiliary stylesheets) loaded at the end of body for performance reasons
200
+ # See http://www.html5rocks.com/en/tutorials/speed/script-loading/
203
201
 
204
- # Load Javascript at the end of body for performance
205
- # See http://www.html5rocks.com/en/tutorials/speed/script-loading/
206
- case highlighter
207
- when 'highlightjs', 'highlight.js'
208
- highlightjs_path = node.attr 'highlightjsdir', %(#{cdn_base}/highlight.js/9.13.1)
209
- result << %(<link rel="stylesheet" href="#{highlightjs_path}/styles/#{node.attr 'highlightjs-theme', 'github'}.min.css"#{slash}>)
210
- result << %(<script src="#{highlightjs_path}/highlight.min.js"></script>
211
- <script>hljs.initHighlighting()</script>)
212
- when 'prettify'
213
- prettify_path = node.attr 'prettifydir', %(#{cdn_base}/prettify/r298)
214
- result << %(<link rel="stylesheet" href="#{prettify_path}/#{node.attr 'prettify-theme', 'prettify'}.min.css"#{slash}>)
215
- result << %(<script src="#{prettify_path}/prettify.min.js"></script>
216
- <script>prettyPrint()</script>)
217
- end
202
+ if syntax_hl && (syntax_hl.docinfo? :footer)
203
+ result << (syntax_hl.docinfo :footer, node, cdn_base_url: cdn_base_url, linkcss: linkcss, self_closing_tag_slash: slash)
204
+ end
218
205
 
219
- if node.attr? 'stem'
220
- eqnums_val = node.attr 'eqnums', 'none'
221
- eqnums_val = 'AMS' if eqnums_val.empty?
222
- eqnums_opt = %( equationNumbers: { autoNumber: "#{eqnums_val}" } )
223
- # IMPORTANT inspect calls on delimiter arrays are intentional for JavaScript compat (emulates JSON.stringify)
224
- result << %(<script type="text/x-mathjax-config">
206
+ if node.attr? 'stem'
207
+ eqnums_val = node.attr 'eqnums', 'none'
208
+ eqnums_val = 'AMS' if eqnums_val.empty?
209
+ eqnums_opt = %( equationNumbers: { autoNumber: "#{eqnums_val}" } )
210
+ # IMPORTANT inspect calls on delimiter arrays are intentional for JavaScript compat (emulates JSON.stringify)
211
+ result << %(<script type="text/x-mathjax-config">
225
212
  MathJax.Hub.Config({
226
- messageStyle: "none",
227
- tex2jax: {
228
- inlineMath: [#{INLINE_MATH_DELIMITERS[:latexmath].inspect}],
229
- displayMath: [#{BLOCK_MATH_DELIMITERS[:latexmath].inspect}],
230
- ignoreClass: "nostem|nolatexmath"
231
- },
232
- asciimath2jax: {
233
- delimiters: [#{BLOCK_MATH_DELIMITERS[:asciimath].inspect}],
234
- ignoreClass: "nostem|noasciimath"
235
- },
236
- TeX: {#{eqnums_opt}}
213
+ messageStyle: "none",
214
+ tex2jax: {
215
+ inlineMath: [#{INLINE_MATH_DELIMITERS[:latexmath].inspect}],
216
+ displayMath: [#{BLOCK_MATH_DELIMITERS[:latexmath].inspect}],
217
+ ignoreClass: "nostem|nolatexmath"
218
+ },
219
+ asciimath2jax: {
220
+ delimiters: [#{BLOCK_MATH_DELIMITERS[:asciimath].inspect}],
221
+ ignoreClass: "nostem|noasciimath"
222
+ },
223
+ TeX: {#{eqnums_opt}}
237
224
  });
238
225
  </script>
239
- <script src="#{cdn_base}/mathjax/#{MATHJAX_VERSION}/MathJax.js?config=TeX-MML-AM_HTMLorMML"></script>)
240
- end
226
+ <script src="#{cdn_base_url}/mathjax/#{MATHJAX_VERSION}/MathJax.js?config=TeX-MML-AM_HTMLorMML"></script>)
227
+ end
241
228
 
242
- result << '</body>'
243
- result << '</html>'
244
- result.join LF
229
+ unless (docinfo_content = node.docinfo :footer).empty?
230
+ result << docinfo_content
245
231
  end
246
232
 
247
- def embedded node
248
- result = []
249
- if node.doctype == 'manpage'
250
- # QUESTION should notitle control the manual page title?
251
- unless node.notitle
252
- id_attr = node.id ? %( id="#{node.id}") : ''
253
- result << %(<h1#{id_attr}>#{node.doctitle} Manual Page</h1>)
254
- end
255
- result << (generate_manname_section node) if node.attr? 'manpurpose'
256
- else
257
- if node.has_header? && !node.notitle
258
- id_attr = node.id ? %( id="#{node.id}") : ''
259
- result << %(<h1#{id_attr}>#{node.header.title}</h1>)
260
- end
233
+ result << '</body>'
234
+ result << '</html>'
235
+ result.join LF
236
+ end
237
+
238
+ def embedded node
239
+ result = []
240
+ if node.doctype == 'manpage'
241
+ # QUESTION should notitle control the manual page title?
242
+ unless node.notitle
243
+ id_attr = node.id ? %( id="#{node.id}") : ''
244
+ result << %(<h1#{id_attr}>#{node.doctitle} Manual Page</h1>)
261
245
  end
246
+ result << (_generate_manname_section node) if node.attr? 'manpurpose'
247
+ elsif node.header? && !node.notitle
248
+ id_attr = node.id ? %( id="#{node.id}") : ''
249
+ result << %(<h1#{id_attr}>#{node.header.title}</h1>)
250
+ end
262
251
 
263
- if node.sections? && (node.attr? 'toc') && (toc_p = node.attr 'toc-placement') != 'macro' && toc_p != 'preamble'
264
- result << %(<div id="toc" class="toc">
252
+ if node.sections? && (node.attr? 'toc') && (toc_p = node.attr 'toc-placement') != 'macro' && toc_p != 'preamble'
253
+ result << %(<div id="toc" class="toc">
265
254
  <div id="toctitle">#{node.attr 'toc-title'}</div>
266
255
  #{outline node}
267
256
  </div>)
268
- end
257
+ end
269
258
 
270
- result << node.content
259
+ result << node.content
271
260
 
272
- if node.footnotes? && !(node.attr? 'nofootnotes')
273
- result << %(<div id="footnotes">
261
+ if node.footnotes? && !(node.attr? 'nofootnotes')
262
+ result << %(<div id="footnotes">
274
263
  <hr#{@void_element_slash}>)
275
- node.footnotes.each do |footnote|
276
- result << %(<div class="footnote" id="_footnotedef_#{footnote.index}">
264
+ node.footnotes.each do |footnote|
265
+ result << %(<div class="footnote" id="_footnotedef_#{footnote.index}">
277
266
  <a href="#_footnoteref_#{footnote.index}">#{footnote.index}</a>. #{footnote.text}
278
267
  </div>)
279
- end
280
- result << '</div>'
281
268
  end
282
-
283
- result.join LF
269
+ result << '</div>'
284
270
  end
285
271
 
286
- def outline node, opts = {}
287
- return unless node.sections?
288
- sectnumlevels = opts[:sectnumlevels] || (node.document.attributes['sectnumlevels'] || 3).to_i
289
- toclevels = opts[:toclevels] || (node.document.attributes['toclevels'] || 2).to_i
290
- sections = node.sections
291
- # FIXME top level is incorrect if a multipart book starts with a special section defined at level 0
292
- result = [%(<ul class="sectlevel#{sections[0].level}">)]
293
- sections.each do |section|
294
- slevel = section.level
295
- if section.caption
296
- stitle = section.captioned_title
297
- elsif section.numbered && slevel <= sectnumlevels
298
- if slevel < 2 && node.document.doctype == 'book'
299
- if section.sectname == 'chapter'
300
- stitle = %(#{(signifier = node.document.attributes['chapter-signifier']) ? "#{signifier} " : ''}#{section.sectnum} #{section.title})
301
- elsif section.sectname == 'part'
302
- stitle = %(#{(signifier = node.document.attributes['part-signifier']) ? "#{signifier} " : ''}#{section.sectnum nil, ':'} #{section.title})
303
- else
304
- stitle = %(#{section.sectnum} #{section.title})
305
- end
272
+ result.join LF
273
+ end
274
+
275
+ def outline node, opts = {}
276
+ return unless node.sections?
277
+ sectnumlevels = opts[:sectnumlevels] || (node.document.attributes['sectnumlevels'] || 3).to_i
278
+ toclevels = opts[:toclevels] || (node.document.attributes['toclevels'] || 2).to_i
279
+ sections = node.sections
280
+ # FIXME top level is incorrect if a multipart book starts with a special section defined at level 0
281
+ result = [%(<ul class="sectlevel#{sections[0].level}">)]
282
+ sections.each do |section|
283
+ slevel = section.level
284
+ if section.caption
285
+ stitle = section.captioned_title
286
+ elsif section.numbered && slevel <= sectnumlevels
287
+ if slevel < 2 && node.document.doctype == 'book'
288
+ if section.sectname == 'chapter'
289
+ stitle = %(#{(signifier = node.document.attributes['chapter-signifier']) ? "#{signifier} " : ''}#{section.sectnum} #{section.title})
290
+ elsif section.sectname == 'part'
291
+ stitle = %(#{(signifier = node.document.attributes['part-signifier']) ? "#{signifier} " : ''}#{section.sectnum nil, ':'} #{section.title})
306
292
  else
307
293
  stitle = %(#{section.sectnum} #{section.title})
308
294
  end
309
295
  else
310
- stitle = section.title
311
- end
312
- stitle = stitle.gsub DropAnchorRx, '' if stitle.include? '<a'
313
- if slevel < toclevels && (child_toc_level = outline section, :toclevels => toclevels, :sectnumlevels => sectnumlevels)
314
- result << %(<li><a href="##{section.id}">#{stitle}</a>)
315
- result << child_toc_level
316
- result << '</li>'
317
- else
318
- result << %(<li><a href="##{section.id}">#{stitle}</a></li>)
296
+ stitle = %(#{section.sectnum} #{section.title})
319
297
  end
298
+ else
299
+ stitle = section.title
300
+ end
301
+ stitle = stitle.gsub DropAnchorRx, '' if stitle.include? '<a'
302
+ if slevel < toclevels && (child_toc_level = outline section, toclevels: toclevels, sectnumlevels: sectnumlevels)
303
+ result << %(<li><a href="##{section.id}">#{stitle}</a>)
304
+ result << child_toc_level
305
+ result << '</li>'
306
+ else
307
+ result << %(<li><a href="##{section.id}">#{stitle}</a></li>)
320
308
  end
321
- result << '</ul>'
322
- result.join LF
323
309
  end
310
+ result << '</ul>'
311
+ result.join LF
312
+ end
324
313
 
325
- def section node
326
- doc_attrs = node.document.attributes
327
- level = node.level
328
- if node.caption
329
- title = node.captioned_title
330
- elsif node.numbered && level <= (doc_attrs['sectnumlevels'] || 3).to_i
331
- if level < 2 && node.document.doctype == 'book'
332
- if node.sectname == 'chapter'
333
- title = %(#{(signifier = doc_attrs['chapter-signifier']) ? "#{signifier} " : ''}#{node.sectnum} #{node.title})
334
- elsif node.sectname == 'part'
335
- title = %(#{(signifier = doc_attrs['part-signifier']) ? "#{signifier} " : ''}#{node.sectnum nil, ':'} #{node.title})
336
- else
337
- title = %(#{node.sectnum} #{node.title})
338
- end
314
+ def section node
315
+ doc_attrs = node.document.attributes
316
+ level = node.level
317
+ if node.caption
318
+ title = node.captioned_title
319
+ elsif node.numbered && level <= (doc_attrs['sectnumlevels'] || 3).to_i
320
+ if level < 2 && node.document.doctype == 'book'
321
+ if node.sectname == 'chapter'
322
+ title = %(#{(signifier = doc_attrs['chapter-signifier']) ? "#{signifier} " : ''}#{node.sectnum} #{node.title})
323
+ elsif node.sectname == 'part'
324
+ title = %(#{(signifier = doc_attrs['part-signifier']) ? "#{signifier} " : ''}#{node.sectnum nil, ':'} #{node.title})
339
325
  else
340
326
  title = %(#{node.sectnum} #{node.title})
341
327
  end
342
328
  else
343
- title = node.title
329
+ title = %(#{node.sectnum} #{node.title})
344
330
  end
345
- if node.id
346
- id_attr = %( id="#{id = node.id}")
347
- if doc_attrs['sectlinks']
348
- title = %(<a class="link" href="##{id}">#{title}</a>)
349
- end
350
- if doc_attrs['sectanchors']
351
- # QUESTION should we add a font-based icon in anchor if icons=font?
352
- if doc_attrs['sectanchors'] == 'after'
353
- title = %(#{title}<a class="anchor" href="##{id}"></a>)
354
- else
355
- title = %(<a class="anchor" href="##{id}"></a>#{title})
356
- end
331
+ else
332
+ title = node.title
333
+ end
334
+ if node.id
335
+ id_attr = %( id="#{id = node.id}")
336
+ if doc_attrs['sectlinks']
337
+ title = %(<a class="link" href="##{id}">#{title}</a>)
338
+ end
339
+ if doc_attrs['sectanchors']
340
+ # QUESTION should we add a font-based icon in anchor if icons=font?
341
+ if doc_attrs['sectanchors'] == 'after'
342
+ title = %(#{title}<a class="anchor" href="##{id}"></a>)
343
+ else
344
+ title = %(<a class="anchor" href="##{id}"></a>#{title})
357
345
  end
358
- else
359
- id_attr = ''
360
346
  end
361
- if level == 0
362
- %(<h1#{id_attr} class="sect0#{(role = node.role) ? " #{role}" : ''}">#{title}</h1>
347
+ else
348
+ id_attr = ''
349
+ end
350
+ if level == 0
351
+ %(<h1#{id_attr} class="sect0#{(role = node.role) ? " #{role}" : ''}">#{title}</h1>
363
352
  #{node.content})
364
- else
365
- %(<div class="sect#{level}#{(role = node.role) ? " #{role}" : ''}">
353
+ else
354
+ %(<div class="sect#{level}#{(role = node.role) ? " #{role}" : ''}">
366
355
  <h#{level + 1}#{id_attr}>#{title}</h#{level + 1}>
367
356
  #{level == 1 ? %[<div class="sectionbody">
368
357
  #{node.content}
369
358
  </div>] : node.content}
370
359
  </div>)
371
- end
372
360
  end
361
+ end
373
362
 
374
- def admonition node
375
- id_attr = node.id ? %( id="#{node.id}") : ''
376
- name = node.attr 'name'
377
- title_element = node.title? ? %(<div class="title">#{node.title}</div>\n) : ''
378
- if node.document.attr? 'icons'
379
- if (node.document.attr? 'icons', 'font') && !(node.attr? 'icon')
380
- label = %(<i class="fa icon-#{name}" title="#{node.attr 'textlabel'}"></i>)
381
- else
382
- label = %(<img src="#{node.icon_uri name}" alt="#{node.attr 'textlabel'}"#{@void_element_slash}>)
383
- end
363
+ def admonition node
364
+ id_attr = node.id ? %( id="#{node.id}") : ''
365
+ name = node.attr 'name'
366
+ title_element = node.title? ? %(<div class="title">#{node.title}</div>\n) : ''
367
+ if node.document.attr? 'icons'
368
+ if (node.document.attr? 'icons', 'font') && !(node.attr? 'icon')
369
+ label = %(<i class="fa icon-#{name}" title="#{node.attr 'textlabel'}"></i>)
384
370
  else
385
- label = %(<div class="title">#{node.attr 'textlabel'}</div>)
371
+ label = %(<img src="#{node.icon_uri name}" alt="#{node.attr 'textlabel'}"#{@void_element_slash}>)
386
372
  end
387
- %(<div#{id_attr} class="admonitionblock #{name}#{(role = node.role) ? " #{role}" : ''}">
373
+ else
374
+ label = %(<div class="title">#{node.attr 'textlabel'}</div>)
375
+ end
376
+ %(<div#{id_attr} class="admonitionblock #{name}#{(role = node.role) ? " #{role}" : ''}">
388
377
  <table>
389
378
  <tr>
390
379
  <td class="icon">
@@ -396,853 +385,850 @@ MathJax.Hub.Config({
396
385
  </tr>
397
386
  </table>
398
387
  </div>)
399
- end
388
+ end
400
389
 
401
- def audio node
402
- xml = @xml_mode
403
- id_attribute = node.id ? %( id="#{node.id}") : ''
404
- classes = ['audioblock', node.role].compact
405
- class_attribute = %( class="#{classes.join ' '}")
406
- title_element = node.title? ? %(<div class="title">#{node.title}</div>\n) : ''
407
- start_t = node.attr 'start', nil, false
408
- end_t = node.attr 'end', nil, false
409
- time_anchor = (start_t || end_t) ? %(#t=#{start_t || ''}#{end_t ? ",#{end_t}" : ''}) : ''
410
- %(<div#{id_attribute}#{class_attribute}>
390
+ def audio node
391
+ xml = @xml_mode
392
+ id_attribute = node.id ? %( id="#{node.id}") : ''
393
+ classes = ['audioblock', node.role].compact
394
+ class_attribute = %( class="#{classes.join ' '}")
395
+ title_element = node.title? ? %(<div class="title">#{node.title}</div>\n) : ''
396
+ start_t = node.attr 'start'
397
+ end_t = node.attr 'end'
398
+ time_anchor = (start_t || end_t) ? %(#t=#{start_t || ''}#{end_t ? ",#{end_t}" : ''}) : ''
399
+ %(<div#{id_attribute}#{class_attribute}>
411
400
  #{title_element}<div class="content">
412
- <audio src="#{node.media_uri(node.attr 'target')}#{time_anchor}"#{(node.option? 'autoplay') ? (append_boolean_attribute 'autoplay', xml) : ''}#{(node.option? 'nocontrols') ? '' : (append_boolean_attribute 'controls', xml)}#{(node.option? 'loop') ? (append_boolean_attribute 'loop', xml) : ''}>
401
+ <audio src="#{node.media_uri(node.attr 'target')}#{time_anchor}"#{(node.option? 'autoplay') ? (_append_boolean_attribute 'autoplay', xml) : ''}#{(node.option? 'nocontrols') ? '' : (_append_boolean_attribute 'controls', xml)}#{(node.option? 'loop') ? (_append_boolean_attribute 'loop', xml) : ''}>
413
402
  Your browser does not support the audio tag.
414
403
  </audio>
415
404
  </div>
416
405
  </div>)
417
- end
406
+ end
418
407
 
419
- def colist node
420
- result = []
421
- id_attribute = node.id ? %( id="#{node.id}") : ''
422
- classes = ['colist', node.style, node.role].compact
423
- class_attribute = %( class="#{classes.join ' '}")
424
-
425
- result << %(<div#{id_attribute}#{class_attribute}>)
426
- result << %(<div class="title">#{node.title}</div>) if node.title?
427
-
428
- if node.document.attr? 'icons'
429
- result << '<table>'
430
- font_icons, num = (node.document.attr? 'icons', 'font'), 0
431
- node.items.each do |item|
432
- num += 1
433
- if font_icons
434
- num_label = %(<i class="conum" data-value="#{num}"></i><b>#{num}</b>)
435
- else
436
- num_label = %(<img src="#{node.icon_uri "callouts/#{num}"}" alt="#{num}"#{@void_element_slash}>)
437
- end
438
- result << %(<tr>
408
+ def colist node
409
+ result = []
410
+ id_attribute = node.id ? %( id="#{node.id}") : ''
411
+ classes = ['colist', node.style, node.role].compact
412
+ class_attribute = %( class="#{classes.join ' '}")
413
+
414
+ result << %(<div#{id_attribute}#{class_attribute}>)
415
+ result << %(<div class="title">#{node.title}</div>) if node.title?
416
+
417
+ if node.document.attr? 'icons'
418
+ result << '<table>'
419
+ font_icons, num = (node.document.attr? 'icons', 'font'), 0
420
+ node.items.each do |item|
421
+ num += 1
422
+ if font_icons
423
+ num_label = %(<i class="conum" data-value="#{num}"></i><b>#{num}</b>)
424
+ else
425
+ num_label = %(<img src="#{node.icon_uri "callouts/#{num}"}" alt="#{num}"#{@void_element_slash}>)
426
+ end
427
+ result << %(<tr>
439
428
  <td>#{num_label}</td>
440
429
  <td>#{item.text}#{item.blocks? ? LF + item.content : ''}</td>
441
430
  </tr>)
442
- end
443
- result << '</table>'
444
- else
445
- result << '<ol>'
446
- node.items.each do |item|
447
- result << %(<li>
431
+ end
432
+ result << '</table>'
433
+ else
434
+ result << '<ol>'
435
+ node.items.each do |item|
436
+ result << %(<li>
448
437
  <p>#{item.text}</p>#{item.blocks? ? LF + item.content : ''}
449
438
  </li>)
450
- end
451
- result << '</ol>'
452
439
  end
453
-
454
- result << '</div>'
455
- result.join LF
440
+ result << '</ol>'
456
441
  end
457
442
 
458
- def dlist node
459
- result = []
460
- id_attribute = node.id ? %( id="#{node.id}") : ''
443
+ result << '</div>'
444
+ result.join LF
445
+ end
461
446
 
462
- classes = case node.style
463
- when 'qanda'
464
- ['qlist', 'qanda', node.role]
465
- when 'horizontal'
466
- ['hdlist', node.role]
467
- else
468
- ['dlist', node.style, node.role]
469
- end.compact
470
-
471
- class_attribute = %( class="#{classes.join ' '}")
472
-
473
- result << %(<div#{id_attribute}#{class_attribute}>)
474
- result << %(<div class="title">#{node.title}</div>) if node.title?
475
- case node.style
476
- when 'qanda'
477
- result << '<ol>'
478
- node.items.each do |terms, dd|
479
- result << '<li>'
480
- [*terms].each do |dt|
481
- result << %(<p><em>#{dt.text}</em></p>)
482
- end
483
- if dd
484
- result << %(<p>#{dd.text}</p>) if dd.text?
485
- result << dd.content if dd.blocks?
486
- end
487
- result << '</li>'
447
+ def dlist node
448
+ result = []
449
+ id_attribute = node.id ? %( id="#{node.id}") : ''
450
+
451
+ classes = case node.style
452
+ when 'qanda'
453
+ ['qlist', 'qanda', node.role]
454
+ when 'horizontal'
455
+ ['hdlist', node.role]
456
+ else
457
+ ['dlist', node.style, node.role]
458
+ end.compact
459
+
460
+ class_attribute = %( class="#{classes.join ' '}")
461
+
462
+ result << %(<div#{id_attribute}#{class_attribute}>)
463
+ result << %(<div class="title">#{node.title}</div>) if node.title?
464
+ case node.style
465
+ when 'qanda'
466
+ result << '<ol>'
467
+ node.items.each do |terms, dd|
468
+ result << '<li>'
469
+ terms.each do |dt|
470
+ result << %(<p><em>#{dt.text}</em></p>)
488
471
  end
489
- result << '</ol>'
490
- when 'horizontal'
491
- slash = @void_element_slash
492
- result << '<table>'
493
- if (node.attr? 'labelwidth') || (node.attr? 'itemwidth')
494
- result << '<colgroup>'
495
- col_style_attribute = (node.attr? 'labelwidth') ? %( style="width: #{(node.attr 'labelwidth').chomp '%'}%;") : ''
496
- result << %(<col#{col_style_attribute}#{slash}>)
497
- col_style_attribute = (node.attr? 'itemwidth') ? %( style="width: #{(node.attr 'itemwidth').chomp '%'}%;") : ''
498
- result << %(<col#{col_style_attribute}#{slash}>)
499
- result << '</colgroup>'
472
+ if dd
473
+ result << %(<p>#{dd.text}</p>) if dd.text?
474
+ result << dd.content if dd.blocks?
500
475
  end
501
- node.items.each do |terms, dd|
502
- result << '<tr>'
503
- result << %(<td class="hdlist1#{(node.option? 'strong') ? ' strong' : ''}">)
504
- terms_array = [*terms]
505
- last_term = terms_array[-1]
506
- terms_array.each do |dt|
507
- result << dt.text
508
- result << %(<br#{slash}>) if dt != last_term
509
- end
510
- result << '</td>'
511
- result << '<td class="hdlist2">'
512
- if dd
513
- result << %(<p>#{dd.text}</p>) if dd.text?
514
- result << dd.content if dd.blocks?
515
- end
516
- result << '</td>'
517
- result << '</tr>'
476
+ result << '</li>'
477
+ end
478
+ result << '</ol>'
479
+ when 'horizontal'
480
+ slash = @void_element_slash
481
+ result << '<table>'
482
+ if (node.attr? 'labelwidth') || (node.attr? 'itemwidth')
483
+ result << '<colgroup>'
484
+ col_style_attribute = (node.attr? 'labelwidth') ? %( style="width: #{(node.attr 'labelwidth').chomp '%'}%;") : ''
485
+ result << %(<col#{col_style_attribute}#{slash}>)
486
+ col_style_attribute = (node.attr? 'itemwidth') ? %( style="width: #{(node.attr 'itemwidth').chomp '%'}%;") : ''
487
+ result << %(<col#{col_style_attribute}#{slash}>)
488
+ result << '</colgroup>'
489
+ end
490
+ node.items.each do |terms, dd|
491
+ result << '<tr>'
492
+ result << %(<td class="hdlist1#{(node.option? 'strong') ? ' strong' : ''}">)
493
+ first_term = true
494
+ terms.each do |dt|
495
+ result << %(<br#{slash}>) unless first_term
496
+ result << dt.text
497
+ first_term = nil
518
498
  end
519
- result << '</table>'
520
- else
521
- result << '<dl>'
522
- dt_style_attribute = node.style ? '' : ' class="hdlist1"'
523
- node.items.each do |terms, dd|
524
- [*terms].each do |dt|
525
- result << %(<dt#{dt_style_attribute}>#{dt.text}</dt>)
526
- end
527
- if dd
528
- result << '<dd>'
529
- result << %(<p>#{dd.text}</p>) if dd.text?
530
- result << dd.content if dd.blocks?
531
- result << '</dd>'
532
- end
499
+ result << '</td>'
500
+ result << '<td class="hdlist2">'
501
+ if dd
502
+ result << %(<p>#{dd.text}</p>) if dd.text?
503
+ result << dd.content if dd.blocks?
533
504
  end
534
- result << '</dl>'
505
+ result << '</td>'
506
+ result << '</tr>'
535
507
  end
536
-
537
- result << '</div>'
538
- result.join LF
508
+ result << '</table>'
509
+ else
510
+ result << '<dl>'
511
+ dt_style_attribute = node.style ? '' : ' class="hdlist1"'
512
+ node.items.each do |terms, dd|
513
+ terms.each do |dt|
514
+ result << %(<dt#{dt_style_attribute}>#{dt.text}</dt>)
515
+ end
516
+ if dd
517
+ result << '<dd>'
518
+ result << %(<p>#{dd.text}</p>) if dd.text?
519
+ result << dd.content if dd.blocks?
520
+ result << '</dd>'
521
+ end
522
+ end
523
+ result << '</dl>'
539
524
  end
540
525
 
541
- def example node
542
- id_attribute = node.id ? %( id="#{node.id}") : ''
543
- title_element = node.title? ? %(<div class="title">#{node.captioned_title}</div>\n) : ''
526
+ result << '</div>'
527
+ result.join LF
528
+ end
529
+
530
+ def example node
531
+ id_attribute = node.id ? %( id="#{node.id}") : ''
532
+ title_element = node.title? ? %(<div class="title">#{node.captioned_title}</div>\n) : ''
544
533
 
545
- %(<div#{id_attribute} class="exampleblock#{(role = node.role) ? " #{role}" : ''}">
534
+ %(<div#{id_attribute} class="exampleblock#{(role = node.role) ? " #{role}" : ''}">
546
535
  #{title_element}<div class="content">
547
536
  #{node.content}
548
537
  </div>
549
538
  </div>)
550
- end
539
+ end
551
540
 
552
- def floating_title node
553
- tag_name = %(h#{node.level + 1})
554
- id_attribute = node.id ? %( id="#{node.id}") : ''
555
- classes = [node.style, node.role].compact
556
- %(<#{tag_name}#{id_attribute} class="#{classes.join ' '}">#{node.title}</#{tag_name}>)
557
- end
541
+ def floating_title node
542
+ tag_name = %(h#{node.level + 1})
543
+ id_attribute = node.id ? %( id="#{node.id}") : ''
544
+ classes = [node.style, node.role].compact
545
+ %(<#{tag_name}#{id_attribute} class="#{classes.join ' '}">#{node.title}</#{tag_name}>)
546
+ end
558
547
 
559
- def image node
560
- target = node.attr 'target'
561
- width_attr = (node.attr? 'width') ? %( width="#{node.attr 'width'}") : ''
562
- height_attr = (node.attr? 'height') ? %( height="#{node.attr 'height'}") : ''
563
- if ((node.attr? 'format', 'svg', false) || (target.include? '.svg')) && node.document.safe < SafeMode::SECURE &&
564
- ((svg = (node.option? 'inline')) || (obj = (node.option? 'interactive')))
565
- if svg
566
- img = (read_svg_contents node, target) || %(<span class="alt">#{node.alt}</span>)
567
- elsif obj
568
- fallback = (node.attr? 'fallback') ? %(<img src="#{node.image_uri(node.attr 'fallback')}" alt="#{encode_quotes node.alt}"#{width_attr}#{height_attr}#{@void_element_slash}>) : %(<span class="alt">#{node.alt}</span>)
569
- img = %(<object type="image/svg+xml" data="#{node.image_uri target}"#{width_attr}#{height_attr}>#{fallback}</object>)
570
- end
571
- end
572
- img ||= %(<img src="#{node.image_uri target}" alt="#{encode_quotes node.alt}"#{width_attr}#{height_attr}#{@void_element_slash}>)
573
- if node.attr? 'link', nil, false
574
- img = %(<a class="image" href="#{node.attr 'link'}"#{(append_link_constraint_attrs node).join}>#{img}</a>)
548
+ def image node
549
+ target = node.attr 'target'
550
+ width_attr = (node.attr? 'width') ? %( width="#{node.attr 'width'}") : ''
551
+ height_attr = (node.attr? 'height') ? %( height="#{node.attr 'height'}") : ''
552
+ if ((node.attr? 'format', 'svg') || (target.include? '.svg')) && node.document.safe < SafeMode::SECURE &&
553
+ ((svg = (node.option? 'inline')) || (obj = (node.option? 'interactive')))
554
+ if svg
555
+ img = (_read_svg_contents node, target) || %(<span class="alt">#{node.alt}</span>)
556
+ elsif obj
557
+ fallback = (node.attr? 'fallback') ? %(<img src="#{node.image_uri(node.attr 'fallback')}" alt="#{_encode_attribute_value node.alt}"#{width_attr}#{height_attr}#{@void_element_slash}>) : %(<span class="alt">#{node.alt}</span>)
558
+ img = %(<object type="image/svg+xml" data="#{node.image_uri target}"#{width_attr}#{height_attr}>#{fallback}</object>)
575
559
  end
576
- id_attr = node.id ? %( id="#{node.id}") : ''
577
- classes = ['imageblock']
578
- classes << (node.attr 'float') if node.attr? 'float'
579
- classes << %(text-#{node.attr 'align'}) if node.attr? 'align'
580
- classes << node.role if node.role
581
- class_attr = %( class="#{classes.join ' '}")
582
- title_el = node.title? ? %(\n<div class="title">#{node.captioned_title}</div>) : ''
583
- %(<div#{id_attr}#{class_attr}>
560
+ end
561
+ img ||= %(<img src="#{node.image_uri target}" alt="#{_encode_attribute_value node.alt}"#{width_attr}#{height_attr}#{@void_element_slash}>)
562
+ if node.attr? 'link'
563
+ img = %(<a class="image" href="#{node.attr 'link'}"#{(_append_link_constraint_attrs node).join}>#{img}</a>)
564
+ end
565
+ id_attr = node.id ? %( id="#{node.id}") : ''
566
+ classes = ['imageblock']
567
+ classes << (node.attr 'float') if node.attr? 'float'
568
+ classes << %(text-#{node.attr 'align'}) if node.attr? 'align'
569
+ classes << node.role if node.role
570
+ class_attr = %( class="#{classes.join ' '}")
571
+ title_el = node.title? ? %(\n<div class="title">#{node.captioned_title}</div>) : ''
572
+ %(<div#{id_attr}#{class_attr}>
584
573
  <div class="content">
585
574
  #{img}
586
575
  </div>#{title_el}
587
576
  </div>)
588
- end
577
+ end
589
578
 
590
- def listing node
591
- nowrap = !(node.document.attr? 'prewrap') || (node.option? 'nowrap')
592
- if node.style == 'source'
593
- if (language = node.attr 'language', nil, false)
594
- code_attrs = %( data-lang="#{language}")
595
- else
596
- code_attrs = ''
597
- end
598
- case node.document.attr 'source-highlighter'
599
- when 'coderay'
600
- pre_class = %( class="CodeRay highlight#{nowrap ? ' nowrap' : ''}")
601
- when 'pygments'
602
- if (node.document.attr? 'pygments-css', 'inline')
603
- @pygments_bg = @stylesheets.pygments_background(node.document.attr 'pygments-style') unless defined? @pygments_bg
604
- pre_class = %( class="pygments highlight#{nowrap ? ' nowrap' : ''}" style="background: #{@pygments_bg}")
605
- else
606
- pre_class = %( class="pygments highlight#{nowrap ? ' nowrap' : ''}")
607
- end
608
- when 'highlightjs', 'highlight.js'
609
- pre_class = %( class="highlightjs highlight#{nowrap ? ' nowrap' : ''}")
610
- code_attrs = %( class="language-#{language} hljs"#{code_attrs}) if language
611
- when 'prettify'
612
- pre_class = %( class="prettyprint highlight#{nowrap ? ' nowrap' : ''}#{(node.attr? 'linenums', nil, false) ? ' linenums' : ''}")
613
- code_attrs = %( class="language-#{language}"#{code_attrs}) if language
614
- when 'html-pipeline'
615
- pre_class = language ? %( lang="#{language}") : ''
616
- code_attrs = ''
617
- else
618
- pre_class = %( class="highlight#{nowrap ? ' nowrap' : ''}")
619
- code_attrs = %( class="language-#{language}"#{code_attrs}) if language
620
- end
621
- pre_start = %(<pre#{pre_class}><code#{code_attrs}>)
622
- pre_end = '</code></pre>'
579
+ def listing node
580
+ nowrap = (node.option? 'nowrap') || !(node.document.attr? 'prewrap')
581
+ if node.style == 'source'
582
+ lang = node.attr 'language'
583
+ if (syntax_hl = node.document.syntax_highlighter)
584
+ opts = syntax_hl.highlight? ? {
585
+ css_mode: ((doc_attrs = node.document.attributes)[%(#{syntax_hl.name}-css)] || :class).to_sym,
586
+ style: doc_attrs[%(#{syntax_hl.name}-style)],
587
+ } : {}
588
+ opts[:nowrap] = nowrap
623
589
  else
624
- pre_start = %(<pre#{nowrap ? ' class="nowrap"' : ''}>)
625
- pre_end = '</pre>'
590
+ pre_open = %(<pre class="highlight#{nowrap ? ' nowrap' : ''}"><code#{lang ? %[ class="language-#{lang}" data-lang="#{lang}"] : ''}>)
591
+ pre_close = '</code></pre>'
626
592
  end
627
-
628
- id_attribute = node.id ? %( id="#{node.id}") : ''
629
- title_element = node.title? ? %(<div class="title">#{node.captioned_title}</div>\n) : ''
630
- %(<div#{id_attribute} class="listingblock#{(role = node.role) ? " #{role}" : ''}">
593
+ else
594
+ pre_open = %(<pre#{nowrap ? ' class="nowrap"' : ''}>)
595
+ pre_close = '</pre>'
596
+ end
597
+ id_attribute = node.id ? %( id="#{node.id}") : ''
598
+ title_element = node.title? ? %(<div class="title">#{node.captioned_title}</div>\n) : ''
599
+ %(<div#{id_attribute} class="listingblock#{(role = node.role) ? " #{role}" : ''}">
631
600
  #{title_element}<div class="content">
632
- #{pre_start}#{node.content}#{pre_end}
601
+ #{syntax_hl ? (syntax_hl.format node, lang, opts) : pre_open + (node.content || '') + pre_close}
633
602
  </div>
634
603
  </div>)
635
- end
604
+ end
636
605
 
637
- def literal node
638
- id_attribute = node.id ? %( id="#{node.id}") : ''
639
- title_element = node.title? ? %(<div class="title">#{node.title}</div>\n) : ''
640
- nowrap = !(node.document.attr? 'prewrap') || (node.option? 'nowrap')
641
- %(<div#{id_attribute} class="literalblock#{(role = node.role) ? " #{role}" : ''}">
606
+ def literal node
607
+ id_attribute = node.id ? %( id="#{node.id}") : ''
608
+ title_element = node.title? ? %(<div class="title">#{node.title}</div>\n) : ''
609
+ nowrap = !(node.document.attr? 'prewrap') || (node.option? 'nowrap')
610
+ %(<div#{id_attribute} class="literalblock#{(role = node.role) ? " #{role}" : ''}">
642
611
  #{title_element}<div class="content">
643
612
  <pre#{nowrap ? ' class="nowrap"' : ''}>#{node.content}</pre>
644
613
  </div>
645
614
  </div>)
646
- end
615
+ end
647
616
 
648
- def stem node
649
- id_attribute = node.id ? %( id="#{node.id}") : ''
650
- title_element = node.title? ? %(<div class="title">#{node.title}</div>\n) : ''
651
- open, close = BLOCK_MATH_DELIMITERS[style = node.style.to_sym]
652
- equation = node.content
617
+ alias pass _content_only
653
618
 
619
+ def stem node
620
+ id_attribute = node.id ? %( id="#{node.id}") : ''
621
+ title_element = node.title? ? %(<div class="title">#{node.title}</div>\n) : ''
622
+ open, close = BLOCK_MATH_DELIMITERS[style = node.style.to_sym]
623
+ if (equation = node.content)
654
624
  if style == :asciimath && (equation.include? LF)
655
625
  br = %(<br#{@void_element_slash}>#{LF})
656
626
  equation = equation.gsub(StemBreakRx) { %(#{close}#{br * ($&.count LF)}#{open}) }
657
627
  end
658
-
659
628
  unless (equation.start_with? open) && (equation.end_with? close)
660
629
  equation = %(#{open}#{equation}#{close})
661
630
  end
662
-
663
- %(<div#{id_attribute} class="stemblock#{(role = node.role) ? " #{role}" : ''}">
631
+ else
632
+ equation = ''
633
+ end
634
+ %(<div#{id_attribute} class="stemblock#{(role = node.role) ? " #{role}" : ''}">
664
635
  #{title_element}<div class="content">
665
636
  #{equation}
666
637
  </div>
667
638
  </div>)
668
- end
669
-
670
- def olist node
671
- result = []
672
- id_attribute = node.id ? %( id="#{node.id}") : ''
673
- classes = ['olist', node.style, node.role].compact
674
- class_attribute = %( class="#{classes.join ' '}")
675
-
676
- result << %(<div#{id_attribute}#{class_attribute}>)
677
- result << %(<div class="title">#{node.title}</div>) if node.title?
678
-
679
- type_attribute = (keyword = node.list_marker_keyword) ? %( type="#{keyword}") : ''
680
- start_attribute = (node.attr? 'start') ? %( start="#{node.attr 'start'}") : ''
681
- reversed_attribute = (node.option? 'reversed') ? (append_boolean_attribute 'reversed', @xml_mode) : ''
682
- result << %(<ol class="#{node.style}"#{type_attribute}#{start_attribute}#{reversed_attribute}>)
639
+ end
683
640
 
684
- node.items.each do |item|
641
+ def olist node
642
+ result = []
643
+ id_attribute = node.id ? %( id="#{node.id}") : ''
644
+ classes = ['olist', node.style, node.role].compact
645
+ class_attribute = %( class="#{classes.join ' '}")
646
+
647
+ result << %(<div#{id_attribute}#{class_attribute}>)
648
+ result << %(<div class="title">#{node.title}</div>) if node.title?
649
+
650
+ type_attribute = (keyword = node.list_marker_keyword) ? %( type="#{keyword}") : ''
651
+ start_attribute = (node.attr? 'start') ? %( start="#{node.attr 'start'}") : ''
652
+ reversed_attribute = (node.option? 'reversed') ? (_append_boolean_attribute 'reversed', @xml_mode) : ''
653
+ result << %(<ol class="#{node.style}"#{type_attribute}#{start_attribute}#{reversed_attribute}>)
654
+
655
+ node.items.each do |item|
656
+ if item.id
657
+ result << %(<li id="#{item.id}"#{item.role ? %[ class="#{item.role}"] : ''}>)
658
+ elsif item.role
659
+ result << %(<li class="#{item.role}">)
660
+ else
685
661
  result << '<li>'
686
- result << %(<p>#{item.text}</p>)
687
- result << item.content if item.blocks?
688
- result << '</li>'
689
662
  end
690
-
691
- result << '</ol>'
692
- result << '</div>'
693
- result.join LF
663
+ result << %(<p>#{item.text}</p>)
664
+ result << item.content if item.blocks?
665
+ result << '</li>'
694
666
  end
695
667
 
696
- def open node
697
- if (style = node.style) == 'abstract'
698
- if node.parent == node.document && node.document.doctype == 'book'
699
- logger.warn 'abstract block cannot be used in a document without a title when doctype is book. Excluding block content.'
700
- ''
701
- else
702
- id_attr = node.id ? %( id="#{node.id}") : ''
703
- title_el = node.title? ? %(<div class="title">#{node.title}</div>\n) : ''
704
- %(<div#{id_attr} class="quoteblock abstract#{(role = node.role) ? " #{role}" : ''}">
668
+ result << '</ol>'
669
+ result << '</div>'
670
+ result.join LF
671
+ end
672
+
673
+ def open node
674
+ if (style = node.style) == 'abstract'
675
+ if node.parent == node.document && node.document.doctype == 'book'
676
+ logger.warn 'abstract block cannot be used in a document without a title when doctype is book. Excluding block content.'
677
+ ''
678
+ else
679
+ id_attr = node.id ? %( id="#{node.id}") : ''
680
+ title_el = node.title? ? %(<div class="title">#{node.title}</div>\n) : ''
681
+ %(<div#{id_attr} class="quoteblock abstract#{(role = node.role) ? " #{role}" : ''}">
705
682
  #{title_el}<blockquote>
706
683
  #{node.content}
707
684
  </blockquote>
708
685
  </div>)
709
- end
710
- elsif style == 'partintro' && (node.level > 0 || node.parent.context != :section || node.document.doctype != 'book')
711
- logger.error 'partintro block can only be used when doctype is book and must be a child of a book part. Excluding block content.'
712
- ''
713
- else
714
- id_attr = node.id ? %( id="#{node.id}") : ''
715
- title_el = node.title? ? %(<div class="title">#{node.title}</div>\n) : ''
716
- %(<div#{id_attr} class="openblock#{style && style != 'open' ? " #{style}" : ''}#{(role = node.role) ? " #{role}" : ''}">
686
+ end
687
+ elsif style == 'partintro' && (node.level > 0 || node.parent.context != :section || node.document.doctype != 'book')
688
+ logger.error 'partintro block can only be used when doctype is book and must be a child of a book part. Excluding block content.'
689
+ ''
690
+ else
691
+ id_attr = node.id ? %( id="#{node.id}") : ''
692
+ title_el = node.title? ? %(<div class="title">#{node.title}</div>\n) : ''
693
+ %(<div#{id_attr} class="openblock#{style && style != 'open' ? " #{style}" : ''}#{(role = node.role) ? " #{role}" : ''}">
717
694
  #{title_el}<div class="content">
718
695
  #{node.content}
719
696
  </div>
720
697
  </div>)
721
- end
722
- end
723
-
724
- def page_break node
725
- '<div style="page-break-after: always;"></div>'
726
698
  end
699
+ end
727
700
 
728
- def paragraph node
729
- class_attribute = node.role ? %(class="paragraph #{node.role}") : 'class="paragraph"'
730
- attributes = node.id ? %(id="#{node.id}" #{class_attribute}) : class_attribute
701
+ def page_break node
702
+ '<div style="page-break-after: always;"></div>'
703
+ end
731
704
 
732
- if node.title?
733
- %(<div #{attributes}>
705
+ def paragraph node
706
+ if node.role
707
+ attributes = %(#{node.id ? %[ id="#{node.id}"] : ''} class="paragraph #{node.role}")
708
+ elsif node.id
709
+ attributes = %( id="#{node.id}" class="paragraph")
710
+ else
711
+ attributes = ' class="paragraph"'
712
+ end
713
+ if node.title?
714
+ %(<div#{attributes}>
734
715
  <div class="title">#{node.title}</div>
735
716
  <p>#{node.content}</p>
736
717
  </div>)
737
- else
738
- %(<div #{attributes}>
718
+ else
719
+ %(<div#{attributes}>
739
720
  <p>#{node.content}</p>
740
721
  </div>)
741
- end
742
722
  end
723
+ end
743
724
 
744
- def preamble node
745
- if (doc = node.document).attr?('toc-placement', 'preamble') && doc.sections? && (doc.attr? 'toc')
746
- toc = %(
725
+ def preamble node
726
+ if (doc = node.document).attr?('toc-placement', 'preamble') && doc.sections? && (doc.attr? 'toc')
727
+ toc = %(
747
728
  <div id="toc" class="#{doc.attr 'toc-class', 'toc'}">
748
729
  <div id="toctitle">#{doc.attr 'toc-title'}</div>
749
730
  #{outline doc}
750
731
  </div>)
751
- else
752
- toc = ''
753
- end
732
+ else
733
+ toc = ''
734
+ end
754
735
 
755
- %(<div id="preamble">
736
+ %(<div id="preamble">
756
737
  <div class="sectionbody">
757
738
  #{node.content}
758
739
  </div>#{toc}
759
740
  </div>)
760
- end
741
+ end
761
742
 
762
- def quote node
763
- id_attribute = node.id ? %( id="#{node.id}") : ''
764
- classes = ['quoteblock', node.role].compact
765
- class_attribute = %( class="#{classes.join ' '}")
766
- title_element = node.title? ? %(\n<div class="title">#{node.title}</div>) : ''
767
- attribution = (node.attr? 'attribution') ? (node.attr 'attribution') : nil
768
- citetitle = (node.attr? 'citetitle') ? (node.attr 'citetitle') : nil
769
- if attribution || citetitle
770
- cite_element = citetitle ? %(<cite>#{citetitle}</cite>) : ''
771
- attribution_text = attribution ? %(&#8212; #{attribution}#{citetitle ? "<br#{@void_element_slash}>\n" : ''}) : ''
772
- attribution_element = %(\n<div class="attribution">\n#{attribution_text}#{cite_element}\n</div>)
773
- else
774
- attribution_element = ''
775
- end
743
+ def quote node
744
+ id_attribute = node.id ? %( id="#{node.id}") : ''
745
+ classes = ['quoteblock', node.role].compact
746
+ class_attribute = %( class="#{classes.join ' '}")
747
+ title_element = node.title? ? %(\n<div class="title">#{node.title}</div>) : ''
748
+ attribution = (node.attr? 'attribution') ? (node.attr 'attribution') : nil
749
+ citetitle = (node.attr? 'citetitle') ? (node.attr 'citetitle') : nil
750
+ if attribution || citetitle
751
+ cite_element = citetitle ? %(<cite>#{citetitle}</cite>) : ''
752
+ attribution_text = attribution ? %(&#8212; #{attribution}#{citetitle ? "<br#{@void_element_slash}>\n" : ''}) : ''
753
+ attribution_element = %(\n<div class="attribution">\n#{attribution_text}#{cite_element}\n</div>)
754
+ else
755
+ attribution_element = ''
756
+ end
776
757
 
777
- %(<div#{id_attribute}#{class_attribute}>#{title_element}
758
+ %(<div#{id_attribute}#{class_attribute}>#{title_element}
778
759
  <blockquote>
779
760
  #{node.content}
780
761
  </blockquote>#{attribution_element}
781
762
  </div>)
782
- end
763
+ end
783
764
 
784
- def thematic_break node
785
- %(<hr#{@void_element_slash}>)
786
- end
765
+ def thematic_break node
766
+ %(<hr#{@void_element_slash}>)
767
+ end
787
768
 
788
- def sidebar node
789
- id_attribute = node.id ? %( id="#{node.id}") : ''
790
- title_element = node.title? ? %(<div class="title">#{node.title}</div>\n) : ''
791
- %(<div#{id_attribute} class="sidebarblock#{(role = node.role) ? " #{role}" : ''}">
769
+ def sidebar node
770
+ id_attribute = node.id ? %( id="#{node.id}") : ''
771
+ title_element = node.title? ? %(<div class="title">#{node.title}</div>\n) : ''
772
+ %(<div#{id_attribute} class="sidebarblock#{(role = node.role) ? " #{role}" : ''}">
792
773
  <div class="content">
793
774
  #{title_element}#{node.content}
794
775
  </div>
795
776
  </div>)
777
+ end
778
+
779
+ def table node
780
+ result = []
781
+ id_attribute = node.id ? %( id="#{node.id}") : ''
782
+ classes = ['tableblock', %(frame-#{node.attr 'frame', 'all', 'table-frame'}), %(grid-#{node.attr 'grid', 'all', 'table-grid'})]
783
+ if (stripes = node.attr 'stripes', nil, 'table-stripes')
784
+ classes << %(stripes-#{stripes})
796
785
  end
786
+ styles = []
787
+ if (autowidth = node.option? 'autowidth') && !(node.attr? 'width')
788
+ classes << 'fit-content'
789
+ elsif (tablewidth = node.attr 'tablepcwidth') == 100
790
+ classes << 'stretch'
791
+ else
792
+ styles << %(width: #{tablewidth}%;)
793
+ end
794
+ classes << (node.attr 'float') if node.attr? 'float'
795
+ if (role = node.role)
796
+ classes << role
797
+ end
798
+ class_attribute = %( class="#{classes.join ' '}")
799
+ style_attribute = styles.empty? ? '' : %( style="#{styles.join ' '}")
797
800
 
798
- def table node
799
- result = []
800
- id_attribute = node.id ? %( id="#{node.id}") : ''
801
- classes = ['tableblock', %(frame-#{node.attr 'frame', 'all'}), %(grid-#{node.attr 'grid', 'all'})]
802
- if (stripes = node.attr 'stripes')
803
- classes << %(stripes-#{stripes})
804
- end
805
- styles = []
806
- if (autowidth = node.attributes['autowidth-option']) && !(node.attr? 'width', nil, false)
807
- classes << 'fit-content'
808
- elsif (tablewidth = node.attr 'tablepcwidth') == 100
809
- classes << 'stretch'
801
+ result << %(<table#{id_attribute}#{class_attribute}#{style_attribute}>)
802
+ result << %(<caption class="title">#{node.captioned_title}</caption>) if node.title?
803
+ if (node.attr 'rowcount') > 0
804
+ slash = @void_element_slash
805
+ result << '<colgroup>'
806
+ if autowidth
807
+ result += (Array.new node.columns.size, %(<col#{slash}>))
810
808
  else
811
- styles << %(width: #{tablewidth}%;)
812
- end
813
- classes << (node.attr 'float') if node.attr? 'float'
814
- if (role = node.role)
815
- classes << role
816
- end
817
- class_attribute = %( class="#{classes.join ' '}")
818
- style_attribute = styles.empty? ? '' : %( style="#{styles.join ' '}")
819
-
820
- result << %(<table#{id_attribute}#{class_attribute}#{style_attribute}>)
821
- result << %(<caption class="title">#{node.captioned_title}</caption>) if node.title?
822
- if (node.attr 'rowcount') > 0
823
- slash = @void_element_slash
824
- result << '<colgroup>'
825
- if autowidth
826
- result += (Array.new node.columns.size, %(<col#{slash}>))
827
- else
828
- node.columns.each do |col|
829
- result << (col.attributes['autowidth-option'] ? %(<col#{slash}>) : %(<col style="width: #{col.attr 'colpcwidth'}%;"#{slash}>))
830
- end
809
+ node.columns.each do |col|
810
+ result << ((col.option? 'autowidth') ? %(<col#{slash}>) : %(<col style="width: #{col.attr 'colpcwidth'}%;"#{slash}>))
831
811
  end
832
- result << '</colgroup>'
833
- node.rows.by_section.each do |tsec, rows|
834
- next if rows.empty?
835
- result << %(<t#{tsec}>)
836
- rows.each do |row|
837
- result << '<tr>'
838
- row.each do |cell|
839
- if tsec == :head
840
- cell_content = cell.text
812
+ end
813
+ result << '</colgroup>'
814
+ node.rows.to_h.each do |tsec, rows|
815
+ next if rows.empty?
816
+ result << %(<t#{tsec}>)
817
+ rows.each do |row|
818
+ result << '<tr>'
819
+ row.each do |cell|
820
+ if tsec == :head
821
+ cell_content = cell.text
822
+ else
823
+ case cell.style
824
+ when :asciidoc
825
+ cell_content = %(<div class="content">#{cell.content}</div>)
826
+ when :literal
827
+ cell_content = %(<div class="literal"><pre>#{cell.text}</pre></div>)
841
828
  else
842
- case cell.style
843
- when :asciidoc
844
- cell_content = %(<div class="content">#{cell.content}</div>)
845
- when :verse
846
- cell_content = %(<div class="verse">#{cell.text}</div>)
847
- when :literal
848
- cell_content = %(<div class="literal"><pre>#{cell.text}</pre></div>)
849
- else
850
- cell_content = (cell_content = cell.content).empty? ? '' : %(<p class="tableblock">#{cell_content.join '</p>
829
+ cell_content = (cell_content = cell.content).empty? ? '' : %(<p class="tableblock">#{cell_content.join '</p>
851
830
  <p class="tableblock">'}</p>)
852
- end
853
831
  end
854
-
855
- cell_tag_name = (tsec == :head || cell.style == :header ? 'th' : 'td')
856
- cell_class_attribute = %( class="tableblock halign-#{cell.attr 'halign'} valign-#{cell.attr 'valign'}")
857
- cell_colspan_attribute = cell.colspan ? %( colspan="#{cell.colspan}") : ''
858
- cell_rowspan_attribute = cell.rowspan ? %( rowspan="#{cell.rowspan}") : ''
859
- cell_style_attribute = (node.document.attr? 'cellbgcolor') ? %( style="background-color: #{node.document.attr 'cellbgcolor'};") : ''
860
- result << %(<#{cell_tag_name}#{cell_class_attribute}#{cell_colspan_attribute}#{cell_rowspan_attribute}#{cell_style_attribute}>#{cell_content}</#{cell_tag_name}>)
861
832
  end
862
- result << '</tr>'
833
+
834
+ cell_tag_name = (tsec == :head || cell.style == :header ? 'th' : 'td')
835
+ cell_class_attribute = %( class="tableblock halign-#{cell.attr 'halign'} valign-#{cell.attr 'valign'}")
836
+ cell_colspan_attribute = cell.colspan ? %( colspan="#{cell.colspan}") : ''
837
+ cell_rowspan_attribute = cell.rowspan ? %( rowspan="#{cell.rowspan}") : ''
838
+ cell_style_attribute = (node.document.attr? 'cellbgcolor') ? %( style="background-color: #{node.document.attr 'cellbgcolor'};") : ''
839
+ result << %(<#{cell_tag_name}#{cell_class_attribute}#{cell_colspan_attribute}#{cell_rowspan_attribute}#{cell_style_attribute}>#{cell_content}</#{cell_tag_name}>)
863
840
  end
864
- result << %(</t#{tsec}>)
841
+ result << '</tr>'
865
842
  end
843
+ result << %(</t#{tsec}>)
866
844
  end
867
- result << '</table>'
868
- result.join LF
869
845
  end
846
+ result << '</table>'
847
+ result.join LF
848
+ end
870
849
 
871
- def toc node
872
- unless (doc = node.document).attr?('toc-placement', 'macro') && doc.sections? && (doc.attr? 'toc')
873
- return '<!-- toc disabled -->'
874
- end
850
+ def toc node
851
+ unless (doc = node.document).attr?('toc-placement', 'macro') && doc.sections? && (doc.attr? 'toc')
852
+ return '<!-- toc disabled -->'
853
+ end
875
854
 
876
- if node.id
877
- id_attr = %( id="#{node.id}")
878
- title_id_attr = %( id="#{node.id}title")
879
- else
880
- id_attr = ' id="toc"'
881
- title_id_attr = ' id="toctitle"'
882
- end
883
- title = node.title? ? node.title : (doc.attr 'toc-title')
884
- levels = (node.attr? 'levels') ? (node.attr 'levels').to_i : nil
885
- role = node.role? ? node.role : (doc.attr 'toc-class', 'toc')
855
+ if node.id
856
+ id_attr = %( id="#{node.id}")
857
+ title_id_attr = %( id="#{node.id}title")
858
+ else
859
+ id_attr = ' id="toc"'
860
+ title_id_attr = ' id="toctitle"'
861
+ end
862
+ title = node.title? ? node.title : (doc.attr 'toc-title')
863
+ levels = (node.attr? 'levels') ? (node.attr 'levels').to_i : nil
864
+ role = node.role? ? node.role : (doc.attr 'toc-class', 'toc')
886
865
 
887
- %(<div#{id_attr} class="#{role}">
866
+ %(<div#{id_attr} class="#{role}">
888
867
  <div#{title_id_attr} class="title">#{title}</div>
889
- #{outline doc, :toclevels => levels}
868
+ #{outline doc, toclevels: levels}
890
869
  </div>)
891
- end
870
+ end
892
871
 
893
- def ulist node
894
- result = []
895
- id_attribute = node.id ? %( id="#{node.id}") : ''
896
- div_classes = ['ulist', node.style, node.role].compact
897
- marker_checked = marker_unchecked = ''
898
- if (checklist = node.option? 'checklist')
899
- div_classes.unshift div_classes.shift, 'checklist'
900
- ul_class_attribute = ' class="checklist"'
901
- if node.option? 'interactive'
902
- if @xml_mode
903
- marker_checked = '<input type="checkbox" data-item-complete="1" checked="checked"/> '
904
- marker_unchecked = '<input type="checkbox" data-item-complete="0"/> '
905
- else
906
- marker_checked = '<input type="checkbox" data-item-complete="1" checked> '
907
- marker_unchecked = '<input type="checkbox" data-item-complete="0"> '
908
- end
872
+ def ulist node
873
+ result = []
874
+ id_attribute = node.id ? %( id="#{node.id}") : ''
875
+ div_classes = ['ulist', node.style, node.role].compact
876
+ marker_checked = marker_unchecked = ''
877
+ if (checklist = node.option? 'checklist')
878
+ div_classes.unshift div_classes.shift, 'checklist'
879
+ ul_class_attribute = ' class="checklist"'
880
+ if node.option? 'interactive'
881
+ if @xml_mode
882
+ marker_checked = '<input type="checkbox" data-item-complete="1" checked="checked"/> '
883
+ marker_unchecked = '<input type="checkbox" data-item-complete="0"/> '
909
884
  else
910
- if node.document.attr? 'icons', 'font'
911
- marker_checked = '<i class="fa fa-check-square-o"></i> '
912
- marker_unchecked = '<i class="fa fa-square-o"></i> '
913
- else
914
- marker_checked = '&#10003; '
915
- marker_unchecked = '&#10063; '
916
- end
885
+ marker_checked = '<input type="checkbox" data-item-complete="1" checked> '
886
+ marker_unchecked = '<input type="checkbox" data-item-complete="0"> '
917
887
  end
888
+ elsif node.document.attr? 'icons', 'font'
889
+ marker_checked = '<i class="fa fa-check-square-o"></i> '
890
+ marker_unchecked = '<i class="fa fa-square-o"></i> '
918
891
  else
919
- ul_class_attribute = node.style ? %( class="#{node.style}") : ''
892
+ marker_checked = '&#10003; '
893
+ marker_unchecked = '&#10063; '
920
894
  end
921
- result << %(<div#{id_attribute} class="#{div_classes.join ' '}">)
922
- result << %(<div class="title">#{node.title}</div>) if node.title?
923
- result << %(<ul#{ul_class_attribute}>)
924
-
925
- node.items.each do |item|
895
+ else
896
+ ul_class_attribute = node.style ? %( class="#{node.style}") : ''
897
+ end
898
+ result << %(<div#{id_attribute} class="#{div_classes.join ' '}">)
899
+ result << %(<div class="title">#{node.title}</div>) if node.title?
900
+ result << %(<ul#{ul_class_attribute}>)
901
+
902
+ node.items.each do |item|
903
+ if item.id
904
+ result << %(<li id="#{item.id}"#{item.role ? %[ class="#{item.role}"] : ''}>)
905
+ elsif item.role
906
+ result << %(<li class="#{item.role}">)
907
+ else
926
908
  result << '<li>'
927
- if checklist && (item.attr? 'checkbox')
928
- result << %(<p>#{(item.attr? 'checked') ? marker_checked : marker_unchecked}#{item.text}</p>)
929
- else
930
- result << %(<p>#{item.text}</p>)
931
- end
932
- result << item.content if item.blocks?
933
- result << '</li>'
934
909
  end
935
-
936
- result << '</ul>'
937
- result << '</div>'
938
- result.join LF
939
- end
940
-
941
- def verse node
942
- id_attribute = node.id ? %( id="#{node.id}") : ''
943
- classes = ['verseblock', node.role].compact
944
- class_attribute = %( class="#{classes.join ' '}")
945
- title_element = node.title? ? %(\n<div class="title">#{node.title}</div>) : ''
946
- attribution = (node.attr? 'attribution') ? (node.attr 'attribution') : nil
947
- citetitle = (node.attr? 'citetitle') ? (node.attr 'citetitle') : nil
948
- if attribution || citetitle
949
- cite_element = citetitle ? %(<cite>#{citetitle}</cite>) : ''
950
- attribution_text = attribution ? %(&#8212; #{attribution}#{citetitle ? "<br#{@void_element_slash}>\n" : ''}) : ''
951
- attribution_element = %(\n<div class="attribution">\n#{attribution_text}#{cite_element}\n</div>)
910
+ if checklist && (item.attr? 'checkbox')
911
+ result << %(<p>#{(item.attr? 'checked') ? marker_checked : marker_unchecked}#{item.text}</p>)
952
912
  else
953
- attribution_element = ''
913
+ result << %(<p>#{item.text}</p>)
954
914
  end
915
+ result << item.content if item.blocks?
916
+ result << '</li>'
917
+ end
955
918
 
956
- %(<div#{id_attribute}#{class_attribute}>#{title_element}
919
+ result << '</ul>'
920
+ result << '</div>'
921
+ result.join LF
922
+ end
923
+
924
+ def verse node
925
+ id_attribute = node.id ? %( id="#{node.id}") : ''
926
+ classes = ['verseblock', node.role].compact
927
+ class_attribute = %( class="#{classes.join ' '}")
928
+ title_element = node.title? ? %(\n<div class="title">#{node.title}</div>) : ''
929
+ attribution = (node.attr? 'attribution') ? (node.attr 'attribution') : nil
930
+ citetitle = (node.attr? 'citetitle') ? (node.attr 'citetitle') : nil
931
+ if attribution || citetitle
932
+ cite_element = citetitle ? %(<cite>#{citetitle}</cite>) : ''
933
+ attribution_text = attribution ? %(&#8212; #{attribution}#{citetitle ? "<br#{@void_element_slash}>\n" : ''}) : ''
934
+ attribution_element = %(\n<div class="attribution">\n#{attribution_text}#{cite_element}\n</div>)
935
+ else
936
+ attribution_element = ''
937
+ end
938
+
939
+ %(<div#{id_attribute}#{class_attribute}>#{title_element}
957
940
  <pre class="content">#{node.content}</pre>#{attribution_element}
958
941
  </div>)
959
- end
942
+ end
960
943
 
961
- def video node
962
- xml = @xml_mode
963
- id_attribute = node.id ? %( id="#{node.id}") : ''
964
- classes = ['videoblock']
965
- classes << (node.attr 'float') if node.attr? 'float'
966
- classes << %(text-#{node.attr 'align'}) if node.attr? 'align'
967
- classes << node.role if node.role
968
- class_attribute = %( class="#{classes.join ' '}")
969
- title_element = node.title? ? %(\n<div class="title">#{node.title}</div>) : ''
970
- width_attribute = (node.attr? 'width') ? %( width="#{node.attr 'width'}") : ''
971
- height_attribute = (node.attr? 'height') ? %( height="#{node.attr 'height'}") : ''
972
- case node.attr 'poster'
973
- when 'vimeo'
974
- unless (asset_uri_scheme = (node.document.attr 'asset-uri-scheme', 'https')).empty?
975
- asset_uri_scheme = %(#{asset_uri_scheme}:)
976
- end
977
- start_anchor = (node.attr? 'start', nil, false) ? %(#at=#{node.attr 'start'}) : ''
978
- delimiter = '?'
979
- if node.option? 'autoplay'
980
- autoplay_param = %(#{delimiter}autoplay=1)
981
- delimiter = '&amp;'
982
- else
983
- autoplay_param = ''
984
- end
985
- loop_param = (node.option? 'loop') ? %(#{delimiter}loop=1) : ''
986
- %(<div#{id_attribute}#{class_attribute}>#{title_element}
944
+ def video node
945
+ xml = @xml_mode
946
+ id_attribute = node.id ? %( id="#{node.id}") : ''
947
+ classes = ['videoblock']
948
+ classes << (node.attr 'float') if node.attr? 'float'
949
+ classes << %(text-#{node.attr 'align'}) if node.attr? 'align'
950
+ classes << node.role if node.role
951
+ class_attribute = %( class="#{classes.join ' '}")
952
+ title_element = node.title? ? %(\n<div class="title">#{node.title}</div>) : ''
953
+ width_attribute = (node.attr? 'width') ? %( width="#{node.attr 'width'}") : ''
954
+ height_attribute = (node.attr? 'height') ? %( height="#{node.attr 'height'}") : ''
955
+ case node.attr 'poster'
956
+ when 'vimeo'
957
+ unless (asset_uri_scheme = (node.document.attr 'asset-uri-scheme', 'https')).empty?
958
+ asset_uri_scheme = %(#{asset_uri_scheme}:)
959
+ end
960
+ start_anchor = (node.attr? 'start') ? %(#at=#{node.attr 'start'}) : ''
961
+ delimiter = ['?']
962
+ autoplay_param = (node.option? 'autoplay') ? %(#{delimiter.pop || '&amp;'}autoplay=1) : ''
963
+ loop_param = (node.option? 'loop') ? %(#{delimiter.pop || '&amp;'}loop=1) : ''
964
+ muted_param = (node.option? 'muted') ? %(#{delimiter.pop || '&amp;'}muted=1) : ''
965
+ %(<div#{id_attribute}#{class_attribute}>#{title_element}
987
966
  <div class="content">
988
- <iframe#{width_attribute}#{height_attribute} src="#{asset_uri_scheme}//player.vimeo.com/video/#{node.attr 'target'}#{start_anchor}#{autoplay_param}#{loop_param}" frameborder="0"#{(node.option? 'nofullscreen') ? '' : (append_boolean_attribute 'allowfullscreen', xml)}></iframe>
967
+ <iframe#{width_attribute}#{height_attribute} src="#{asset_uri_scheme}//player.vimeo.com/video/#{node.attr 'target'}#{autoplay_param}#{loop_param}#{muted_param}#{start_anchor}" frameborder="0"#{(node.option? 'nofullscreen') ? '' : (_append_boolean_attribute 'allowfullscreen', xml)}></iframe>
989
968
  </div>
990
969
  </div>)
991
- when 'youtube'
992
- unless (asset_uri_scheme = (node.document.attr 'asset-uri-scheme', 'https')).empty?
993
- asset_uri_scheme = %(#{asset_uri_scheme}:)
994
- end
995
- rel_param_val = (node.option? 'related') ? 1 : 0
996
- # NOTE start and end must be seconds (t parameter allows XmYs where X is minutes and Y is seconds)
997
- start_param = (node.attr? 'start', nil, false) ? %(&amp;start=#{node.attr 'start'}) : ''
998
- end_param = (node.attr? 'end', nil, false) ? %(&amp;end=#{node.attr 'end'}) : ''
999
- autoplay_param = (node.option? 'autoplay') ? '&amp;autoplay=1' : ''
1000
- loop_param = (has_loop_param = node.option? 'loop') ? '&amp;loop=1' : ''
1001
- controls_param = (node.option? 'nocontrols') ? '&amp;controls=0' : ''
1002
- # cover both ways of controlling fullscreen option
1003
- if node.option? 'nofullscreen'
1004
- fs_param = '&amp;fs=0'
1005
- fs_attribute = ''
1006
- else
1007
- fs_param = ''
1008
- fs_attribute = append_boolean_attribute 'allowfullscreen', xml
1009
- end
1010
- modest_param = (node.option? 'modest') ? '&amp;modestbranding=1' : ''
1011
- theme_param = (node.attr? 'theme', nil, false) ? %(&amp;theme=#{node.attr 'theme'}) : ''
1012
- hl_param = (node.attr? 'lang') ? %(&amp;hl=#{node.attr 'lang'}) : ''
1013
-
1014
- # parse video_id/list_id syntax where list_id (i.e., playlist) is optional
1015
- target, list = (node.attr 'target').split '/', 2
1016
- if (list ||= (node.attr 'list', nil, false))
1017
- list_param = %(&amp;list=#{list})
970
+ when 'youtube'
971
+ unless (asset_uri_scheme = (node.document.attr 'asset-uri-scheme', 'https')).empty?
972
+ asset_uri_scheme = %(#{asset_uri_scheme}:)
973
+ end
974
+ rel_param_val = (node.option? 'related') ? 1 : 0
975
+ # NOTE start and end must be seconds (t parameter allows XmYs where X is minutes and Y is seconds)
976
+ start_param = (node.attr? 'start') ? %(&amp;start=#{node.attr 'start'}) : ''
977
+ end_param = (node.attr? 'end') ? %(&amp;end=#{node.attr 'end'}) : ''
978
+ autoplay_param = (node.option? 'autoplay') ? '&amp;autoplay=1' : ''
979
+ loop_param = (has_loop_param = node.option? 'loop') ? '&amp;loop=1' : ''
980
+ mute_param = (node.option? 'muted') ? '&amp;mute=1' : ''
981
+ controls_param = (node.option? 'nocontrols') ? '&amp;controls=0' : ''
982
+ # cover both ways of controlling fullscreen option
983
+ if node.option? 'nofullscreen'
984
+ fs_param = '&amp;fs=0'
985
+ fs_attribute = ''
986
+ else
987
+ fs_param = ''
988
+ fs_attribute = _append_boolean_attribute 'allowfullscreen', xml
989
+ end
990
+ modest_param = (node.option? 'modest') ? '&amp;modestbranding=1' : ''
991
+ theme_param = (node.attr? 'theme') ? %(&amp;theme=#{node.attr 'theme'}) : ''
992
+ hl_param = (node.attr? 'lang') ? %(&amp;hl=#{node.attr 'lang'}) : ''
993
+
994
+ # parse video_id/list_id syntax where list_id (i.e., playlist) is optional
995
+ target, list = (node.attr 'target').split '/', 2
996
+ if (list ||= (node.attr 'list'))
997
+ list_param = %(&amp;list=#{list})
998
+ else
999
+ # parse dynamic playlist syntax: video_id1,video_id2,...
1000
+ target, playlist = target.split ',', 2
1001
+ if (playlist ||= (node.attr 'playlist'))
1002
+ # INFO playlist bar doesn't appear in Firefox unless showinfo=1 and modestbranding=1
1003
+ list_param = %(&amp;playlist=#{playlist})
1018
1004
  else
1019
- # parse dynamic playlist syntax: video_id1,video_id2,...
1020
- target, playlist = target.split ',', 2
1021
- if (playlist ||= (node.attr 'playlist', nil, false))
1022
- # INFO playlist bar doesn't appear in Firefox unless showinfo=1 and modestbranding=1
1023
- list_param = %(&amp;playlist=#{playlist})
1024
- else
1025
- # NOTE for loop to work, playlist must be specified; use VIDEO_ID if there's no explicit playlist
1026
- list_param = has_loop_param ? %(&amp;playlist=#{target}) : ''
1027
- end
1005
+ # NOTE for loop to work, playlist must be specified; use VIDEO_ID if there's no explicit playlist
1006
+ list_param = has_loop_param ? %(&amp;playlist=#{target}) : ''
1028
1007
  end
1008
+ end
1029
1009
 
1030
- %(<div#{id_attribute}#{class_attribute}>#{title_element}
1010
+ %(<div#{id_attribute}#{class_attribute}>#{title_element}
1031
1011
  <div class="content">
1032
- <iframe#{width_attribute}#{height_attribute} src="#{asset_uri_scheme}//www.youtube.com/embed/#{target}?rel=#{rel_param_val}#{start_param}#{end_param}#{autoplay_param}#{loop_param}#{controls_param}#{list_param}#{fs_param}#{modest_param}#{theme_param}#{hl_param}" frameborder="0"#{fs_attribute}></iframe>
1012
+ <iframe#{width_attribute}#{height_attribute} src="#{asset_uri_scheme}//www.youtube.com/embed/#{target}?rel=#{rel_param_val}#{start_param}#{end_param}#{autoplay_param}#{loop_param}#{mute_param}#{controls_param}#{list_param}#{fs_param}#{modest_param}#{theme_param}#{hl_param}" frameborder="0"#{fs_attribute}></iframe>
1033
1013
  </div>
1034
1014
  </div>)
1035
- else
1036
- poster_attribute = (val = node.attr 'poster', nil, false).nil_or_empty? ? '' : %( poster="#{node.media_uri val}")
1037
- preload_attribute = (val = node.attr 'preload', nil, false).nil_or_empty? ? '' : %( preload="#{val}")
1038
- start_t = node.attr 'start', nil, false
1039
- end_t = node.attr 'end', nil, false
1040
- time_anchor = (start_t || end_t) ? %(#t=#{start_t || ''}#{end_t ? ",#{end_t}" : ''}) : ''
1041
- %(<div#{id_attribute}#{class_attribute}>#{title_element}
1015
+ else
1016
+ poster_attribute = (val = node.attr 'poster').nil_or_empty? ? '' : %( poster="#{node.media_uri val}")
1017
+ preload_attribute = (val = node.attr 'preload').nil_or_empty? ? '' : %( preload="#{val}")
1018
+ start_t = node.attr 'start'
1019
+ end_t = node.attr 'end'
1020
+ time_anchor = (start_t || end_t) ? %(#t=#{start_t || ''}#{end_t ? ",#{end_t}" : ''}) : ''
1021
+ %(<div#{id_attribute}#{class_attribute}>#{title_element}
1042
1022
  <div class="content">
1043
- <video src="#{node.media_uri(node.attr 'target')}#{time_anchor}"#{width_attribute}#{height_attribute}#{poster_attribute}#{(node.option? 'autoplay') ? (append_boolean_attribute 'autoplay', xml) : ''}#{(node.option? 'nocontrols') ? '' : (append_boolean_attribute 'controls', xml)}#{(node.option? 'loop') ? (append_boolean_attribute 'loop', xml) : ''}#{preload_attribute}>
1023
+ <video src="#{node.media_uri(node.attr 'target')}#{time_anchor}"#{width_attribute}#{height_attribute}#{poster_attribute}#{(node.option? 'autoplay') ? (_append_boolean_attribute 'autoplay', xml) : ''}#{(node.option? 'nocontrols') ? '' : (_append_boolean_attribute 'controls', xml)}#{(node.option? 'loop') ? (_append_boolean_attribute 'loop', xml) : ''}#{preload_attribute}>
1044
1024
  Your browser does not support the video tag.
1045
1025
  </video>
1046
1026
  </div>
1047
1027
  </div>)
1048
- end
1049
1028
  end
1029
+ end
1050
1030
 
1051
- def inline_anchor node
1052
- case node.type
1053
- when :xref
1054
- if (path = node.attributes['path'])
1055
- attrs = (append_link_constraint_attrs node, node.role ? [%( class="#{node.role}")] : []).join
1056
- text = node.text || path
1057
- else
1058
- attrs = node.role ? %( class="#{node.role}") : ''
1059
- unless (text = node.text)
1060
- refid = node.attributes['refid']
1061
- if AbstractNode === (ref = (@refs ||= node.document.catalog[:refs])[refid])
1062
- text = (ref.xreftext node.attr('xrefstyle')) || %([#{refid}])
1063
- else
1064
- text = %([#{refid}])
1065
- end
1031
+ def inline_anchor node
1032
+ case node.type
1033
+ when :xref
1034
+ if (path = node.attributes['path'])
1035
+ attrs = (_append_link_constraint_attrs node, node.role ? [%( class="#{node.role}")] : []).join
1036
+ text = node.text || path
1037
+ else
1038
+ attrs = node.role ? %( class="#{node.role}") : ''
1039
+ unless (text = node.text)
1040
+ refid = node.attributes['refid']
1041
+ if AbstractNode === (ref = (@refs ||= node.document.catalog[:refs])[refid])
1042
+ text = (ref.xreftext node.attr('xrefstyle', nil, true)) || %([#{refid}])
1043
+ else
1044
+ text = %([#{refid}])
1066
1045
  end
1067
1046
  end
1068
- %(<a href="#{node.target}"#{attrs}>#{text}</a>)
1069
- when :ref
1070
- %(<a id="#{node.id}"></a>)
1071
- when :link
1072
- attrs = node.id ? [%( id="#{node.id}")] : []
1073
- attrs << %( class="#{node.role}") if node.role
1074
- attrs << %( title="#{node.attr 'title'}") if node.attr? 'title', nil, false
1075
- %(<a href="#{node.target}"#{(append_link_constraint_attrs node, attrs).join}>#{node.text}</a>)
1076
- when :bibref
1077
- # NOTE technically node.text should be node.reftext, but subs have already been applied to text
1078
- %(<a id="#{node.id}"></a>#{node.text})
1079
- else
1080
- logger.warn %(unknown anchor type: #{node.type.inspect})
1081
- nil
1082
1047
  end
1048
+ %(<a href="#{node.target}"#{attrs}>#{text}</a>)
1049
+ when :ref
1050
+ %(<a id="#{node.id}"></a>)
1051
+ when :link
1052
+ attrs = node.id ? [%( id="#{node.id}")] : []
1053
+ attrs << %( class="#{node.role}") if node.role
1054
+ attrs << %( title="#{node.attr 'title'}") if node.attr? 'title'
1055
+ %(<a href="#{node.target}"#{(_append_link_constraint_attrs node, attrs).join}>#{node.text}</a>)
1056
+ when :bibref
1057
+ %(<a id="#{node.id}"></a>[#{node.reftext || node.id}])
1058
+ else
1059
+ logger.warn %(unknown anchor type: #{node.type.inspect})
1060
+ nil
1083
1061
  end
1062
+ end
1084
1063
 
1085
- def inline_break node
1086
- %(#{node.text}<br#{@void_element_slash}>)
1087
- end
1064
+ def inline_break node
1065
+ %(#{node.text}<br#{@void_element_slash}>)
1066
+ end
1088
1067
 
1089
- def inline_button node
1090
- %(<b class="button">#{node.text}</b>)
1068
+ def inline_button node
1069
+ %(<b class="button">#{node.text}</b>)
1070
+ end
1071
+
1072
+ def inline_callout node
1073
+ if node.document.attr? 'icons', 'font'
1074
+ %(<i class="conum" data-value="#{node.text}"></i><b>(#{node.text})</b>)
1075
+ elsif node.document.attr? 'icons'
1076
+ src = node.icon_uri("callouts/#{node.text}")
1077
+ %(<img src="#{src}" alt="#{node.text}"#{@void_element_slash}>)
1078
+ else
1079
+ %(#{node.attributes['guard']}<b class="conum">(#{node.text})</b>)
1091
1080
  end
1081
+ end
1092
1082
 
1093
- def inline_callout node
1094
- if node.document.attr? 'icons', 'font'
1095
- %(<i class="conum" data-value="#{node.text}"></i><b>(#{node.text})</b>)
1096
- elsif node.document.attr? 'icons'
1097
- src = node.icon_uri("callouts/#{node.text}")
1098
- %(<img src="#{src}" alt="#{node.text}"#{@void_element_slash}>)
1083
+ def inline_footnote node
1084
+ if (index = node.attr 'index')
1085
+ if node.type == :xref
1086
+ %(<sup class="footnoteref">[<a class="footnote" href="#_footnotedef_#{index}" title="View footnote.">#{index}</a>]</sup>)
1099
1087
  else
1100
- %(#{node.attributes['guard']}<b class="conum">(#{node.text})</b>)
1088
+ id_attr = node.id ? %( id="_footnote_#{node.id}") : ''
1089
+ %(<sup class="footnote"#{id_attr}>[<a id="_footnoteref_#{index}" class="footnote" href="#_footnotedef_#{index}" title="View footnote.">#{index}</a>]</sup>)
1101
1090
  end
1091
+ elsif node.type == :xref
1092
+ %(<sup class="footnoteref red" title="Unresolved footnote reference.">[#{node.text}]</sup>)
1102
1093
  end
1094
+ end
1103
1095
 
1104
- def inline_footnote node
1105
- if (index = node.attr 'index', nil, false)
1106
- if node.type == :xref
1107
- %(<sup class="footnoteref">[<a class="footnote" href="#_footnotedef_#{index}" title="View footnote.">#{index}</a>]</sup>)
1108
- else
1109
- id_attr = node.id ? %( id="_footnote_#{node.id}") : ''
1110
- %(<sup class="footnote"#{id_attr}>[<a id="_footnoteref_#{index}" class="footnote" href="#_footnotedef_#{index}" title="View footnote.">#{index}</a>]</sup>)
1111
- end
1112
- elsif node.type == :xref
1113
- %(<sup class="footnoteref red" title="Unresolved footnote reference.">[#{node.text}]</sup>)
1096
+ def inline_image node
1097
+ if (type = node.type) == 'icon' && (node.document.attr? 'icons', 'font')
1098
+ class_attr_val = %(fa fa-#{node.target})
1099
+ { 'size' => 'fa-', 'rotate' => 'fa-rotate-', 'flip' => 'fa-flip-' }.each do |key, prefix|
1100
+ class_attr_val = %(#{class_attr_val} #{prefix}#{node.attr key}) if node.attr? key
1114
1101
  end
1115
- end
1116
-
1117
- def inline_image node
1118
- if (type = node.type) == 'icon' && (node.document.attr? 'icons', 'font')
1119
- class_attr_val = %(fa fa-#{node.target})
1120
- {'size' => 'fa-', 'rotate' => 'fa-rotate-', 'flip' => 'fa-flip-'}.each do |key, prefix|
1121
- class_attr_val = %(#{class_attr_val} #{prefix}#{node.attr key}) if node.attr? key
1122
- end
1123
- title_attr = (node.attr? 'title') ? %( title="#{node.attr 'title'}") : ''
1124
- img = %(<i class="#{class_attr_val}"#{title_attr}></i>)
1125
- elsif type == 'icon' && !(node.document.attr? 'icons')
1126
- img = %([#{node.alt}])
1127
- else
1128
- target = node.target
1129
- attrs = ['width', 'height', 'title'].map {|name| (node.attr? name) ? %( #{name}="#{node.attr name}") : '' }.join
1130
- if type != 'icon' && ((node.attr? 'format', 'svg', false) || (target.include? '.svg')) &&
1131
- node.document.safe < SafeMode::SECURE && ((svg = (node.option? 'inline')) || (obj = (node.option? 'interactive')))
1132
- if svg
1133
- img = (read_svg_contents node, target) || %(<span class="alt">#{node.alt}</span>)
1134
- elsif obj
1135
- fallback = (node.attr? 'fallback') ? %(<img src="#{node.image_uri(node.attr 'fallback')}" alt="#{encode_quotes node.alt}"#{attrs}#{@void_element_slash}>) : %(<span class="alt">#{node.alt}</span>)
1136
- img = %(<object type="image/svg+xml" data="#{node.image_uri target}"#{attrs}>#{fallback}</object>)
1137
- end
1102
+ title_attr = (node.attr? 'title') ? %( title="#{node.attr 'title'}") : ''
1103
+ img = %(<i class="#{class_attr_val}"#{title_attr}></i>)
1104
+ elsif type == 'icon' && !(node.document.attr? 'icons')
1105
+ img = %([#{node.alt}])
1106
+ else
1107
+ target = node.target
1108
+ attrs = ['width', 'height', 'title'].map {|name| (node.attr? name) ? %( #{name}="#{node.attr name}") : '' }.join
1109
+ if type != 'icon' && ((node.attr? 'format', 'svg') || (target.include? '.svg')) &&
1110
+ node.document.safe < SafeMode::SECURE && ((svg = (node.option? 'inline')) || (obj = (node.option? 'interactive')))
1111
+ if svg
1112
+ img = (_read_svg_contents node, target) || %(<span class="alt">#{node.alt}</span>)
1113
+ elsif obj
1114
+ fallback = (node.attr? 'fallback') ? %(<img src="#{node.image_uri(node.attr 'fallback')}" alt="#{_encode_attribute_value node.alt}"#{attrs}#{@void_element_slash}>) : %(<span class="alt">#{node.alt}</span>)
1115
+ img = %(<object type="image/svg+xml" data="#{node.image_uri target}"#{attrs}>#{fallback}</object>)
1138
1116
  end
1139
- img ||= %(<img src="#{type == 'icon' ? (node.icon_uri target) : (node.image_uri target)}" alt="#{encode_quotes node.alt}"#{attrs}#{@void_element_slash}>)
1140
- end
1141
- if node.attr? 'link', nil, false
1142
- img = %(<a class="image" href="#{node.attr 'link'}"#{(append_link_constraint_attrs node).join}>#{img}</a>)
1143
1117
  end
1144
- if (role = node.role)
1145
- if node.attr? 'float'
1146
- class_attr_val = %(#{type} #{node.attr 'float'} #{role})
1147
- else
1148
- class_attr_val = %(#{type} #{role})
1149
- end
1150
- elsif node.attr? 'float'
1151
- class_attr_val = %(#{type} #{node.attr 'float'})
1118
+ img ||= %(<img src="#{type == 'icon' ? (node.icon_uri target) : (node.image_uri target)}" alt="#{_encode_attribute_value node.alt}"#{attrs}#{@void_element_slash}>)
1119
+ end
1120
+ if node.attr? 'link'
1121
+ img = %(<a class="image" href="#{node.attr 'link'}"#{(_append_link_constraint_attrs node).join}>#{img}</a>)
1122
+ end
1123
+ if (role = node.role)
1124
+ if node.attr? 'float'
1125
+ class_attr_val = %(#{type} #{node.attr 'float'} #{role})
1152
1126
  else
1153
- class_attr_val = type
1127
+ class_attr_val = %(#{type} #{role})
1154
1128
  end
1155
- %(<span class="#{class_attr_val}">#{img}</span>)
1129
+ elsif node.attr? 'float'
1130
+ class_attr_val = %(#{type} #{node.attr 'float'})
1131
+ else
1132
+ class_attr_val = type
1156
1133
  end
1134
+ %(<span class="#{class_attr_val}">#{img}</span>)
1135
+ end
1136
+
1137
+ def inline_indexterm node
1138
+ node.type == :visible ? node.text : ''
1139
+ end
1157
1140
 
1158
- def inline_indexterm node
1159
- node.type == :visible ? node.text : ''
1141
+ def inline_kbd node
1142
+ if (keys = node.attr 'keys').size == 1
1143
+ %(<kbd>#{keys[0]}</kbd>)
1144
+ else
1145
+ %(<span class="keyseq"><kbd>#{keys.join '</kbd>+<kbd>'}</kbd></span>)
1160
1146
  end
1147
+ end
1161
1148
 
1162
- def inline_kbd node
1163
- if (keys = node.attr 'keys').size == 1
1164
- %(<kbd>#{keys[0]}</kbd>)
1149
+ def inline_menu node
1150
+ caret = (node.document.attr? 'icons', 'font') ? '&#160;<i class="fa fa-angle-right caret"></i> ' : '&#160;<b class="caret">&#8250;</b> '
1151
+ submenu_joiner = %(</b>#{caret}<b class="submenu">)
1152
+ menu = node.attr 'menu'
1153
+ if (submenus = node.attr 'submenus').empty?
1154
+ if (menuitem = node.attr 'menuitem')
1155
+ %(<span class="menuseq"><b class="menu">#{menu}</b>#{caret}<b class="menuitem">#{menuitem}</b></span>)
1165
1156
  else
1166
- %(<span class="keyseq"><kbd>#{keys.join '</kbd>+<kbd>'}</kbd></span>)
1157
+ %(<b class="menuref">#{menu}</b>)
1167
1158
  end
1159
+ else
1160
+ %(<span class="menuseq"><b class="menu">#{menu}</b>#{caret}<b class="submenu">#{submenus.join submenu_joiner}</b>#{caret}<b class="menuitem">#{node.attr 'menuitem'}</b></span>)
1168
1161
  end
1162
+ end
1169
1163
 
1170
- def inline_menu node
1171
- caret = (node.document.attr? 'icons', 'font') ? '&#160;<i class="fa fa-angle-right caret"></i> ' : '&#160;<b class="caret">&#8250;</b> '
1172
- submenu_joiner = %(</b>#{caret}<b class="submenu">)
1173
- menu = node.attr 'menu'
1174
- if (submenus = node.attr 'submenus').empty?
1175
- if (menuitem = node.attr 'menuitem', nil, false)
1176
- %(<span class="menuseq"><b class="menu">#{menu}</b>#{caret}<b class="menuitem">#{menuitem}</b></span>)
1177
- else
1178
- %(<b class="menuref">#{menu}</b>)
1179
- end
1164
+ def inline_quoted node
1165
+ open, close, tag = QUOTE_TAGS[node.type]
1166
+ if node.id
1167
+ class_attr = node.role ? %( class="#{node.role}") : ''
1168
+ if tag
1169
+ %(#{open.chop} id="#{node.id}"#{class_attr}>#{node.text}#{close})
1180
1170
  else
1181
- %(<span class="menuseq"><b class="menu">#{menu}</b>#{caret}<b class="submenu">#{submenus.join submenu_joiner}</b>#{caret}<b class="menuitem">#{node.attr 'menuitem'}</b></span>)
1171
+ %(<span id="#{node.id}"#{class_attr}>#{open}#{node.text}#{close}</span>)
1182
1172
  end
1183
- end
1184
-
1185
- def inline_quoted node
1186
- open, close, is_tag = QUOTE_TAGS[node.type]
1187
- class_attr = %( class="#{node.role}") if node.role
1188
- id_attr = %( id="#{node.id}") if node.id
1189
- if class_attr || id_attr
1190
- if is_tag
1191
- %(#{open.chop}#{id_attr || ''}#{class_attr || ''}>#{node.text}#{close})
1192
- else
1193
- %(<span#{id_attr || ''}#{class_attr || ''}>#{open}#{node.text}#{close}</span>)
1194
- end
1173
+ elsif node.role
1174
+ if tag
1175
+ %(#{open.chop} class="#{node.role}">#{node.text}#{close})
1195
1176
  else
1196
- %(#{open}#{node.text}#{close})
1177
+ %(<span class="#{node.role}">#{open}#{node.text}#{close}</span>)
1197
1178
  end
1179
+ else
1180
+ %(#{open}#{node.text}#{close})
1198
1181
  end
1182
+ end
1199
1183
 
1200
- def append_boolean_attribute name, xml
1201
- xml ? %( #{name}="#{name}") : %( #{name})
1202
- end
1184
+ private
1203
1185
 
1204
- def encode_quotes val
1205
- (val.include? '"') ? (val.gsub '"', '&quot;') : val
1186
+ def _append_boolean_attribute name, xml
1187
+ xml ? %( #{name}="#{name}") : %( #{name})
1188
+ end
1189
+
1190
+ def _append_link_constraint_attrs node, attrs = []
1191
+ rel = 'nofollow' if node.option? 'nofollow'
1192
+ if (window = node.attributes['window'])
1193
+ attrs << %( target="#{window}")
1194
+ attrs << (rel ? %( rel="#{rel} noopener") : ' rel="noopener"') if window == '_blank' || (node.option? 'noopener')
1195
+ elsif rel
1196
+ attrs << %( rel="#{rel}")
1206
1197
  end
1198
+ attrs
1199
+ end
1207
1200
 
1208
- def generate_manname_section node
1209
- manname_title = node.attr 'manname-title', 'Name'
1210
- if (next_section = node.sections[0]) && (next_section_title = next_section.title) == next_section_title.upcase
1211
- manname_title = manname_title.upcase
1212
- end
1213
- manname_id_attr = (manname_id = node.attr 'manname-id') ? %( id="#{manname_id}") : ''
1214
- %(<h2#{manname_id_attr}>#{manname_title}</h2>
1201
+ def _encode_attribute_value val
1202
+ (val.include? '"') ? (val.gsub '"', '&quot;') : val
1203
+ end
1204
+
1205
+ def _generate_manname_section node
1206
+ manname_title = node.attr 'manname-title', 'Name'
1207
+ if (next_section = node.sections[0]) && (next_section_title = next_section.title) == next_section_title.upcase
1208
+ manname_title = manname_title.upcase
1209
+ end
1210
+ manname_id_attr = (manname_id = node.attr 'manname-id') ? %( id="#{manname_id}") : ''
1211
+ %(<h2#{manname_id_attr}>#{manname_title}</h2>
1215
1212
  <div class="sectionbody">
1216
1213
  <p>#{node.attr 'manname'} - #{node.attr 'manpurpose'}</p>
1217
1214
  </div>)
1218
- end
1219
-
1220
- def append_link_constraint_attrs node, attrs = []
1221
- rel = 'nofollow' if node.option? 'nofollow'
1222
- if (window = node.attributes['window'])
1223
- attrs << %( target="#{window}")
1224
- attrs << (rel ? %( rel="#{rel} noopener") : ' rel="noopener"') if window == '_blank' || (node.option? 'noopener')
1225
- elsif rel
1226
- attrs << %( rel="#{rel}")
1227
- end
1228
- attrs
1229
- end
1215
+ end
1230
1216
 
1231
- def read_svg_contents node, target
1232
- if (svg = node.read_contents target, :start => (node.document.attr 'imagesdir'), :normalize => true, :label => 'SVG')
1233
- svg = svg.sub SvgPreambleRx, '' unless svg.start_with? '<svg'
1234
- old_start_tag = new_start_tag = nil
1235
- # NOTE width, height and style attributes are removed if either width or height is specified
1236
- ['width', 'height'].each do |dim|
1237
- if node.attr? dim
1238
- new_start_tag = (old_start_tag = (svg.match SvgStartTagRx)[0]).gsub DimensionAttributeRx, '' unless new_start_tag
1239
- # QUESTION should we add px since it's already the default?
1240
- new_start_tag = %(#{new_start_tag.chop} #{dim}="#{node.attr dim}px">)
1241
- end
1217
+ def _read_svg_contents node, target
1218
+ if (svg = node.read_contents target, start: (node.document.attr 'imagesdir'), normalize: true, label: 'SVG')
1219
+ svg = svg.sub SvgPreambleRx, '' unless svg.start_with? '<svg'
1220
+ old_start_tag = new_start_tag = nil
1221
+ # NOTE width, height and style attributes are removed if either width or height is specified
1222
+ ['width', 'height'].each do |dim|
1223
+ if node.attr? dim
1224
+ new_start_tag = (old_start_tag = (svg.match SvgStartTagRx)[0]).gsub DimensionAttributeRx, '' unless new_start_tag
1225
+ # QUESTION should we add px since it's already the default?
1226
+ new_start_tag = %(#{new_start_tag.chop} #{dim}="#{node.attr dim}px">)
1242
1227
  end
1243
- svg = %(#{new_start_tag}#{svg[old_start_tag.length..-1]}) if new_start_tag
1244
1228
  end
1245
- svg
1229
+ svg = %(#{new_start_tag}#{svg[old_start_tag.length..-1]}) if new_start_tag
1246
1230
  end
1231
+ svg
1247
1232
  end
1248
1233
  end
1234
+ end