asciidoctor-html 2.1.2 → 2.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -38,7 +38,8 @@ module Asciidoctor
38
38
  "imagesdir" => IMG_PATH,
39
39
  "dollar" => "$",
40
40
  "parskip" => %(<span class="parskip"></span><br>),
41
- "notitle" => %(<span class="notitle">&nbsp;</span>)
41
+ "notitle" => %(<span class="notitle">&nbsp;</span>),
42
+ "br" => "<br>"
42
43
  }.freeze
43
44
 
44
45
  DEFAULT_OPTS = {
@@ -265,7 +266,6 @@ module Asciidoctor
265
266
  title: @title,
266
267
  short_title: @short_title,
267
268
  authors: display_authors(doc),
268
- date: @date,
269
269
  description: doc.attr("description"),
270
270
  chapheading: tdata.chapheading,
271
271
  chapsubheading: tdata.chapsubheading,
@@ -111,8 +111,6 @@ module Asciidoctor
111
111
  </div>
112
112
  #{opts[:content]}
113
113
  </div>
114
- #{opts[:paginator]}
115
- #{footer opts[:authors]}
116
114
  </main>
117
115
  HTML
118
116
  end
@@ -154,10 +152,12 @@ module Asciidoctor
154
152
 
155
153
  def self.footer(authors)
156
154
  <<~HTML
157
- <footer class="footer dynamic-width">
158
- <div class="footer-left">&#169; <span id="cr-year"></span> #{authors}</div>
159
- <div class="footer-right">Built with
160
- <a href="https://github.com/ravirajani/asciidoctor-html">asciidoctor-html</a>
155
+ <footer class="footer">
156
+ <div class="footer-content dynamic-width">
157
+ <div class="footer-left">&#169; <span id="cr-year"></span> #{authors}</div>
158
+ <div class="footer-right">Built with
159
+ <a href="https://github.com/ravirajani/asciidoctor-html">asciidoctor-html</a>
160
+ </div>
161
161
  </div>
162
162
  </footer>
163
163
  HTML
@@ -227,8 +227,10 @@ module Asciidoctor
227
227
  def self.html(content, nav_items, opts = {})
228
228
  nav = !nav_items.empty? && (nav_items.size > 1 || opts[:has_subnav])
229
229
  page_classes = ["page"]
230
- page_classes << "multi" unless opts[:pagestyle] == :single
231
- page_classes << "presentation" if opts[:pagestyle] == :presentation
230
+ if nav
231
+ page_classes << "multi" unless opts[:pagestyle] == :single
232
+ page_classes << "presentation" if opts[:pagestyle] == :presentation
233
+ end
232
234
  page_classname = page_classes.join " "
233
235
  <<~HTML
234
236
  <!DOCTYPE html>
@@ -243,6 +245,8 @@ module Asciidoctor
243
245
  #{MENU_BTN if nav}
244
246
  #{header opts[:title], opts[:short_title], opts[:chapheading], opts[:has_subnav]}
245
247
  #{main content:, **opts}
248
+ #{opts[:paginator]}
249
+ #{footer opts[:authors]}
246
250
  </div> <!-- .page -->
247
251
  <script>document.getElementById("cr-year").textContent = (new Date()).getFullYear();</script>
248
252
  <script type="module">
@@ -250,8 +254,8 @@ module Asciidoctor
250
254
  #{Popovers::POPOVERS}
251
255
  #{Sidebar::TOGGLE if nav}
252
256
  #{Scroll::SCROLL}
253
- #{Flip::FLIP}
254
- #{Live::LIVE if opts[:has_live]}
257
+ #{Flip::FLIP if nav}
258
+ #{Live::LIVE if nav && opts[:has_live]}
255
259
  </script>
256
260
  #{opts[:at_body_end]}
257
261
  </body>
@@ -5,6 +5,7 @@ require_relative "list"
5
5
  require_relative "utils"
6
6
  require_relative "figure"
7
7
  require_relative "table"
8
+ require_relative "tabs"
8
9
  require_relative "jupyterlite"
9
10
 
10
11
  module Asciidoctor
@@ -165,24 +166,31 @@ module Asciidoctor
165
166
  end
166
167
 
167
168
  def convert_example(node)
168
- Utils.wrap_node_with_title node.content, node
169
+ Utils.wrap_node(Utils.display_title(node) + node.content, node)
169
170
  end
170
171
 
171
172
  def convert_image(node)
172
173
  content = display_figure node
173
- Utils.wrap_id_classes content, node.id, ["figbox", node.role].compact.join(" ")
174
+ classes = ["figbox", node.role]
175
+ Utils.wrap_live(
176
+ Utils.wrap_id_classes(content, node.id, classes.compact.join(" ")),
177
+ node.attr("live")
178
+ )
174
179
  end
175
180
 
176
181
  def convert_inline_image(node)
177
182
  target = node.target
178
183
  return read_svg_contents(node, target) if node.option?("inline")
179
184
 
180
- mark = node.parent.attr "mark"
185
+ parent = node.parent
186
+ mark = parent.attr "mark"
181
187
  title_attr = node.attr? "title"
182
188
  if mark # The image is part of a figlist
183
189
  title = node.attr("title") if title_attr
184
- %( #{display_image node, target}
185
- <figcaption><span class="li-mark">#{mark}</span>#{title}</figcaption>).gsub(/^ /, "")
190
+ caption = if title_attr || parent.context == :olist
191
+ %(\n <figcaption><span class="li-mark">#{mark}</span>#{title}</figcaption>)
192
+ end
193
+ %( #{display_image node, target}#{caption})
186
194
  else
187
195
  display_image node, target, title_attr:
188
196
  end
@@ -199,20 +207,25 @@ module Asciidoctor
199
207
  end
200
208
 
201
209
  def convert_ulist(node)
210
+ return convert_figlist(node) if node.style == "figlist"
211
+
202
212
  List.convert node, :ul
203
213
  end
204
214
 
205
215
  def convert_dlist(node)
216
+ return Tabs.convert_tabs(node) if node.option?("tabs")
217
+
206
218
  classes = ["dlist", node.style, node.role].compact.join(" ")
207
219
  result = [%(<dl#{Utils.dyn_id_class_attr_str node, classes}>)]
208
220
  live = node.attr? "live"
209
221
  line_number = 1
210
222
  node.items.each do |terms, dd|
223
+ return %(<p class="text-danger">Definition is required.</p>) unless dd
224
+
211
225
  terms.each do |dt|
212
226
  result << %(<dt class="dterm"#{Utils.line_number_attr line_number, live:}>#{dt.text}</dt>)
213
227
  line_number += 1
214
228
  end
215
- next unless dd
216
229
 
217
230
  result << "<dd#{Utils.line_number_attr line_number, live:}>"
218
231
  line_number += 1
@@ -264,7 +277,7 @@ module Asciidoctor
264
277
  width_attribute = %( width="#{tablewidth}%")
265
278
  end
266
279
  result = [%(<table#{Utils.id_class_attr_str node.id, classes.join(" ")}#{width_attribute}>)]
267
- unless node.option? "nocaption"
280
+ if Utils.show_title? node
268
281
  result << %(<caption class="table-title">#{Utils.display_title_prefix node}#{node.title}</caption>)
269
282
  end
270
283
  if node.attr("rowcount").positive? && node.attr?("cols")
@@ -23,18 +23,21 @@ module Asciidoctor
23
23
 
24
24
  def display_figure(node)
25
25
  target = node.attr "target"
26
- title = node.title? ? node.title : ""
26
+ title = node.title if node.title?
27
27
  image = display_image node, target
28
- caption = %( <figcaption>#{Utils.display_title_prefix node}#{title}</figcaption>)
29
- %(<figure>\n #{image}\n#{caption}\n</figure>)
28
+ caption = %( <figcaption>#{Utils.display_title_prefix node}#{title}</figcaption>\n) if Utils.show_title?(node)
29
+ %(<figure>\n #{image}\n#{caption}</figure>)
30
30
  end
31
31
 
32
32
  def convert_figlist(node)
33
+ tagname = node.context == :olist ? :ol : :ul
33
34
  result = node.items.map do |item|
34
35
  %(<li#{Utils.id_class_attr_str item.id, item.role}><figure>\n#{item.text}\n</figure></li>)
35
36
  end
36
- content = Utils.wrap_id_classes result.join("\n"), nil, "figlist", :ol
37
- title = %(<div class="figlist-title">#{Utils.display_title_prefix(node)}#{node.title}</div>)
37
+ content = Utils.wrap_id_classes result.join("\n"), nil, "figlist", tagname
38
+ title = if Utils.show_title?(node)
39
+ %(<div class="figlist-title">#{Utils.display_title_prefix(node)}#{node.title}</div>)
40
+ end
38
41
  classes = ["figlist-wrapper", node.role].compact.join(" ")
39
42
  Utils.wrap_id_classes %(#{content}#{title}), node.id, classes
40
43
  end
@@ -1,10 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "pagination"
4
+
3
5
  module Asciidoctor
4
6
  module Html
5
7
  # Flip when pagestyle is multi or presentation
6
8
  module Flip
7
- FLIP = <<~JS
9
+ FLIP = <<~JS.freeze
8
10
  (function() {
9
11
  // Holds replaced pagination links to prev/next chapter
10
12
  const chapPagination = {
@@ -16,6 +18,7 @@ module Asciidoctor
16
18
  const sectsById = { "page": []};
17
19
 
18
20
  const page = document.getElementById('page');
21
+ const main = document.getElementById('main');
19
22
  const focusEl = document.getElementById('content-container');
20
23
  const searchForm = document.getElementById('search-form');
21
24
  const chapheading = page.querySelector('.chapheading');
@@ -45,7 +48,14 @@ module Asciidoctor
45
48
  function focusOnLoad() {
46
49
  if(searchForm) return;
47
50
 
48
- focusEl.focus({preventScroll: !page.classList.contains('presentation')});
51
+ focusEl.focus({preventScroll: true});
52
+ }
53
+
54
+ function pagitemHTML(text, direction) {
55
+ if(direction == 'left') {
56
+ return `#{Pagination.pagitem_html "${text}", left: true}`;
57
+ }
58
+ return `#{Pagination.pagitem_html "${text}"}`;
49
59
  }
50
60
 
51
61
  function updatePaginator(prev, next) {
@@ -56,13 +66,10 @@ module Asciidoctor
56
66
  if(next) {
57
67
  const nextH = next.querySelector(':scope > h2');
58
68
  const nextLink = document.createElement('a');
59
- nextLink.id = "flip-forward"
69
+ nextLink.id = 'flip-forward';
60
70
  const nextSectText = nextH && nextH.innerHTML;
61
71
  nextLink.href = '#' + next.id;
62
- nextLink.innerHTML = `
63
- <div>${nextSectText || ''}</div>
64
- <div><i class="bi bi-chevron-compact-right"></i></div>
65
- `;
72
+ nextLink.innerHTML = pagitemHTML(nextSectText, 'right');
66
73
  chapPagination.nextChap ||= nextPage;
67
74
  nextPage.replaceWith(nextLink);
68
75
  } else if(chapPagination.nextChap) {
@@ -72,21 +79,17 @@ module Asciidoctor
72
79
  const prevH = prev.querySelector(':scope > h2');
73
80
  const prevSectitle = prevH && (prevH.innerHTML + ' ');
74
81
  const prevLink = document.createElement('a');
75
- prevLink.id = "flip-back"
82
+ prevLink.id = 'flip-back';
76
83
  let prevSectText = prevSectitle || chapheading &&
77
- ('<span class="title-prefix">' + chapheading.textContent + '</span><br>');
84
+ ('<span class="title-prefix">' + chapheading.textContent + '</span><br>') || '';
78
85
  if(!prevH) prevSectText += chaptitle.textContent;
79
86
  prevLink.href = '#' + (prev.id ? prev.id : 'page');
80
- prevLink.innerHTML = `
81
- <div><i class="bi bi-chevron-compact-left"></i></div>
82
- <div>${prevSectText || ''}</div>
83
- `;
87
+ prevLink.innerHTML = pagitemHTML(prevSectText, 'left');
84
88
  chapPagination.prevChap ||= prevPage;
85
89
  prevPage.replaceWith(prevLink);
86
90
  } else if(chapPagination.prevChap) {
87
- prevPage.replaceWith(chapPagination.prevChap)
91
+ prevPage.replaceWith(chapPagination.prevChap);
88
92
  }
89
- paginator.classList.toggle('visible', paginator.querySelector('a'));
90
93
  }
91
94
 
92
95
  function flip(e) {
@@ -132,15 +135,17 @@ module Asciidoctor
132
135
 
133
136
  ADHT.nudgeMenuBtn();
134
137
 
138
+ const scrollEl = page.classList.contains('presentation') ? main : page;
135
139
  if(target == section) {
136
- page.scrollTo({
140
+ scrollEl.scrollTo({
137
141
  top: 0,
138
- left: 0
142
+ left: 0,
143
+ behavior: 'instant'
139
144
  });
140
145
  } else {
141
- const rect = target.getBoundingClientRect()
142
- page.scrollTo({
143
- top: rect.top + page.scrollTop,
146
+ const rect = target.getBoundingClientRect();
147
+ scrollEl.scrollTo({
148
+ top: rect.top + scrollEl.scrollTop,
144
149
  left: 0
145
150
  });
146
151
  }
@@ -148,6 +153,7 @@ module Asciidoctor
148
153
  focusOnLoad();
149
154
  if(isPresentation) focusEl.dataset.flip = id;
150
155
  }
156
+
151
157
  flip();
152
158
 
153
159
  const dropdownItems = document.querySelectorAll('#viewmode-actions .dropdown-item');
@@ -192,6 +198,7 @@ module Asciidoctor
192
198
  }));
193
199
 
194
200
  page.classList.add('loaded');
201
+
195
202
  ADHT.move = move;
196
203
  })();
197
204
  JS
@@ -64,7 +64,7 @@ module Asciidoctor
64
64
 
65
65
  const overlay = document.createElement('div');
66
66
  overlay.classList.add('copy-button');
67
- overlay.textContent = result.language.toUpperCase() + ' ';
67
+ // overlay.textContent = result.language.toUpperCase() + ' ';
68
68
 
69
69
  const copyButton = document.createElement('button');
70
70
  copyButton.classList.add('btn');
@@ -2,12 +2,8 @@
2
2
 
3
3
  module Asciidoctor
4
4
  module Html
5
- # Constants for the jupyterlite library
5
+ # Jupyterlite library
6
6
  module Jupyterlite
7
- class << self
8
- attr_accessor :cell_id
9
- end
10
-
11
7
  PATH = "jupyterlite"
12
8
  REPL_PATH = "repl/index.html"
13
9
 
@@ -40,8 +36,7 @@ module Asciidoctor
40
36
  end
41
37
 
42
38
  def self.html(node)
43
- @cell_id += 1
44
- cell_id = "jupyter-cell-frame-#{@cell_id}"
39
+ cell_id = "jupyter-cell-frame-#{node.attr "jupyter-cell-id"}"
45
40
  height_attr = %( style="height: #{node.attr("height")}px;") if node.attr?("height")
46
41
  <<~HTML
47
42
  <div id="#{cell_id}"#{height_attr} class="jupyter-cell"></div>
@@ -5,7 +5,7 @@ module Asciidoctor
5
5
  # Helper functions for the list conversion
6
6
  module List
7
7
  def self.convert(node, tag_name = :ol)
8
- depth = node.attr "list-depth"
8
+ depth = node.attr "list-depth", 0
9
9
  flat = node.attr? "flat-style"
10
10
  inside = node.option? "inside"
11
11
  level = depth + 1
@@ -7,28 +7,61 @@ module Asciidoctor
7
7
  # Pagination item
8
8
  PagItem = Struct.new "PagItem", :url, :title, :text
9
9
 
10
+ def self.chevron(left: false)
11
+ transform_attr = %( transform="rotate(180 7 8)") if left
12
+ <<~HTML
13
+ <svg xmlns="http://www.w3.org/2000/svg" width="100%" fill="currentColor" viewBox="3 0 8 16">
14
+ <path#{transform_attr} fill-rule="evenodd" d="M6.776 1.553a.5.5 0 0 1 .671.223l3 6a.5.5 0 0 1 0 .448l-3 6a.5.5 0 1 1-.894-.448L9.44 8 6.553 2.224a.5.5 0 0 1 .223-.671"/>
15
+ </svg>
16
+ HTML
17
+ end
18
+
19
+ def self.pagitem_html(text, left: false)
20
+ if left
21
+ <<~HTML
22
+ <div class="chevron">
23
+ #{Pagination.chevron left:}
24
+ </div>
25
+ <div class="pagination-prv">#{text}</div>
26
+ HTML
27
+ else
28
+ <<~HTML
29
+ <div class="pagination-nxt">#{text}</div>
30
+ <div class="chevron">
31
+ #{Pagination.chevron}
32
+ </div>
33
+ HTML
34
+ end
35
+ end
36
+
37
+ def self.display_prefix(prefix)
38
+ %(<span class="title-prefix">#{prefix}</span><br>)
39
+ end
40
+
10
41
  def display_paginator(prv, nxt)
11
42
  blank = %(<span class="blank">&nbsp;</span>)
12
43
  html = [<<~HTML
13
- <div class="paginator-wrapper dynamic-width">
14
- <div class="paginator">
44
+ <div class="paginator-wrapper">
45
+ <div class="paginator dynamic-width">
15
46
  HTML
16
47
  ]
17
48
  html << if prv
49
+ prefix = Pagination.display_prefix(prv.title) if prv.title
50
+ text = "#{prefix}#{prv.text}"
18
51
  <<~HTML
19
52
  <a id="flip-back" href="#{prv.url}">
20
- <div><i class="bi bi-chevron-compact-left"></i></div>
21
- <div>#{%(<span class="title-prefix">#{prv.title}</span><br>) if prv.title}#{prv.text}</div>
53
+ #{Pagination.pagitem_html text, left: true}
22
54
  </a>
23
55
  HTML
24
56
  else
25
57
  blank
26
58
  end
27
59
  html << if nxt
60
+ prefix = Pagination.display_prefix(nxt.title) if nxt.title
61
+ text = "#{prefix}#{nxt.text}"
28
62
  <<~HTML
29
63
  <a id="flip-forward" href="#{nxt.url}">
30
- <div>#{%(<span class="title-prefix">#{nxt.title}</span><br>) if nxt.title}#{nxt.text}</div>
31
- <div><i class="bi bi-chevron-compact-right"></i></div>
64
+ #{Pagination.pagitem_html text}
32
65
  </a>
33
66
  HTML
34
67
  else
@@ -22,27 +22,34 @@ module Asciidoctor
22
22
  listing: "ltg-number"
23
23
  }.freeze
24
24
 
25
- def assign_numeral!(node, document, counter_name)
25
+ def initialize(*args)
26
+ @jupyter_cell_id = 0
27
+ @tabs_id = 0
28
+ super
29
+ end
30
+
31
+ def assign_numeral!(node, counter_name)
32
+ document = node.document
26
33
  document.counters[counter_name] ||= 0
27
34
  node.numeral = (document.counters[counter_name] += 1)
28
35
  end
29
36
 
30
- def relative_numeral(node, document)
37
+ def relative_numeral(node)
31
38
  return "" unless node.numeral
32
39
 
33
- chapnum = document.attr "chapnum"
40
+ chapnum = node.document.attr "chapnum"
34
41
  has_prefix = chapnum && !chapnum.empty? && chapnum != "0"
35
42
  has_prefix ? "#{chapnum}.#{node.numeral}" : node.numeral.to_s
36
43
  end
37
44
 
38
- def process_numbered_block!(block, document)
45
+ def process_numbered_block!(block)
39
46
  context = block.context
40
47
  style = block.style
41
48
  context = :image if style == "figlist"
42
49
  env = env context, style
43
50
  block.set_attr("showcaption", true) unless context == :stem
44
- assign_numeral! block, document, NUMBERED_CONTEXTS[context] unless context == :section
45
- relative_numeral = relative_numeral block, document
51
+ assign_numeral! block, NUMBERED_CONTEXTS[context] unless context == :section
52
+ relative_numeral = relative_numeral block
46
53
 
47
54
  reftext = if context == :stem
48
55
  "(#{relative_numeral})"
@@ -53,6 +60,27 @@ module Asciidoctor
53
60
  block.set_attr "title-prefix", reftext
54
61
  end
55
62
 
63
+ def process_unnumbered_block!(block)
64
+ reftext = block.title? ? block.title : "[#{block.id}]"
65
+ block.set_attr "reftext", reftext
66
+ end
67
+
68
+ def process_block!(block)
69
+ if block.option? "unnumbered"
70
+ process_unnumbered_block! block
71
+ elsif process_numbered_block? block
72
+ process_numbered_block! block
73
+ end
74
+ if block.option? "jupyter"
75
+ @jupyter_cell_id += 1
76
+ block.set_attr "jupyter-cell-id", @jupyter_cell_id
77
+ end
78
+ return unless block.option? "tabs"
79
+
80
+ @tabs_id += 1
81
+ block.set_attr "tabs-id", @tabs_id
82
+ end
83
+
56
84
  def env(context, style)
57
85
  case context
58
86
  when :image then "figure"
@@ -69,8 +97,6 @@ module Asciidoctor
69
97
  block.style == "figlist"
70
98
  when :stem, :listing
71
99
  block.option? "numbered"
72
- when :table
73
- !block.option? "nocaption"
74
100
  when :section
75
101
  block.numbered && block.level == 1
76
102
  else
@@ -236,7 +262,7 @@ module Asciidoctor
236
262
  tw = TreeWalker.new document
237
263
  while (block = tw.next_block)
238
264
  unless block.attr? "refprocessed"
239
- process_numbered_block!(block, document) if process_numbered_block?(block)
265
+ process_block! block
240
266
  if colist? block
241
267
  process_colist! block
242
268
  elsif (is_olist = olist? block) || (is_ulist = ulist? block)
@@ -12,12 +12,12 @@ module Asciidoctor
12
12
  def search_page
13
13
  content = <<~HTML
14
14
  <div class="search-form-container">
15
- <div id="search-form-spinner" class="d-flex justify-content-center">
15
+ <div id="search-form-spinner" class="d-flex justify-content-center position-absolute w-100">
16
16
  <div class="spinner-border" role="status">
17
17
  <span class="visually-hidden">Loading...</span>
18
18
  </div>
19
19
  </div>
20
- <form id="search-form" class="search-form hidden">
20
+ <form id="search-form" class="search-form invisible">
21
21
  <input type="text" id="search-text" name="search-text" class="form-control search-box" placeholder="Search">
22
22
  <button type="submit" class="btn btn-primary search-btn">Go</button>
23
23
  </form>
@@ -33,11 +33,10 @@ module Asciidoctor
33
33
  title: @title,
34
34
  short_title: @short_title,
35
35
  authors: display_authors,
36
- date: @date,
37
36
  chapsubheading: "Search",
38
- langs: [],
39
37
  at_head_end: %(<script defer src="https://cdn.jsdelivr.net/npm/lunr@2.3.9/lunr.min.js"></script>),
40
- at_body_end: %(<script type="module">#{lunr_script}</script>)
38
+ at_body_end: %(<script type="module">#{lunr_script}</script>),
39
+ pagestyle: :single
41
40
  )
42
41
  end
43
42
 
@@ -168,7 +167,7 @@ module Asciidoctor
168
167
  resultsContainer.classList.remove('hidden');
169
168
  }
170
169
  document.getElementById('search-form-spinner').classList.add('hidden');
171
- searchForm.classList.remove('hidden');
170
+ searchForm.classList.remove('invisible');
172
171
  searchForm.addEventListener('submit', e => {
173
172
  e.preventDefault();
174
173
  const searchText = searchBox.value;
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "utils"
4
+
5
+ module Asciidoctor
6
+ module Html
7
+ # Helpers for the tabs conversion
8
+ module Tabs
9
+ def self.convert_tabs(node)
10
+ tabs_id = node.attr "tabs-id"
11
+ nav = [%(<div class="nav nav-tabs" role="tablist">)]
12
+ panes = [%(<div class="tab-content">)]
13
+ pane_number = 1
14
+ node.items.each do |terms, dd|
15
+ return %(<p class="text-danger">Definition is required.</p>) unless dd
16
+
17
+ active = pane_number == 1
18
+ tab_id = "tab-#{tabs_id}-#{pane_number}"
19
+ pane_id = "#{tab_id}-pane"
20
+ terms.each do |dt|
21
+ class_attr = %( class="nav-link#{" active" if active}")
22
+ target_attr = %( data-bs-target="##{pane_id}")
23
+ selected_attr = %( aria-selected="#{active ? "true" : "false"}")
24
+ other_attrs = %( data-bs-toggle="tab" type="button" role="tab" aria-controls="#{pane_id}")
25
+ id_attr = %( id="#{tab_id}")
26
+ nav << %(<button#{id_attr}#{class_attr}#{target_attr}#{other_attrs}#{selected_attr}>#{dt.text}</button>)
27
+ end
28
+
29
+ class_attr = %( class="tab-pane#{" show active" if active}")
30
+ id_attr = %( id="#{pane_id}")
31
+ other_attrs = %( role="tabpanel" aria-labelledby="#{tab_id}" tabindex="0")
32
+ panes << %(<div#{id_attr}#{class_attr}#{other_attrs}>)
33
+ panes << %(<p>#{dd.text}</p>) if dd.text?
34
+ panes << dd.content if dd.blocks?
35
+ panes << "</div>"
36
+ pane_number += 1
37
+ end
38
+ nav << "</div> <!-- .nav.nav-tabs -->\n"
39
+ panes << "</div> <!-- .tab-content -->\n"
40
+ content = %(<div class="tabs">\n#{nav.join("\n")}#{panes.join("\n")}</div> <!-- .tabs -->\n)
41
+ Utils.wrap_id_classes_with_title(content, node, node.id, "tabs-wrapper")
42
+ end
43
+ end
44
+ end
45
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Asciidoctor
4
4
  module Html
5
- VERSION = "2.1.2"
5
+ VERSION = "2.1.4"
6
6
  end
7
7
  end
@@ -37,7 +37,7 @@ module Minitest
37
37
  title = display_result_title name, failed, color
38
38
  pre = %([live=normal-faded,asciidoc]\n------\n#{adoc}\n------\n)
39
39
  fail = failed ? display_failure(@results[key].join("\n")) : ""
40
- %([##{id}]\n== #{title}\n\n#{pre}#{fail}\n\n#{adoc}\n\n)
40
+ %([##{id}.flex-grow-1]\n== #{title}\n\n#{pre}#{fail}\n\n#{adoc}\n\n)
41
41
  end
42
42
 
43
43
  def report_files(results, dirname)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asciidoctor-html
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.2
4
+ version: 2.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ravi Rajani
@@ -134,6 +134,7 @@ files:
134
134
  - lib/asciidoctor/html/sidebar.rb
135
135
  - lib/asciidoctor/html/subnav_block_macro.rb
136
136
  - lib/asciidoctor/html/table.rb
137
+ - lib/asciidoctor/html/tabs.rb
137
138
  - lib/asciidoctor/html/text_inline_macro.rb
138
139
  - lib/asciidoctor/html/tree_walker.rb
139
140
  - lib/asciidoctor/html/utils.rb