asciidoctor 1.5.8 → 2.0.0.rc.1

Sign up to get free protection for your applications and to get access to all the features.
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