asciidoctor-html 0.1.2 → 0.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +6 -3
- data/README.md +29 -11
- data/Rakefile +15 -6
- data/assets/css/fonts/bootstrap-icons.woff +0 -0
- data/assets/css/fonts/bootstrap-icons.woff2 +0 -0
- data/assets/css/styles.css +5 -0
- data/assets/css/styles.css.map +1 -0
- data/exe/adoctohtml +6 -0
- data/lib/asciidoctor/html/bi_inline_macro.rb +25 -0
- data/lib/asciidoctor/html/book.rb +228 -0
- data/lib/asciidoctor/html/cli.rb +113 -0
- data/lib/asciidoctor/html/converter.rb +165 -24
- data/lib/asciidoctor/html/cref_inline_macro.rb +37 -0
- data/lib/asciidoctor/html/figure.rb +10 -10
- data/lib/asciidoctor/html/highlightjs.rb +99 -0
- data/lib/asciidoctor/html/list.rb +38 -0
- data/lib/asciidoctor/html/popovers.rb +49 -0
- data/lib/asciidoctor/html/ref_tree_processor.rb +134 -57
- data/lib/asciidoctor/html/template.rb +145 -0
- data/lib/asciidoctor/html/tree_walker.rb +3 -1
- data/lib/asciidoctor/html/utils.rb +6 -0
- data/lib/asciidoctor/html/webmanifest.rb +23 -0
- data/lib/asciidoctor/html.rb +13 -1
- data/lib/minitest/html_plugin.rb +18 -22
- metadata +52 -27
- data/docs/_config.yml +0 -5
- data/docs/_layouts/default.html +0 -25
- data/docs/_sass/_custom.scss +0 -35
- data/docs/_sass/_example.scss +0 -30
- data/docs/_sass/_figure.scss +0 -17
- data/docs/_sass/_olist.scss +0 -101
- data/docs/_sass/main.scss +0 -40
- data/docs/assets/css/fonts +0 -1
- data/docs/assets/css/styles.scss +0 -3
- data/docs/assets/img/cat1.jpg +0 -0
- data/docs/assets/img/cat2.jpg +0 -0
- data/docs/assets/img/cat3.jpg +0 -0
- data/docs/package-lock.json +0 -59
- data/docs/package.json +0 -6
- data/docs/site.webmanifest +0 -1
- data/lib/asciidoctor/html/olist.rb +0 -18
- data/lib/asciidoctor/html/version.rb +0 -7
- /data/{docs → assets/favicon}/android-chrome-192x192.png +0 -0
- /data/{docs → assets/favicon}/android-chrome-512x512.png +0 -0
- /data/{docs → assets/favicon}/apple-touch-icon.png +0 -0
- /data/{docs → assets/favicon}/favicon-16x16.png +0 -0
- /data/{docs → assets/favicon}/favicon-32x32.png +0 -0
- /data/{docs → assets/favicon}/favicon.ico +0 -0
@@ -1,30 +1,30 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "olist"
|
4
|
-
|
5
3
|
module Asciidoctor
|
6
4
|
module Html
|
7
5
|
# Helper functions for the image/figure conversion.
|
8
6
|
# Mixed into the Converter class.
|
9
7
|
module Figure
|
10
|
-
def display_image(node, target,
|
8
|
+
def display_image(node, target, title_attr: false)
|
9
|
+
attrs = image_attrs(node, title_attr:)
|
11
10
|
%(<img src="#{node.image_uri target}" #{attrs}#{@void_element_slash}>)
|
12
11
|
end
|
13
12
|
|
14
|
-
def image_attrs(node)
|
13
|
+
def image_attrs(node, title_attr: false)
|
15
14
|
width = node.attr?("width") ? %( width="#{node.attr "width"}") : ""
|
16
15
|
height = node.attr?("height") ? %( height="#{node.attr "height"}") : ""
|
16
|
+
title = encode_attribute_value node.attr("title") if node.attr?("title") && title_attr
|
17
|
+
title = title ? %( data-bs-toggle="tooltip" data-bs-title="#{title}") : ""
|
17
18
|
alt = encode_attribute_value node.alt
|
18
|
-
%(alt="#{alt}"#{width}#{height})
|
19
|
+
%(alt="#{alt}"#{width}#{height}#{title})
|
19
20
|
end
|
20
21
|
|
21
22
|
def display_figure(node)
|
22
23
|
target = node.attr "target"
|
23
24
|
title = node.title? ? node.title : ""
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
%(<figure>\n #{image}\n #{caption}\n</figure>)
|
25
|
+
image = display_image node, target
|
26
|
+
caption = %( <figcaption>#{Utils.display_title_prefix node}#{title}</figcaption>)
|
27
|
+
%(<figure>\n #{image}\n#{caption}\n</figure>)
|
28
28
|
end
|
29
29
|
|
30
30
|
def convert_figlist(node)
|
@@ -32,7 +32,7 @@ module Asciidoctor
|
|
32
32
|
%(<li#{Utils.id_class_attr_str item.id}><figure>\n#{item.text}\n</figure></li>)
|
33
33
|
end
|
34
34
|
content = Utils.wrap_id_classes result.join("\n"), nil, "figlist loweralpha", :ol
|
35
|
-
title = Utils.
|
35
|
+
title = %(<div class="figlist-title">#{Utils.display_title_prefix(node)}#{node.title}</div>)
|
36
36
|
classes = ["figlist-wrapper", node.role].compact.join(" ")
|
37
37
|
Utils.wrap_id_classes %(#{content}#{title}), node.id, classes
|
38
38
|
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Asciidoctor
|
4
|
+
module Html
|
5
|
+
# Constants for the highlightjs syntax highlighting library
|
6
|
+
module Highlightjs
|
7
|
+
CDN_PATH = "https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.11.1/build"
|
8
|
+
|
9
|
+
INCLUDED_LANGS = {
|
10
|
+
"bash" => true,
|
11
|
+
"c" => true,
|
12
|
+
"cpp" => true,
|
13
|
+
"csharp" => true,
|
14
|
+
"css" => true,
|
15
|
+
"diff" => true,
|
16
|
+
"go" => true,
|
17
|
+
"graphql" => true,
|
18
|
+
"ini" => true,
|
19
|
+
"java" => true,
|
20
|
+
"javascript" => true,
|
21
|
+
"json" => true,
|
22
|
+
"kotlin" => true,
|
23
|
+
"less" => true,
|
24
|
+
"lua" => true,
|
25
|
+
"makefile" => true,
|
26
|
+
"markdown" => true,
|
27
|
+
"objectivec" => true,
|
28
|
+
"perl" => true,
|
29
|
+
"php" => true,
|
30
|
+
"php-template" => true,
|
31
|
+
"plaintext" => true,
|
32
|
+
"python" => true,
|
33
|
+
"python-repl" => true,
|
34
|
+
"r" => true,
|
35
|
+
"ruby" => true,
|
36
|
+
"rust" => true,
|
37
|
+
"scss" => true,
|
38
|
+
"shell" => true,
|
39
|
+
"sql" => true,
|
40
|
+
"swift" => true,
|
41
|
+
"typescript" => true,
|
42
|
+
"vbnet" => true,
|
43
|
+
"wasm" => true,
|
44
|
+
"xml" => true,
|
45
|
+
"yaml" => true
|
46
|
+
}.freeze
|
47
|
+
|
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; }
|
57
|
+
|
58
|
+
const overlay = document.createElement("div");
|
59
|
+
overlay.classList.add("copy-button");
|
60
|
+
overlay.textContent = result.language.toUpperCase() + ' ';
|
61
|
+
|
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
|
+
|
69
|
+
const copyIcon = document.createElement("i");
|
70
|
+
copyIcon.classList.add("bi", "bi-clipboard");
|
71
|
+
|
72
|
+
copyButton.append(copyIcon);
|
73
|
+
overlay.append(copyButton);
|
74
|
+
|
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
|
+
};
|
82
|
+
|
83
|
+
// Append the copy button to the wrapper
|
84
|
+
wrapper.appendChild(overlay);
|
85
|
+
|
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="bi bi-' + (match.charCodeAt() - 9311) + '-circle"></i>';
|
92
|
+
});
|
93
|
+
}
|
94
|
+
}
|
95
|
+
});
|
96
|
+
JS
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Asciidoctor
|
4
|
+
module Html
|
5
|
+
# Helper functions for the list conversion.
|
6
|
+
module List
|
7
|
+
def self.convert(node, tag_name = :ol)
|
8
|
+
depth = node.attr "list-depth"
|
9
|
+
flat = node.attr? "flat-style"
|
10
|
+
level = depth + 1
|
11
|
+
classes = [
|
12
|
+
"list",
|
13
|
+
"list-#{node.context}",
|
14
|
+
"level-#{level}",
|
15
|
+
flat ? "pseudocode" : node.style,
|
16
|
+
node.role
|
17
|
+
].compact
|
18
|
+
classes << "checklist" if node.option?("checklist")
|
19
|
+
result = [%(<#{tag_name}#{Utils.dyn_id_class_attr_str node, classes.join(" ")}>)]
|
20
|
+
node.items.each do |item|
|
21
|
+
result << display_list_item(item)
|
22
|
+
end
|
23
|
+
result << %(</#{tag_name}> <!-- .level-#{level} -->\n)
|
24
|
+
Utils.wrap_id_classes_with_title result.join("\n"), node, node.id, "list-wrapper"
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.display_list_item(item)
|
28
|
+
result = []
|
29
|
+
result << %(<li#{Utils.id_class_attr_str item.id,
|
30
|
+
item.role}><div class="li-mark">#{item.attr "mark"}</div>)
|
31
|
+
result << %(<div class="li-content"><p>#{item.text}</p>)
|
32
|
+
result << "\n#{item.content}" if item.blocks?
|
33
|
+
result << %(</div></li>#{Utils.id_class_sel_comment item.id, item.role})
|
34
|
+
result.join "\n"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Asciidoctor
|
4
|
+
module Html
|
5
|
+
# Configure the popovers for footnotes and citations.
|
6
|
+
module Popovers
|
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
|
18
|
+
}
|
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
|
+
}
|
33
|
+
}
|
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);
|
42
|
+
});
|
43
|
+
}
|
44
|
+
JS
|
45
|
+
|
46
|
+
INIT = "#{TOOLTIPS}\n#{POPOVERS}".freeze
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -1,71 +1,99 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "asciidoctor"
|
3
4
|
require "roman-numerals"
|
4
5
|
require_relative "tree_walker"
|
6
|
+
require_relative "highlightjs"
|
5
7
|
|
6
8
|
module Asciidoctor
|
7
9
|
module Html
|
8
|
-
# Traverses the document tree and
|
9
|
-
# numbered nodes
|
10
|
+
# Traverses the document tree and:
|
11
|
+
# - attaches a correct reftext to numbered nodes;
|
12
|
+
# - populates the text (= reftext for inline nodes) of anchors at
|
13
|
+
# the beginning of a list item for an ordered list;
|
14
|
+
# - registers every encountered source code language not included
|
15
|
+
# in the default highlightjs build.
|
10
16
|
class RefTreeProcessor < Asciidoctor::Extensions::TreeProcessor
|
11
17
|
NUMBERED_CONTEXTS = {
|
12
18
|
example: "thm-number",
|
13
19
|
table: "tbl-number",
|
14
|
-
image: "fig-number"
|
20
|
+
image: "fig-number",
|
21
|
+
stem: "eqn-number",
|
22
|
+
listing: "ltg-number"
|
15
23
|
}.freeze
|
16
24
|
|
17
|
-
def number_within(document)
|
18
|
-
return :chapter if document.attr? "chapnum"
|
19
|
-
return :section if document.attr? "sectnums"
|
20
|
-
|
21
|
-
:document
|
22
|
-
end
|
23
|
-
|
24
25
|
def assign_numeral!(node, document, counter_name)
|
25
26
|
document.counters[counter_name] ||= 0
|
26
27
|
node.numeral = (document.counters[counter_name] += 1)
|
27
28
|
end
|
28
29
|
|
29
|
-
def relative_numeral(node, document
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
end
|
30
|
+
def relative_numeral(node, document)
|
31
|
+
return "" unless node.numeral
|
32
|
+
|
33
|
+
chapnum = document.attr "chapnum"
|
34
|
+
has_prefix = chapnum && !chapnum.empty? && chapnum != "0"
|
35
|
+
has_prefix ? "#{chapnum}.#{node.numeral}" : node.numeral.to_s
|
36
36
|
end
|
37
37
|
|
38
|
-
def process_numbered_block!(block, document
|
38
|
+
def process_numbered_block!(block, document)
|
39
39
|
context = block.context
|
40
|
-
|
41
|
-
|
42
|
-
|
40
|
+
style = block.style
|
41
|
+
context = :image if style == "figlist"
|
42
|
+
env = env context, style
|
43
|
+
block.set_attr("showcaption", true) unless context == :stem
|
43
44
|
assign_numeral! block, document, NUMBERED_CONTEXTS[context]
|
44
|
-
|
45
|
-
|
45
|
+
relative_numeral = relative_numeral block, document
|
46
|
+
reftext = if context == :stem
|
47
|
+
"(#{relative_numeral})"
|
48
|
+
else
|
49
|
+
"#{env.capitalize} #{relative_numeral}"
|
50
|
+
end
|
51
|
+
block.set_attr "reftext", reftext
|
52
|
+
end
|
53
|
+
|
54
|
+
def env(context, style)
|
55
|
+
case context
|
56
|
+
when :image then "figure"
|
57
|
+
when :stem then "equation"
|
58
|
+
when :listing then "listing"
|
59
|
+
else style || context.to_s
|
60
|
+
end
|
46
61
|
end
|
47
62
|
|
48
63
|
def process_numbered_block?(block)
|
49
|
-
|
64
|
+
context = block.context
|
65
|
+
case context
|
66
|
+
when :olist
|
67
|
+
block.style == "figlist"
|
68
|
+
when :stem, :listing
|
69
|
+
block.option? "numbered"
|
70
|
+
else
|
71
|
+
NUMBERED_CONTEXTS.include? context
|
72
|
+
end
|
50
73
|
end
|
51
74
|
|
52
75
|
def li_mark(depth, idx)
|
53
76
|
case depth
|
54
|
-
when
|
55
|
-
|
56
|
-
when
|
57
|
-
|
58
|
-
when 2
|
59
|
-
RomanNumerals.to_roman(idx + 1).downcase
|
60
|
-
when 3
|
61
|
-
("a".."z").to_a[idx].upcase
|
77
|
+
when 1 then ("a".."z").to_a[idx]
|
78
|
+
when 2 then RomanNumerals.to_roman(idx + 1).downcase
|
79
|
+
when 3 then ("a".."z").to_a[idx].upcase
|
80
|
+
else idx + 1
|
62
81
|
end
|
63
82
|
end
|
64
83
|
|
65
|
-
def
|
66
|
-
|
84
|
+
def bullet(depth)
|
85
|
+
case depth
|
86
|
+
when 1 then "‐"
|
87
|
+
when 2 then "⭑"
|
88
|
+
when 3 then "◦"
|
89
|
+
else "•"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def ref_li_mark(mark, depth, style = nil)
|
94
|
+
return "[#{mark}]" if style == "bibliography"
|
67
95
|
|
68
|
-
"(#{mark})"
|
96
|
+
depth.even? ? mark.to_s : "(#{mark})"
|
69
97
|
end
|
70
98
|
|
71
99
|
def offset(list)
|
@@ -76,7 +104,7 @@ module Asciidoctor
|
|
76
104
|
# its reftext to that of item's if necessary.
|
77
105
|
def register_reftext!(item, reftext)
|
78
106
|
item.set_attr "reftext", reftext
|
79
|
-
|
107
|
+
/\A<a id="(?<anchor_id>.+?)"/ =~ item.text
|
80
108
|
node = item.document.catalog[:refs][anchor_id]
|
81
109
|
node&.text ||= reftext
|
82
110
|
end
|
@@ -93,57 +121,106 @@ module Asciidoctor
|
|
93
121
|
block.set_attr("flat-style", true)
|
94
122
|
else
|
95
123
|
offset = offset block
|
124
|
+
style = block.style
|
96
125
|
block.items.each_with_index do |item, idx|
|
97
|
-
d =
|
126
|
+
d = style == "figlist" ? 1 : depth
|
98
127
|
mark = li_mark(d, idx + offset)
|
99
128
|
item.set_attr "mark", mark
|
100
|
-
item_reftext = "#{parent_reftext}#{ref_li_mark mark, d}"
|
129
|
+
item_reftext = "#{parent_reftext}#{ref_li_mark mark, d, style}"
|
101
130
|
register_reftext! item, item_reftext
|
102
131
|
end
|
103
132
|
end
|
104
133
|
end
|
105
134
|
|
135
|
+
def process_colist!(block)
|
136
|
+
block.set_attr "list-depth", 0
|
137
|
+
block.items.each_with_index do |item, idx|
|
138
|
+
icon = %(<i class="bi bi-#{idx + 1}-circle"></i>)
|
139
|
+
item.set_attr "mark", icon
|
140
|
+
register_reftext! item, icon
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def process_ulist!(block, depth)
|
145
|
+
block.set_attr "list-depth", depth
|
146
|
+
block.items.each do |item|
|
147
|
+
is_checkbox = item.attr? "checkbox"
|
148
|
+
icon_class = item.attr?("checked") ? "check-" : ""
|
149
|
+
icon = %(<i class="bi bi-#{icon_class}square"></i>)
|
150
|
+
mark = is_checkbox ? icon : bullet(depth)
|
151
|
+
item.role = "checked" if is_checkbox
|
152
|
+
item.set_attr "mark", mark
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
106
156
|
def process_flat_item!(item, idx)
|
107
157
|
mark = li_mark(0, idx)
|
108
158
|
item.set_attr "mark", mark
|
109
159
|
register_reftext! item, ref_li_mark(mark, 0)
|
110
160
|
end
|
111
161
|
|
112
|
-
def
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
162
|
+
def process_source_code!(document, lang)
|
163
|
+
document.set_attr("source-langs", {}) unless document.attr?("source-langs")
|
164
|
+
langs = document.attr "source-langs"
|
165
|
+
langs[lang] = true unless Highlightjs::INCLUDED_LANGS.include?(lang)
|
166
|
+
end
|
167
|
+
|
168
|
+
def olist_item?(node)
|
169
|
+
node.context == :list_item && node.parent.context == :olist
|
170
|
+
end
|
171
|
+
|
172
|
+
def ulist_item?(node)
|
173
|
+
node.context == :list_item && node.parent.context == :ulist
|
174
|
+
end
|
175
|
+
|
176
|
+
def ulist?(node)
|
177
|
+
node.context == :ulist
|
178
|
+
end
|
179
|
+
|
180
|
+
def olist?(node)
|
181
|
+
node.context == :olist
|
182
|
+
end
|
183
|
+
|
184
|
+
def colist?(node)
|
185
|
+
node.context == :colist
|
186
|
+
end
|
187
|
+
|
188
|
+
def source_code?(node)
|
189
|
+
node.context == :listing && node.style == "source" && node.attr?("language")
|
117
190
|
end
|
118
191
|
|
119
192
|
def process(document)
|
120
|
-
sectnum = 0
|
121
193
|
listdepth = 0
|
194
|
+
bulletdepth = 0
|
122
195
|
flat_style = false
|
123
196
|
flat_idx = 0 # flat index for (pseudocode) list
|
124
|
-
tw = TreeWalker.new
|
197
|
+
tw = TreeWalker.new document
|
125
198
|
while (block = tw.next_block)
|
126
|
-
context = block.context
|
127
199
|
unless block.attr? "refprocessed"
|
128
|
-
process_numbered_block!(block, document
|
129
|
-
if
|
130
|
-
|
131
|
-
|
132
|
-
elsif context == :olist
|
200
|
+
process_numbered_block!(block, document) if process_numbered_block?(block)
|
201
|
+
if colist? block
|
202
|
+
process_colist! block
|
203
|
+
elsif olist? block
|
133
204
|
if listdepth.zero?
|
134
205
|
flat_style = (block.style == "pseudocode")
|
135
|
-
flat_idx = offset block
|
206
|
+
flat_idx = offset block # rubocop:disable Lint/UselessAssignment
|
136
207
|
end
|
137
|
-
process_olist!
|
138
|
-
elsif
|
139
|
-
process_flat_item!
|
208
|
+
process_olist! block, listdepth, flat_style:
|
209
|
+
elsif olist_item?(block) && flat_style
|
210
|
+
process_flat_item! block, flat_idx
|
140
211
|
flat_idx += 1
|
212
|
+
elsif source_code? block
|
213
|
+
process_source_code! document, block.attr("language")
|
214
|
+
elsif ulist? block
|
215
|
+
process_ulist! block, bulletdepth
|
141
216
|
end
|
142
217
|
block.set_attr "refprocessed", true
|
143
218
|
end
|
144
219
|
tw.walk do |move|
|
145
|
-
listdepth += 1 if
|
146
|
-
listdepth -= 1 if
|
220
|
+
listdepth += 1 if olist?(block) && move == :explore
|
221
|
+
listdepth -= 1 if olist_item?(block) && move == :retreat
|
222
|
+
bulletdepth += 1 if ulist?(block) && move == :explore
|
223
|
+
bulletdepth -= 1 if ulist_item?(block) && move == :retreat
|
147
224
|
end
|
148
225
|
end
|
149
226
|
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "date"
|
4
|
+
require_relative "highlightjs"
|
5
|
+
require_relative "popovers"
|
6
|
+
|
7
|
+
module Asciidoctor
|
8
|
+
module Html
|
9
|
+
# The template for the book layout
|
10
|
+
module Template
|
11
|
+
def self.nav_item(target, text, content = "", active: false)
|
12
|
+
active_class = active ? %( class="active") : ""
|
13
|
+
link = %(<a href="#{target}">#{text}</a>)
|
14
|
+
subnav = content.empty? ? content : "\n#{content}\n"
|
15
|
+
%(<li#{active_class}>#{link}#{subnav}</li>\n)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.nav_text(chapnum, chaptitle)
|
19
|
+
return chaptitle if chapnum.empty?
|
20
|
+
|
21
|
+
%(<span class="title-mark">#{chapnum}</span>#{chaptitle})
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.appendix_title(chapname, numeral, doctitle, num_appendices)
|
25
|
+
numeral = num_appendices == 1 ? "" : " #{numeral}"
|
26
|
+
%(<span class="title-prefix">#{chapname}#{numeral}</span>#{doctitle})
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.sidebar(nav_items)
|
30
|
+
<<~HTML
|
31
|
+
<div id="sidebar" class="sidebar collapse collapse-horizontal">
|
32
|
+
<nav id="sidenav"><ul>
|
33
|
+
#{nav_items.join "\n"}
|
34
|
+
</ul></nav>
|
35
|
+
</div> <!-- .sidebar -->
|
36
|
+
HTML
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.main(content, chapnum, chaptitle, author, year)
|
40
|
+
<<~HTML
|
41
|
+
<main class="main">
|
42
|
+
<div class="content-container">
|
43
|
+
<h2>#{nav_text chapnum, chaptitle}</h2>
|
44
|
+
#{content}
|
45
|
+
#{footer author, year}
|
46
|
+
</div>
|
47
|
+
</main>
|
48
|
+
HTML
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.header(title, short_title, nav: true)
|
52
|
+
nav_btn = if nav
|
53
|
+
<<~HTML
|
54
|
+
<button type="button" class="btn menu"
|
55
|
+
data-bs-toggle="collapse" data-bs-target="#sidebar"
|
56
|
+
aria-expanded="false" aria-controls="sidebar">
|
57
|
+
<i class="bi bi-list"></i>
|
58
|
+
</button>
|
59
|
+
HTML
|
60
|
+
else
|
61
|
+
""
|
62
|
+
end
|
63
|
+
<<~HTML
|
64
|
+
<header class="header">
|
65
|
+
<a class="home d-none d-sm-block" href="./">#{title}</a>
|
66
|
+
<a class="home d-block d-sm-none" href="./">#{short_title}</a>
|
67
|
+
#{nav_btn}
|
68
|
+
</header>
|
69
|
+
HTML
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.footer(author, year)
|
73
|
+
%(<footer class="footer">© #{year} #{author}</footer>\n)
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.highlightjs(langs)
|
77
|
+
langs.map do |lang|
|
78
|
+
%(<script src="#{Highlightjs::CDN_PATH}/languages/#{lang}.min.js"></script>)
|
79
|
+
end.join("\n ")
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.head(title, langs)
|
83
|
+
<<~HTML
|
84
|
+
<head>
|
85
|
+
<meta charset="utf-8">
|
86
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
87
|
+
<title>#{title}</title>
|
88
|
+
<link rel="apple-touch-icon" sizes="180x180" href="#{FAVICON_PATH}/apple-touch-icon.png">
|
89
|
+
<link rel="icon" type="image/png" sizes="32x32" href="#{FAVICON_PATH}/favicon-32x32.png">
|
90
|
+
<link rel="icon" type="image/png" sizes="16x16" href="#{FAVICON_PATH}/favicon-16x16.png">
|
91
|
+
<link rel="manifest" href="#{FAVICON_PATH}/site.webmanifest">
|
92
|
+
<link rel="stylesheet" href="#{CSS_PATH}/styles.css">
|
93
|
+
<link rel="stylesheet" href="#{Highlightjs::CDN_PATH}/styles/tomorrow-night-blue.min.css">
|
94
|
+
<script src="#{Highlightjs::CDN_PATH}/highlight.min.js"></script>
|
95
|
+
#{highlightjs langs}
|
96
|
+
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
|
97
|
+
</head>
|
98
|
+
HTML
|
99
|
+
end
|
100
|
+
|
101
|
+
# opts:
|
102
|
+
# - title: String
|
103
|
+
# - short_title: String
|
104
|
+
# - author: String
|
105
|
+
# - date: Date
|
106
|
+
# - nav: Boolean
|
107
|
+
# - chapnum: Int
|
108
|
+
# - chaptitle: String
|
109
|
+
# - langs: Array[String]
|
110
|
+
def self.html(content, nav_items, opts = {})
|
111
|
+
hash_listener = if opts[:nav]
|
112
|
+
<<~JS
|
113
|
+
addEventListener('hashchange', function() {
|
114
|
+
collapse = bootstrap.Collapse.getInstance('#sidebar');
|
115
|
+
if(collapse) collapse.hide();
|
116
|
+
});
|
117
|
+
JS
|
118
|
+
else
|
119
|
+
""
|
120
|
+
end
|
121
|
+
<<~HTML
|
122
|
+
<!DOCTYPE html>
|
123
|
+
<html lang="en">
|
124
|
+
#{head opts[:title], opts[:langs]}
|
125
|
+
<body>
|
126
|
+
#{header opts[:title], opts[:short_title], nav: opts[:nav]}
|
127
|
+
#{sidebar(nav_items) if opts[:nav]}
|
128
|
+
#{main content, opts[:chapnum], opts[:chaptitle], opts[:author], opts[:date].year}
|
129
|
+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.6/dist/js/bootstrap.bundle.min.js"
|
130
|
+
integrity="sha384-j1CDi7MgGQ12Z7Qab0qlWQ/Qqz24Gc6BM0thvEMVjHnfYGF0rmFCozFSxQBxwHKO"
|
131
|
+
crossorigin="anonymous"></script>
|
132
|
+
<script>
|
133
|
+
const touch = matchMedia('(hover: none)').matches;
|
134
|
+
#{Highlightjs::PLUGIN}
|
135
|
+
hljs.highlightAll();
|
136
|
+
#{hash_listener}
|
137
|
+
#{Popovers::POPOVERS}
|
138
|
+
</script>
|
139
|
+
</body>
|
140
|
+
</html>
|
141
|
+
HTML
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -23,7 +23,9 @@ module Asciidoctor
|
|
23
23
|
|
24
24
|
if block.blocks? && @level < @max_levels && @idx[@level + 1] < block.blocks.size
|
25
25
|
@level += 1
|
26
|
-
|
26
|
+
el = block.blocks[@idx[@level]]
|
27
|
+
el = el.last if el.is_a?(Array) # Get the <dd> from an array of <dt>'s followed by <dd>
|
28
|
+
@path.push(el)
|
27
29
|
callback.call(:explore)
|
28
30
|
else
|
29
31
|
@idx[@level + 1] = 0 if @level < @max_levels
|
@@ -65,6 +65,12 @@ module Asciidoctor
|
|
65
65
|
def self.wrap_id_classes_with_title(content, node, id, classes, needs_prefix: false)
|
66
66
|
show_title?(node) ? wrap_id_classes(display_title(node, needs_prefix:) + content, id, classes) : content
|
67
67
|
end
|
68
|
+
|
69
|
+
def self.popover_button(content, content_id, classes = nil)
|
70
|
+
extra_classes = classes ? " #{classes}" : ""
|
71
|
+
attrs = %( tabindex="0" role="button" class="btn-po#{extra_classes}" data-contentid="#{content_id}")
|
72
|
+
%(<a#{attrs}>#{content}</a>)
|
73
|
+
end
|
68
74
|
end
|
69
75
|
end
|
70
76
|
end
|