asciidoctor-html 0.1.5 → 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.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -3
- data/CHANGELOG.md +20 -0
- data/assets/css/styles.css +2 -2
- data/assets/css/styles.css.map +1 -1
- data/assets/favicon/android-chrome-192x192.png +0 -0
- data/assets/favicon/android-chrome-512x512.png +0 -0
- data/assets/favicon/apple-touch-icon.png +0 -0
- data/assets/favicon/favicon-16x16.png +0 -0
- data/assets/favicon/favicon-32x32.png +0 -0
- data/assets/favicon/favicon.ico +0 -0
- data/lib/asciidoctor/html/bi_inline_macro.rb +0 -1
- data/lib/asciidoctor/html/book.rb +63 -36
- data/lib/asciidoctor/html/cli.rb +30 -15
- data/lib/asciidoctor/html/converter.rb +65 -14
- data/lib/asciidoctor/html/figure.rb +4 -2
- data/lib/asciidoctor/html/highlightjs.rb +46 -39
- data/lib/asciidoctor/html/list.rb +2 -3
- data/lib/asciidoctor/html/pagination.rb +50 -0
- data/lib/asciidoctor/html/popovers.rb +32 -35
- data/lib/asciidoctor/html/ref_tree_processor.rb +30 -6
- data/lib/asciidoctor/html/sc_inline_macro.rb +21 -0
- data/lib/asciidoctor/html/scroll.rb +30 -0
- data/lib/asciidoctor/html/sidebar.rb +41 -0
- data/lib/asciidoctor/html/table.rb +40 -0
- data/lib/asciidoctor/html/template.rb +84 -51
- data/lib/asciidoctor/html/utils.rb +20 -15
- metadata +6 -1
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/assets/favicon/favicon.ico
CHANGED
Binary file
|
@@ -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",
|
47
|
+
TData = Struct.new("TData",
|
48
|
+
:chapprefix,
|
49
|
+
:chaptitle,
|
50
|
+
:chapheading,
|
51
|
+
:chapsubheading,
|
52
|
+
:index)
|
43
53
|
|
44
54
|
# opts:
|
45
55
|
# - title
|
@@ -55,6 +65,7 @@ module Asciidoctor
|
|
55
65
|
@author = ERB::Escape.html_escape opts[:author]
|
56
66
|
@date = opts.include?(:date) ? Date.parse(opts[:date]) : Date.today
|
57
67
|
@se_id = opts[:se_id]
|
68
|
+
@base_url = opts[:base_url]
|
58
69
|
@chapname = opts[:chapname]
|
59
70
|
@refs = {} # Hash(docname => Hash(id => reftext))
|
60
71
|
@templates = {} # Hash(docname => TData)
|
@@ -81,15 +92,22 @@ module Asciidoctor
|
|
81
92
|
# - chapters: array of filenames
|
82
93
|
# - appendices: array of filenames
|
83
94
|
# - outdir: directory to write the converted html files to
|
84
|
-
def write(chapters, appendices, outdir)
|
95
|
+
def write(chapters, appendices, outdir, sitemap: false)
|
96
|
+
needs_sitemap = sitemap && @base_url
|
97
|
+
entries = [] # for sitemap
|
85
98
|
read(chapters, appendices).each do |name, html|
|
86
|
-
|
99
|
+
filename = "#{name}.html"
|
100
|
+
File.write("#{outdir}/#{filename}", html)
|
101
|
+
entries << Template.sitemap_entry("#{@base_url}#{filename}") if needs_sitemap
|
87
102
|
end
|
88
103
|
File.write("#{outdir}/#{SEARCH_PAGE}", search_page(@se_id)) if @se_id
|
104
|
+
File.write("#{outdir}/sitemap.xml", Template.sitemap(entries)) if needs_sitemap
|
89
105
|
end
|
90
106
|
|
91
107
|
private
|
92
108
|
|
109
|
+
include Pagination
|
110
|
+
|
93
111
|
def search_page(se_id)
|
94
112
|
content = <<~HTML
|
95
113
|
<script async src="https://cse.google.com/cse.js?cx=#{se_id}"></script>
|
@@ -102,7 +120,6 @@ module Asciidoctor
|
|
102
120
|
short_title: @short_title,
|
103
121
|
author: @author,
|
104
122
|
date: @date,
|
105
|
-
chapnum: "",
|
106
123
|
chaptitle: "Search",
|
107
124
|
langs: []
|
108
125
|
)
|
@@ -122,50 +139,59 @@ module Asciidoctor
|
|
122
139
|
end
|
123
140
|
|
124
141
|
def chapter(filename, idx)
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
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
|
131
156
|
end
|
132
157
|
|
133
158
|
def appendix(filename, idx, num_appendices)
|
159
|
+
key = key filename
|
160
|
+
index = @templates.dig(key, :index) || idx
|
134
161
|
chapname = "Appendix"
|
135
|
-
|
136
|
-
doc = parse_file filename, chapname,
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
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
|
141
174
|
end
|
142
175
|
|
143
176
|
def key(filename)
|
144
177
|
Pathname(filename).basename.sub_ext("").to_s
|
145
178
|
end
|
146
179
|
|
147
|
-
|
148
|
-
# - chapnum
|
149
|
-
# - chaptitle
|
150
|
-
# - chapref
|
151
|
-
def process_doc(key, doc, opts)
|
180
|
+
def process_doc(key, doc, tdata, chapref)
|
152
181
|
val = doc.catalog[:refs].transform_values(&method(:reftext)).compact
|
153
|
-
val["chapref"] =
|
182
|
+
val["chapref"] = chapref
|
154
183
|
@refs[key] = val
|
155
|
-
@templates[key] =
|
156
|
-
chapnum: opts[:chapnum],
|
157
|
-
chaptitle: opts[:chaptitle]
|
158
|
-
)
|
184
|
+
@templates[key] = tdata
|
159
185
|
doc
|
160
186
|
end
|
161
187
|
|
162
|
-
def parse_file(filename, chapname,
|
163
|
-
attributes = { "chapnum" =>
|
188
|
+
def parse_file(filename, chapname, chapnum)
|
189
|
+
attributes = { "chapnum" => chapnum, "chapname" => chapname }.merge DOCATTRS
|
164
190
|
Asciidoctor.load_file filename, safe: :unsafe, attributes:
|
165
191
|
end
|
166
192
|
|
167
|
-
def chapref_default(chapname,
|
168
|
-
"#{ERB::Escape.html_escape chapname} #{
|
193
|
+
def chapref_default(chapname, chapnum)
|
194
|
+
"#{ERB::Escape.html_escape chapname} #{chapnum}"
|
169
195
|
end
|
170
196
|
|
171
197
|
def reftext(node)
|
@@ -194,7 +220,7 @@ module Asciidoctor
|
|
194
220
|
items = @templates.map do |k, td|
|
195
221
|
active = (k == active_key)
|
196
222
|
subnav = active && doc ? outline(doc) : ""
|
197
|
-
navtext = Template.nav_text td.
|
223
|
+
navtext = Template.nav_text td.chapprefix, td.chaptitle
|
198
224
|
Template.nav_item "#{k}.html", navtext, subnav, active:
|
199
225
|
end
|
200
226
|
return items unless @se_id
|
@@ -209,7 +235,7 @@ module Asciidoctor
|
|
209
235
|
def build_template(key, doc)
|
210
236
|
tdata = @templates[key]
|
211
237
|
nav_items = nav_items key, doc
|
212
|
-
content = ERB.new(doc.convert).result(binding)
|
238
|
+
content = "#{ERB.new(doc.convert).result(binding)}\n#{pagination key}"
|
213
239
|
Template.html(
|
214
240
|
content,
|
215
241
|
nav_items,
|
@@ -217,10 +243,11 @@ module Asciidoctor
|
|
217
243
|
short_title: @short_title,
|
218
244
|
author: @author,
|
219
245
|
date: @date,
|
220
|
-
|
246
|
+
description: doc.attr("description"),
|
221
247
|
chaptitle: tdata.chaptitle,
|
222
|
-
|
223
|
-
|
248
|
+
chapheading: tdata.chapheading,
|
249
|
+
chapsubheading: tdata.chapsubheading,
|
250
|
+
langs: langs(doc)
|
224
251
|
)
|
225
252
|
end
|
226
253
|
end
|
data/lib/asciidoctor/html/cli.rb
CHANGED
@@ -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
|
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,28 +54,38 @@ module Asciidoctor
|
|
53
54
|
config
|
54
55
|
end
|
55
56
|
|
56
|
-
def self.setup_outdir(outdir)
|
57
|
-
|
58
|
-
FileUtils.mkdir_p
|
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 "
|
65
|
-
|
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
|
81
|
+
puts "Generating\n #{filename}"
|
82
|
+
puts
|
72
83
|
File.write filename, Webmanifest.generate(name, short_name)
|
73
84
|
end
|
74
85
|
|
75
86
|
def self.generate_bookopts(config)
|
76
87
|
book_opts = {}
|
77
|
-
%i[title short_title author date se_id chapname].each do |opt|
|
88
|
+
%i[title short_title author date se_id base_url chapname].each do |opt|
|
78
89
|
key = opt.to_s
|
79
90
|
book_opts[opt] = config[key] if config.include?(key)
|
80
91
|
end
|
@@ -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
|
94
|
-
|
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("#{
|
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
|
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 "
|
107
|
-
puts "
|
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
|
@@ -4,6 +4,7 @@ require "asciidoctor"
|
|
4
4
|
require_relative "list"
|
5
5
|
require_relative "utils"
|
6
6
|
require_relative "figure"
|
7
|
+
require_relative "table"
|
7
8
|
|
8
9
|
module Asciidoctor
|
9
10
|
module Html
|
@@ -33,7 +34,8 @@ module Asciidoctor
|
|
33
34
|
document = node.document
|
34
35
|
level = node.level
|
35
36
|
show_sectnum = node.numbered && level <= (document.attr("sectnumlevels") || 1).to_i
|
36
|
-
|
37
|
+
tag_level = [level == 1 ? level + 1 : level + 2, 6].min
|
38
|
+
tag_name = %(h#{tag_level})
|
37
39
|
sectnum = show_sectnum ? %(<span class="title-mark">#{node.sectnum ""}</span>) : ""
|
38
40
|
content = %(<#{tag_name}>#{sectnum}#{node.title}</#{tag_name}>\n#{node.content})
|
39
41
|
Utils.wrap_node content, node, :section
|
@@ -66,7 +68,8 @@ module Asciidoctor
|
|
66
68
|
else "exclamation-lg"
|
67
69
|
end
|
68
70
|
icon = %(<div class="icon"><i class="bi bi-#{icon_class}"></i></div>)
|
69
|
-
content =
|
71
|
+
content = node.blocks? ? node.content : "<p>#{node.content}</p>"
|
72
|
+
content = %(#{icon}\n#{Utils.display_title node}#{content})
|
70
73
|
Utils.wrap_id_classes content, node.id, "admonition admonition-#{name}"
|
71
74
|
end
|
72
75
|
|
@@ -81,7 +84,7 @@ module Asciidoctor
|
|
81
84
|
open, close = BLOCK_MATH_DELIMITERS[node.style.to_sym]
|
82
85
|
equation = node.content || ""
|
83
86
|
equation = "#{open}#{equation}#{close}" unless (equation.start_with? open) && (equation.end_with? close)
|
84
|
-
classes = ["stem"]
|
87
|
+
classes = ["stem", node.role].compact
|
85
88
|
if node.option? "numbered"
|
86
89
|
equation = %(<div class="equation">\n#{equation}\n</div> <!-- .equation -->)
|
87
90
|
equation = %(#{equation}\n<div class="equation-number">#{node.reftext}</div>)
|
@@ -123,25 +126,31 @@ module Asciidoctor
|
|
123
126
|
pre_open = %(<pre#{%( class="nowrap") if nowrap}>)
|
124
127
|
pre_close = "</pre>"
|
125
128
|
end
|
126
|
-
|
127
|
-
title = Utils.display_title(node, needs_prefix:)
|
129
|
+
title = Utils.display_title(node)
|
128
130
|
content = title + pre_open + node.content + pre_close
|
129
131
|
Utils.wrap_node content, node
|
130
132
|
end
|
131
133
|
|
134
|
+
def convert_literal(node)
|
135
|
+
nowrap = !(node.document.attr? "prewrap") || (node.option? "nowrap")
|
136
|
+
pre = %(<pre#{%( class="nowrap") if nowrap}>#{node.content}</pre>)
|
137
|
+
title = Utils.display_title(node)
|
138
|
+
Utils.wrap_node "#{title}#{pre}", node
|
139
|
+
end
|
140
|
+
|
132
141
|
def convert_open(node)
|
133
142
|
collapsible = node.option? "collapsible"
|
134
143
|
title = if collapsible
|
135
144
|
%(<summary>#{node.title || "Details"}</summary>\n)
|
136
145
|
else
|
137
|
-
Utils.display_title(node
|
146
|
+
Utils.display_title(node)
|
138
147
|
end
|
139
148
|
tag_name = collapsible ? :details : :div
|
140
149
|
Utils.wrap_node(title + node.content, node, tag_name)
|
141
150
|
end
|
142
151
|
|
143
152
|
def convert_example(node)
|
144
|
-
Utils.wrap_node_with_title node.content, node
|
153
|
+
Utils.wrap_node_with_title node.content, node
|
145
154
|
end
|
146
155
|
|
147
156
|
def convert_image(node)
|
@@ -151,6 +160,8 @@ module Asciidoctor
|
|
151
160
|
|
152
161
|
def convert_inline_image(node)
|
153
162
|
target = node.target
|
163
|
+
return read_svg_contents(node, target) if node.option?("inline")
|
164
|
+
|
154
165
|
mark = node.parent.attr "mark"
|
155
166
|
title_attr = node.attr? "title"
|
156
167
|
if mark # The image is part of a figlist
|
@@ -169,7 +180,6 @@ module Asciidoctor
|
|
169
180
|
end
|
170
181
|
|
171
182
|
def convert_colist(node)
|
172
|
-
node.style = "arabic-circled"
|
173
183
|
List.convert node
|
174
184
|
end
|
175
185
|
|
@@ -196,18 +206,59 @@ module Asciidoctor
|
|
196
206
|
end
|
197
207
|
|
198
208
|
def convert_inline_anchor(node)
|
199
|
-
|
209
|
+
node_text = node.text
|
210
|
+
if node.type == :xref
|
200
211
|
target = node.document.catalog[:refs][node.attr("refid")]
|
201
|
-
if target&.inline?
|
202
|
-
|
203
|
-
|
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
|
204
224
|
|
205
|
-
|
206
|
-
|
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>)
|
207
228
|
end
|
208
229
|
end
|
209
230
|
super
|
210
231
|
end
|
232
|
+
|
233
|
+
def convert_table(node)
|
234
|
+
classes = ["table", node.role].compact
|
235
|
+
classes << "table-striped" if node.option? "striped"
|
236
|
+
classes << "table-bordered" if node.option? "bordered"
|
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")
|
240
|
+
width_attribute = ""
|
241
|
+
if (autowidth = node.option? "autowidth") && !(node.attr? "width")
|
242
|
+
classes << "table-fit"
|
243
|
+
elsif (tablewidth = node.attr "width")
|
244
|
+
width_attribute = %( width="#{tablewidth}%")
|
245
|
+
end
|
246
|
+
result = [%(<table#{Utils.id_class_attr_str node.id, classes.join(" ")}#{width_attribute}>)]
|
247
|
+
result << %(<caption class="table-title">#{Utils.display_title_prefix node}#{node.title}</caption>)
|
248
|
+
if node.attr("rowcount").positive? && node.attr?("cols")
|
249
|
+
result << "<colgroup>"
|
250
|
+
if autowidth
|
251
|
+
result += (Array.new node.columns.size, %(<col>))
|
252
|
+
else
|
253
|
+
node.columns.each do |col|
|
254
|
+
result << (col.option?("autowidth") ? %(<col>) : %(<col style="width:#{col.attr "colpcwidth"}%;">))
|
255
|
+
end
|
256
|
+
end
|
257
|
+
result << "</colgroup>"
|
258
|
+
end
|
259
|
+
result << "#{Table.display_rows(node)}</table>"
|
260
|
+
Utils.wrap_id_classes result.join("\n"), nil, "table-responsive"
|
261
|
+
end
|
211
262
|
end
|
212
263
|
end
|
213
264
|
end
|
@@ -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
|
@@ -29,9 +31,9 @@ module Asciidoctor
|
|
29
31
|
|
30
32
|
def convert_figlist(node)
|
31
33
|
result = node.items.map do |item|
|
32
|
-
%(<li#{Utils.id_class_attr_str item.id}><figure>\n#{item.text}\n</figure></li>)
|
34
|
+
%(<li#{Utils.id_class_attr_str item.id, item.role}><figure>\n#{item.text}\n</figure></li>)
|
33
35
|
end
|
34
|
-
content = Utils.wrap_id_classes result.join("\n"), nil, "figlist
|
36
|
+
content = Utils.wrap_id_classes result.join("\n"), nil, "figlist", :ol
|
35
37
|
title = %(<div class="figlist-title">#{Utils.display_title_prefix(node)}#{node.title}</div>)
|
36
38
|
classes = ["figlist-wrapper", node.role].compact.join(" ")
|
37
39
|
Utils.wrap_id_classes %(#{content}#{title}), node.id, classes
|
@@ -46,53 +46,60 @@ module Asciidoctor
|
|
46
46
|
}.freeze
|
47
47
|
|
48
48
|
PLUGIN = <<~JS
|
49
|
-
function
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
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
|
-
|
59
|
-
|
60
|
-
|
64
|
+
const overlay = document.createElement('div');
|
65
|
+
overlay.classList.add('copy-button');
|
66
|
+
overlay.textContent = result.language.toUpperCase() + ' ';
|
61
67
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
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
|
-
|
70
|
-
|
75
|
+
const copyIcon = document.createElement('i');
|
76
|
+
copyIcon.classList.add('bi', 'bi-clipboard');
|
71
77
|
|
72
|
-
|
73
|
-
|
78
|
+
copyButton.append(copyIcon);
|
79
|
+
overlay.append(copyButton);
|
74
80
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
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
|
-
|
84
|
-
|
89
|
+
// Append the copy button to the wrapper
|
90
|
+
wrapper.appendChild(overlay);
|
85
91
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
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}">« #{prv.title}</a>) if prv}
|
16
|
+
#{%(<span class="blank"> </span>) unless prv && nxt}
|
17
|
+
#{%(<a href="#{nxt.url}">#{nxt.title} »</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
|