asciidoctor-html 0.1.6 → 0.1.7

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.
Binary file
Binary file
Binary file
Binary file
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "asciidoctor"
4
- require "pathname"
5
4
 
6
5
  module Asciidoctor
7
6
  module Html
@@ -8,7 +8,9 @@ require_relative "converter"
8
8
  require_relative "ref_tree_processor"
9
9
  require_relative "cref_inline_macro"
10
10
  require_relative "bi_inline_macro"
11
+ require_relative "sc_inline_macro"
11
12
  require_relative "template"
13
+ require_relative "pagination"
12
14
 
13
15
  module Asciidoctor
14
16
  module Html
@@ -21,6 +23,7 @@ module Asciidoctor
21
23
  Asciidoctor::Extensions.register do
22
24
  tree_processor RefTreeProcessor
23
25
  inline_macro CrefInlineMacro
26
+ inline_macro ScInlineMacro
24
27
  inline_macro BiInlineMacro
25
28
  end
26
29
 
@@ -29,7 +32,9 @@ module Asciidoctor
29
32
  "stem" => "latexmath",
30
33
  "hide-uri-scheme" => true,
31
34
  "source-highlighter" => "highlight.js",
32
- "imagesdir" => IMG_PATH
35
+ "imagesdir" => IMG_PATH,
36
+ "dollar" => "$",
37
+ "parskip" => %(<span class="parskip"></span><br>)
33
38
  }.freeze
34
39
 
35
40
  DEFAULT_OPTS = {
@@ -39,7 +44,12 @@ module Asciidoctor
39
44
  }.freeze
40
45
 
41
46
  # Template data to be processed by each document
42
- TData = Struct.new("TData", :chapnum, :chaptitle)
47
+ TData = Struct.new("TData",
48
+ :chapprefix,
49
+ :chaptitle,
50
+ :chapheading,
51
+ :chapsubheading,
52
+ :index)
43
53
 
44
54
  # opts:
45
55
  # - title
@@ -96,6 +106,8 @@ module Asciidoctor
96
106
 
97
107
  private
98
108
 
109
+ include Pagination
110
+
99
111
  def search_page(se_id)
100
112
  content = <<~HTML
101
113
  <script async src="https://cse.google.com/cse.js?cx=#{se_id}"></script>
@@ -108,7 +120,6 @@ module Asciidoctor
108
120
  short_title: @short_title,
109
121
  author: @author,
110
122
  date: @date,
111
- chapnum: "",
112
123
  chaptitle: "Search",
113
124
  langs: []
114
125
  )
@@ -128,50 +139,59 @@ module Asciidoctor
128
139
  end
129
140
 
130
141
  def chapter(filename, idx)
131
- numeral = idx.to_s
132
- doc = parse_file filename, @chapname, numeral
133
- chaptitle = doctitle doc
134
- chapref = idx.zero? ? chaptitle : chapref_default(@chapname, numeral)
135
- chapnum = idx.zero? ? "" : numeral
136
- process_doc key(filename), doc, chapnum:, chaptitle:, chapref:
142
+ key = key filename
143
+ index = @templates.dig(key, :index) || idx
144
+ chapnum = index.to_s
145
+ doc = parse_file filename, @chapname, chapnum
146
+ chapsubheading = doctitle doc
147
+ chapref = index.zero? ? chapsubheading : chapref_default(@chapname, chapnum)
148
+ tdata = TData.new(
149
+ chapprefix: index.zero? ? "" : chapnum,
150
+ chaptitle: chapsubheading,
151
+ chapheading: (chapref unless index.zero?),
152
+ chapsubheading:,
153
+ index:
154
+ )
155
+ process_doc key, doc, tdata, chapref
137
156
  end
138
157
 
139
158
  def appendix(filename, idx, num_appendices)
159
+ key = key filename
160
+ index = @templates.dig(key, :index) || idx
140
161
  chapname = "Appendix"
141
- numeral = ("a".."z").to_a[idx].upcase
142
- doc = parse_file filename, chapname, numeral
143
- chapref = num_appendices == 1 ? chapname : chapref_default(chapname, numeral)
144
- chapnum = ""
145
- chaptitle = Template.appendix_title chapname, numeral, doctitle(doc), num_appendices
146
- process_doc key(filename), doc, chapnum:, chaptitle:, chapref:
162
+ chapnum = ("a".."z").to_a[index].upcase
163
+ doc = parse_file filename, chapname, chapnum
164
+ chapsubheading = doctitle doc
165
+ chapref = num_appendices == 1 ? chapname : chapref_default(chapname, chapnum)
166
+ tdata = TData.new(
167
+ chapprefix: "",
168
+ chaptitle: Template.appendix_title(chapname, chapnum, chapsubheading, num_appendices),
169
+ chapheading: chapref,
170
+ chapsubheading:,
171
+ index:
172
+ )
173
+ process_doc key, doc, tdata, chapref
147
174
  end
148
175
 
149
176
  def key(filename)
150
177
  Pathname(filename).basename.sub_ext("").to_s
151
178
  end
152
179
 
153
- # opts:
154
- # - chapnum
155
- # - chaptitle
156
- # - chapref
157
- def process_doc(key, doc, opts)
180
+ def process_doc(key, doc, tdata, chapref)
158
181
  val = doc.catalog[:refs].transform_values(&method(:reftext)).compact
159
- val["chapref"] = opts[:chapref]
182
+ val["chapref"] = chapref
160
183
  @refs[key] = val
161
- @templates[key] = TData.new(
162
- chapnum: opts[:chapnum],
163
- chaptitle: opts[:chaptitle]
164
- )
184
+ @templates[key] = tdata
165
185
  doc
166
186
  end
167
187
 
168
- def parse_file(filename, chapname, numeral)
169
- attributes = { "chapnum" => numeral, "chapname" => chapname }.merge DOCATTRS
188
+ def parse_file(filename, chapname, chapnum)
189
+ attributes = { "chapnum" => chapnum, "chapname" => chapname }.merge DOCATTRS
170
190
  Asciidoctor.load_file filename, safe: :unsafe, attributes:
171
191
  end
172
192
 
173
- def chapref_default(chapname, numeral)
174
- "#{ERB::Escape.html_escape chapname} #{numeral}"
193
+ def chapref_default(chapname, chapnum)
194
+ "#{ERB::Escape.html_escape chapname} #{chapnum}"
175
195
  end
176
196
 
177
197
  def reftext(node)
@@ -200,7 +220,7 @@ module Asciidoctor
200
220
  items = @templates.map do |k, td|
201
221
  active = (k == active_key)
202
222
  subnav = active && doc ? outline(doc) : ""
203
- navtext = Template.nav_text td.chapnum, td.chaptitle
223
+ navtext = Template.nav_text td.chapprefix, td.chaptitle
204
224
  Template.nav_item "#{k}.html", navtext, subnav, active:
205
225
  end
206
226
  return items unless @se_id
@@ -215,7 +235,7 @@ module Asciidoctor
215
235
  def build_template(key, doc)
216
236
  tdata = @templates[key]
217
237
  nav_items = nav_items key, doc
218
- content = ERB.new(doc.convert).result(binding)
238
+ content = "#{ERB.new(doc.convert).result(binding)}\n#{pagination key}"
219
239
  Template.html(
220
240
  content,
221
241
  nav_items,
@@ -224,8 +244,9 @@ module Asciidoctor
224
244
  author: @author,
225
245
  date: @date,
226
246
  description: doc.attr("description"),
227
- chapnum: tdata.chapnum,
228
247
  chaptitle: tdata.chaptitle,
248
+ chapheading: tdata.chapheading,
249
+ chapsubheading: tdata.chapsubheading,
229
250
  langs: langs(doc)
230
251
  )
231
252
  end
@@ -37,7 +37,8 @@ module Asciidoctor
37
37
  begin
38
38
  config = Psych.safe_load_file config_file
39
39
  rescue StandardError
40
- puts "Error opening configuration file #{config_file}"
40
+ puts "Error opening configuration file\n #{config_file}"
41
+ puts
41
42
  exit 1
42
43
  end
43
44
  config_dir = Pathname(config_file).dirname
@@ -53,22 +54,32 @@ module Asciidoctor
53
54
  config
54
55
  end
55
56
 
56
- def self.setup_outdir(outdir)
57
- assets_dir = "#{outdir}/#{ASSETS_PATH}"
58
- FileUtils.mkdir_p assets_dir unless File.directory?(assets_dir)
57
+ def self.setup_outdir(srcdir, outdir)
58
+ assets_out = "#{outdir}/#{ASSETS_PATH}"
59
+ FileUtils.mkdir_p assets_out unless File.directory?(assets_out)
60
+ %W[#{IMG_PATH} #{CSS_PATH} #{FAVICON_PATH}].each do |p|
61
+ dir = "#{srcdir}/#{p}"
62
+ next unless Dir.exist?(dir)
63
+
64
+ puts "Copying\n #{dir}\nto\n #{assets_out}"
65
+ puts
66
+ FileUtils.cp_r dir, assets_out
67
+ end
59
68
  rootdir = File.absolute_path "#{__dir__}/../../.."
60
69
  %W[#{CSS_PATH} #{FAVICON_PATH}].each do |p|
61
70
  dir = "#{outdir}/#{p}"
62
71
  next if Dir.exist?(dir)
63
72
 
64
- puts "Generating #{dir}"
65
- FileUtils.cp_r "#{rootdir}/#{p}", assets_dir
73
+ puts "Putting default '#{p}' files in\n #{dir}"
74
+ puts
75
+ FileUtils.cp_r "#{rootdir}/#{p}", assets_out
66
76
  end
67
77
  end
68
78
 
69
79
  def self.generate_webmanifest(outdir, name, short_name)
70
80
  filename = "#{outdir}/#{FAVICON_PATH}/site.webmanifest"
71
- puts "Generating #{filename}"
81
+ puts "Generating\n #{filename}"
82
+ puts
72
83
  File.write filename, Webmanifest.generate(name, short_name)
73
84
  end
74
85
 
@@ -86,25 +97,29 @@ module Asciidoctor
86
97
  opts ||= parse_opts
87
98
  config = read_config opts[:"config-file"]
88
99
  outdir = config["outdir"]
100
+ srcdir = config["srcdir"]
89
101
  book_opts = generate_bookopts config
90
- setup_outdir outdir
102
+ setup_outdir srcdir, outdir
91
103
  generate_webmanifest outdir, book_opts[:title], book_opts[:short_title]
92
104
  book = Book.new book_opts
93
- puts "Writing book to #{outdir}"
94
- book.write config["chapters"], config["appendices"], config["outdir"], sitemap: true
105
+ puts "Writing book to\n #{outdir}"
106
+ puts
107
+ book.write config["chapters"], config["appendices"], outdir, sitemap: true
95
108
  return unless opts[:watch]
96
109
 
97
- Filewatcher.new("#{config["srcdir"]}/*.adoc").watch do |changes|
110
+ Filewatcher.new("#{srcdir}/*.adoc").watch do |changes|
98
111
  chapters = []
99
112
  appendices = []
100
113
  changes.each_key do |filename|
101
- puts "Detected change in #{filename}"
114
+ puts "Detected change in\n #{filename}"
115
+ puts
102
116
  chapters.append(filename) if config["chapters"].include?(filename)
103
117
  appendices.append(filename) if config["appendices"].include?(filename)
104
118
  end
105
119
  puts "Regenerating book:"
106
- puts " Chapters: #{chapters.map { |c| Pathname(c).basename }.join ", "}" unless chapters.empty?
107
- puts " Appendices: #{appendices.map { |a| Pathname(a).basename }.join ", "}" unless appendices.empty?
120
+ puts " Chapters: #{chapters.map { |c| Pathname(c).basename }.join ", "}" unless chapters.empty?
121
+ puts " Appendices: #{appendices.map { |a| Pathname(a).basename }.join ", "}" unless appendices.empty?
122
+ puts
108
123
  book.write chapters, appendices, config["outdir"]
109
124
  end
110
125
  end
@@ -69,7 +69,7 @@ module Asciidoctor
69
69
  end
70
70
  icon = %(<div class="icon"><i class="bi bi-#{icon_class}"></i></div>)
71
71
  content = node.blocks? ? node.content : "<p>#{node.content}</p>"
72
- content = %(#{icon}\n#{Utils.display_title node, needs_prefix: false}#{content})
72
+ content = %(#{icon}\n#{Utils.display_title node}#{content})
73
73
  Utils.wrap_id_classes content, node.id, "admonition admonition-#{name}"
74
74
  end
75
75
 
@@ -84,7 +84,7 @@ module Asciidoctor
84
84
  open, close = BLOCK_MATH_DELIMITERS[node.style.to_sym]
85
85
  equation = node.content || ""
86
86
  equation = "#{open}#{equation}#{close}" unless (equation.start_with? open) && (equation.end_with? close)
87
- classes = ["stem"]
87
+ classes = ["stem", node.role].compact
88
88
  if node.option? "numbered"
89
89
  equation = %(<div class="equation">\n#{equation}\n</div> <!-- .equation -->)
90
90
  equation = %(#{equation}\n<div class="equation-number">#{node.reftext}</div>)
@@ -126,8 +126,7 @@ module Asciidoctor
126
126
  pre_open = %(<pre#{%( class="nowrap") if nowrap}>)
127
127
  pre_close = "</pre>"
128
128
  end
129
- needs_prefix = node.option? "numbered"
130
- title = Utils.display_title(node, needs_prefix:)
129
+ title = Utils.display_title(node)
131
130
  content = title + pre_open + node.content + pre_close
132
131
  Utils.wrap_node content, node
133
132
  end
@@ -135,7 +134,7 @@ module Asciidoctor
135
134
  def convert_literal(node)
136
135
  nowrap = !(node.document.attr? "prewrap") || (node.option? "nowrap")
137
136
  pre = %(<pre#{%( class="nowrap") if nowrap}>#{node.content}</pre>)
138
- title = Utils.display_title(node, needs_prefix: false)
137
+ title = Utils.display_title(node)
139
138
  Utils.wrap_node "#{title}#{pre}", node
140
139
  end
141
140
 
@@ -144,14 +143,14 @@ module Asciidoctor
144
143
  title = if collapsible
145
144
  %(<summary>#{node.title || "Details"}</summary>\n)
146
145
  else
147
- Utils.display_title(node, needs_prefix: false)
146
+ Utils.display_title(node)
148
147
  end
149
148
  tag_name = collapsible ? :details : :div
150
149
  Utils.wrap_node(title + node.content, node, tag_name)
151
150
  end
152
151
 
153
152
  def convert_example(node)
154
- Utils.wrap_node_with_title node.content, node, needs_prefix: true
153
+ Utils.wrap_node_with_title node.content, node
155
154
  end
156
155
 
157
156
  def convert_image(node)
@@ -161,6 +160,8 @@ module Asciidoctor
161
160
 
162
161
  def convert_inline_image(node)
163
162
  target = node.target
163
+ return read_svg_contents(node, target) if node.option?("inline")
164
+
164
165
  mark = node.parent.attr "mark"
165
166
  title_attr = node.attr? "title"
166
167
  if mark # The image is part of a figlist
@@ -179,7 +180,6 @@ module Asciidoctor
179
180
  end
180
181
 
181
182
  def convert_colist(node)
182
- node.style = "arabic-circled"
183
183
  List.convert node
184
184
  end
185
185
 
@@ -206,14 +206,25 @@ module Asciidoctor
206
206
  end
207
207
 
208
208
  def convert_inline_anchor(node)
209
- if node.type == :xref && !node.text
209
+ node_text = node.text
210
+ if node.type == :xref
210
211
  target = node.document.catalog[:refs][node.attr("refid")]
211
- if target&.inline?
212
- text = target.text
213
- return %(<a href="#{node.target}">#{text}</a>) if text&.match?(/\A<i class="bi/)
212
+ if target&.inline? && target.parent&.parent&.style == "bibliography"
213
+ reftext = target.reftext
214
+ if node_text
215
+ /\A\[(?<numeral>\d+)\]\z/ =~ reftext
216
+ reftext = if numeral
217
+ "[#{numeral}, #{node_text}]"
218
+ else
219
+ "#{reftext}, #{node_text}"
220
+ end
221
+ end
222
+ return Utils.popover_button(reftext, target.id, "bibref")
223
+ end
214
224
 
215
- list_style = target.parent&.parent&.style
216
- return Utils.popover_button(target.reftext, target.id, "bibref") if list_style == "bibliography"
225
+ if !node_text && (text = target&.inline? ? target&.text : target&.attr("reftext"))
226
+ subs = %i[specialcharacters quotes replacements macros]
227
+ return %(<a href="#{node.target}">#{node.apply_subs text, subs}</a>)
217
228
  end
218
229
  end
219
230
  super
@@ -224,6 +235,8 @@ module Asciidoctor
224
235
  classes << "table-striped" if node.option? "striped"
225
236
  classes << "table-bordered" if node.option? "bordered"
226
237
  classes << "table-sm" if node.option? "compact"
238
+ classes << "table-v#{node.attr "valign"}" if node.attr?("valign")
239
+ classes << "table-h#{node.attr "halign"}" if node.attr?("halign")
227
240
  width_attribute = ""
228
241
  if (autowidth = node.option? "autowidth") && !(node.attr? "width")
229
242
  classes << "table-fit"
@@ -232,7 +245,7 @@ module Asciidoctor
232
245
  end
233
246
  result = [%(<table#{Utils.id_class_attr_str node.id, classes.join(" ")}#{width_attribute}>)]
234
247
  result << %(<caption class="table-title">#{Utils.display_title_prefix node}#{node.title}</caption>)
235
- if node.attr("rowcount").positive?
248
+ if node.attr("rowcount").positive? && node.attr?("cols")
236
249
  result << "<colgroup>"
237
250
  if autowidth
238
251
  result += (Array.new node.columns.size, %(<col>))
@@ -6,6 +6,8 @@ module Asciidoctor
6
6
  # Mixed into the Converter class.
7
7
  module Figure
8
8
  def display_image(node, target, title_attr: false)
9
+ return read_svg_contents(node, target) if node.option?("inline")
10
+
9
11
  attrs = image_attrs(node, title_attr:)
10
12
  %(<img src="#{node.image_uri target}" #{attrs}#{@void_element_slash}>)
11
13
  end
@@ -46,53 +46,60 @@ module Asciidoctor
46
46
  }.freeze
47
47
 
48
48
  PLUGIN = <<~JS
49
- function toggleCopyIcon(copyIcon) {
50
- copyIcon.classList.toggle("bi-clipboard");
51
- copyIcon.classList.toggle("bi-clipboard-check");
52
- }
53
- hljs.addPlugin({
54
- "after:highlightElement": function({ el, result, text }) {
55
- const wrapper = el.parentElement; // pre element
56
- if(wrapper == null) { return; }
49
+ (function() {
50
+ function canHover() {
51
+ return matchMedia('(hover: hover)').matches &&
52
+ matchMedia('(pointer: fine)').matches;
53
+ }
54
+ function toggleCopyIcon(copyIcon) {
55
+ copyIcon.classList.toggle('bi-clipboard');
56
+ copyIcon.classList.toggle('bi-clipboard-check');
57
+ }
58
+ hljs.addPlugin({
59
+ 'after:highlightElement': function({ el, result, text }) {
60
+ let cbText = text
61
+ const wrapper = el.parentElement; // pre element
62
+ if(wrapper == null) { return; }
57
63
 
58
- const overlay = document.createElement("div");
59
- overlay.classList.add("copy-button");
60
- overlay.textContent = result.language.toUpperCase() + ' ';
64
+ const overlay = document.createElement('div');
65
+ overlay.classList.add('copy-button');
66
+ overlay.textContent = result.language.toUpperCase() + ' ';
61
67
 
62
- const copyButton = document.createElement("button");
63
- copyButton.classList.add("btn");
64
- copyButton.setAttribute("type", "button");
65
- copyButton.setAttribute("data-bs-toggle", "tooltip");
66
- copyButton.setAttribute("data-bs-title", "Copy to clipboard");
67
- if(!touch) {bootstrap.Tooltip.getOrCreateInstance(copyButton);}
68
+ const copyButton = document.createElement('button');
69
+ copyButton.classList.add('btn');
70
+ copyButton.setAttribute('type', 'button');
71
+ copyButton.setAttribute('data-bs-toggle', 'tooltip');
72
+ copyButton.setAttribute('data-bs-title', 'Copy to clipboard');
73
+ if(canHover()) bootstrap.Tooltip.getOrCreateInstance(copyButton);
68
74
 
69
- const copyIcon = document.createElement("i");
70
- copyIcon.classList.add("bi", "bi-clipboard");
75
+ const copyIcon = document.createElement('i');
76
+ copyIcon.classList.add('bi', 'bi-clipboard');
71
77
 
72
- copyButton.append(copyIcon);
73
- overlay.append(copyButton);
78
+ copyButton.append(copyIcon);
79
+ overlay.append(copyButton);
74
80
 
75
- copyButton.onclick = function() {
76
- navigator.clipboard.writeText(text);
77
- if(!copyIcon.classList.contains("bi-clipboard-check")) {
78
- toggleCopyIcon(copyIcon);
79
- setTimeout(() => { toggleCopyIcon(copyIcon); }, 1500);
80
- }
81
- };
81
+ copyButton.addEventListener('click', function() {
82
+ navigator.clipboard.writeText(cbText);
83
+ if(!copyIcon.classList.contains('bi-clipboard-check')) {
84
+ toggleCopyIcon(copyIcon);
85
+ setTimeout(() => { toggleCopyIcon(copyIcon); }, 1500);
86
+ }
87
+ });
82
88
 
83
- // Append the copy button to the wrapper
84
- wrapper.appendChild(overlay);
89
+ // Append the copy button to the wrapper
90
+ wrapper.appendChild(overlay);
85
91
 
86
- // Find and replace inline callouts
87
- const rgx = /[\u2460-\u2468]/gu;
88
- if(text.match(rgx)) {
89
- text = text.replaceAll(rgx, "");
90
- el.innerHTML = el.innerHTML.replaceAll(rgx, (match) => {
91
- return '<i class="hljs-comment bi bi-' + (match.charCodeAt() - 9311) + '-circle"></i>';
92
- });
92
+ // Find and replace inline callouts
93
+ const rgx = /[\u2460-\u2468]/gu;
94
+ if(text.match(rgx)) {
95
+ cbText = text.replaceAll(rgx, '');
96
+ el.innerHTML = el.innerHTML.replaceAll(rgx, (match) => {
97
+ return '<i class="hljs-comment bi bi-' + (match.charCodeAt() - 9311) + '-circle"></i>';
98
+ });
99
+ }
93
100
  }
94
- }
95
- });
101
+ });
102
+ })();
96
103
  JS
97
104
  end
98
105
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Asciidoctor
4
4
  module Html
5
- # Helper functions for the list conversion.
5
+ # Helper functions for the list conversion
6
6
  module List
7
7
  def self.convert(node, tag_name = :ol)
8
8
  depth = node.attr "list-depth"
@@ -11,8 +11,7 @@ module Asciidoctor
11
11
  classes = [
12
12
  "list",
13
13
  "list-#{node.context}",
14
- "level-#{level}",
15
- flat ? "pseudocode" : node.style,
14
+ ("level-#{level} pseudocode" if flat),
16
15
  node.role
17
16
  ].compact
18
17
  classes << "checklist" if node.option?("checklist")
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Asciidoctor
4
+ module Html
5
+ # Mixin to add pagination support to Book class
6
+ module Pagination
7
+ # Pagination item
8
+ PagItem = Struct.new("PagItem", :url, :title)
9
+
10
+ def display_paginator(prv, nxt)
11
+ <<~HTML
12
+ <div class="paginator-wrapper">
13
+ <div class="d-inline-block">
14
+ <div class="paginator">
15
+ #{%(<a href="#{prv.url}">&laquo; #{prv.title}</a>) if prv}
16
+ #{%(<span class="blank">&nbsp;</span>) unless prv && nxt}
17
+ #{%(<a href="#{nxt.url}">#{nxt.title} &raquo;</a>) if nxt}
18
+ </div>
19
+ </div>
20
+ </div>
21
+ HTML
22
+ end
23
+
24
+ def prv_nxt(keys, idx)
25
+ pagitems = []
26
+ [idx - 1, idx + 1].each do |i|
27
+ if i.between?(0, keys.size - 1)
28
+ key = keys[i]
29
+ ref = @refs[key]
30
+ pagitems << PagItem.new(
31
+ url: "#{key}.html",
32
+ title: ref["chapref"]
33
+ )
34
+ else
35
+ pagitems << nil
36
+ end
37
+ end
38
+ display_paginator(*pagitems)
39
+ end
40
+
41
+ def pagination(key = -1)
42
+ keys = @refs.keys
43
+ idx = keys.find_index key
44
+ return "" unless idx
45
+
46
+ prv_nxt keys, idx
47
+ end
48
+ end
49
+ end
50
+ end
@@ -5,45 +5,42 @@ module Asciidoctor
5
5
  # Configure the popovers for footnotes and citations.
6
6
  module Popovers
7
7
  POPOVERS = <<~JS
8
- function initPopovers() {
9
- document.querySelectorAll(".btn-po[data-contentid]").forEach(el => {
10
- const id = el.dataset.contentid;
11
- let content = document.getElementById(id);
12
- if(content) {
13
- if(content.tagName == "A") {
14
- // This is an anchor of a bibitem
15
- const listItem = content.parentElement.cloneNode(true)
16
- listItem.removeChild(listItem.firstChild)
17
- content = listItem
8
+ (function() {
9
+ const popovers = []
10
+ function initPopovers() {
11
+ document.querySelectorAll('.btn-po[data-contentid]').forEach(el => {
12
+ const id = el.dataset.contentid;
13
+ let content = document.getElementById(id);
14
+ if(content) {
15
+ if(content.tagName == 'A') {
16
+ // This is an anchor of a bibitem
17
+ const listItem = content.parentElement.cloneNode(true)
18
+ listItem.removeChild(listItem.firstChild)
19
+ content = listItem
20
+ }
21
+ popovers.push(new bootstrap.Popover(el, {
22
+ content: content,
23
+ html: true,
24
+ sanitize: false
25
+ }));
18
26
  }
19
- new bootstrap.Popover(el, {
20
- trigger: "focus",
21
- content: content,
22
- html: true,
23
- sanitize: false
24
- });
25
- }
26
- });
27
- }
28
- MathJax = {
29
- startup: {
30
- pageReady: function() {
31
- return MathJax.startup.defaultPageReady().then(initPopovers);
32
- }
27
+ });
33
28
  }
34
- };
35
- JS
36
-
37
- TOOLTIPS = <<~JS
38
- // Only enable tooltips on images if not a touch screen device
39
- if(!touch) {
40
- document.querySelectorAll('img[data-bs-toggle="tooltip"]').forEach(el => {
41
- bootstrap.Tooltip.getOrCreateInstance(el);
29
+ addEventListener('click', e => {
30
+ const match = e.target.closest('.btn-po[aria-describedby],.popover');
31
+ if(!match) {
32
+ popovers.forEach(po => po.hide());
33
+ }
34
+ })
35
+ MathJax.startup.promise.then(initPopovers);
36
+ addEventListener('load', function() {
37
+ // Enable tooltips on images
38
+ document.querySelectorAll('img[data-bs-toggle="tooltip"]').forEach(el => {
39
+ bootstrap.Tooltip.getOrCreateInstance(el);
40
+ });
42
41
  });
43
- }
42
+ })();
44
43
  JS
45
-
46
- INIT = "#{TOOLTIPS}\n#{POPOVERS}".freeze
47
44
  end
48
45
  end
49
46
  end