asciidoctor-html 2.0.2 → 2.1.0
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 +7 -4
- data/CHANGELOG.md +8 -0
- data/assets/css/styles.css +2 -2
- data/lib/asciidoctor/html/book.rb +7 -2
- data/lib/asciidoctor/html/book_template.rb +28 -16
- data/lib/asciidoctor/html/converter.rb +23 -11
- data/lib/asciidoctor/html/flip.rb +6 -9
- data/lib/asciidoctor/html/highlightjs.rb +6 -0
- data/lib/asciidoctor/html/list.rb +3 -2
- data/lib/asciidoctor/html/live.rb +140 -0
- data/lib/asciidoctor/html/ref_tree_processor.rb +28 -15
- data/lib/asciidoctor/html/subnav_block_macro.rb +1 -0
- data/lib/asciidoctor/html/table.rb +12 -3
- data/lib/asciidoctor/html/utils.rb +18 -0
- data/lib/asciidoctor/html/version.rb +1 -1
- data/lib/minitest/html_plugin.rb +1 -1
- metadata +2 -1
|
@@ -116,7 +116,7 @@ module Asciidoctor
|
|
|
116
116
|
end
|
|
117
117
|
|
|
118
118
|
def langs(doc)
|
|
119
|
-
doc.attr
|
|
119
|
+
doc.attr("source-langs").keys if doc.attr?("source-langs")
|
|
120
120
|
end
|
|
121
121
|
|
|
122
122
|
def doctitle(doc)
|
|
@@ -207,12 +207,15 @@ module Asciidoctor
|
|
|
207
207
|
|
|
208
208
|
def outline(key, doc, absolute: true)
|
|
209
209
|
items = []
|
|
210
|
+
line_number = 0
|
|
210
211
|
doc.sections.each do |section|
|
|
212
|
+
next if section.option? "skipnav"
|
|
211
213
|
next unless section.id && section.level == 1
|
|
212
214
|
|
|
213
215
|
prefix = Utils.display_sectnum(section) if section.numbered
|
|
214
216
|
url = "#{"#{key}.html" if absolute}##{section.id}"
|
|
215
|
-
|
|
217
|
+
line_number += 1
|
|
218
|
+
items << BookTemplate.nav_item(url, "#{prefix}#{section.title}", line_number:)
|
|
216
219
|
end
|
|
217
220
|
return "" unless items.size > 1
|
|
218
221
|
|
|
@@ -256,6 +259,7 @@ module Asciidoctor
|
|
|
256
259
|
content,
|
|
257
260
|
nav_items,
|
|
258
261
|
has_subnav: !outline.empty?,
|
|
262
|
+
has_live: doc.attr?("live"),
|
|
259
263
|
title: @title,
|
|
260
264
|
short_title: @short_title,
|
|
261
265
|
authors: display_authors(doc),
|
|
@@ -264,6 +268,7 @@ module Asciidoctor
|
|
|
264
268
|
chapheading: tdata.chapheading,
|
|
265
269
|
chapsubheading: tdata.chapsubheading,
|
|
266
270
|
langs: langs(doc),
|
|
271
|
+
linenumbering: doc.attr?("linenumbering"),
|
|
267
272
|
paginator: pagination(key),
|
|
268
273
|
pagestyle: doc.attr?("pagestyle") ? doc.attr("pagestyle").to_sym : :single
|
|
269
274
|
)
|
|
@@ -5,6 +5,7 @@ require_relative "popovers"
|
|
|
5
5
|
require_relative "sidebar"
|
|
6
6
|
require_relative "scroll"
|
|
7
7
|
require_relative "flip"
|
|
8
|
+
require_relative "live"
|
|
8
9
|
|
|
9
10
|
module Asciidoctor
|
|
10
11
|
module Html
|
|
@@ -17,11 +18,12 @@ module Asciidoctor
|
|
|
17
18
|
</button>
|
|
18
19
|
HTML
|
|
19
20
|
|
|
20
|
-
def self.nav_item(target, text, content = "", active: false)
|
|
21
|
+
def self.nav_item(target, text, content = "", active: false, line_number: 0)
|
|
21
22
|
active_class = active ? %( class="active") : ""
|
|
22
23
|
link = %(<a href="#{target}">#{text}</a>)
|
|
23
24
|
subnav = content.empty? ? content : "\n#{content}\n"
|
|
24
|
-
|
|
25
|
+
live_attr = Utils.line_number_attr(line_number, live: line_number.positive?)
|
|
26
|
+
%(<li#{active_class}#{live_attr}>#{link}#{subnav}</li>\n)
|
|
25
27
|
end
|
|
26
28
|
|
|
27
29
|
def self.nav_text(chapprefix, chaptitle)
|
|
@@ -101,7 +103,7 @@ module Asciidoctor
|
|
|
101
103
|
<main id="main" class="main">
|
|
102
104
|
<div id="content-container" class="content-container dynamic-width" tabindex="0">
|
|
103
105
|
#{chapheader opts[:chapheading], opts[:chapsubheading]}
|
|
104
|
-
<div class="chaphead d-block">
|
|
106
|
+
<div class="chaphead flip d-block">
|
|
105
107
|
#{toggle_button opts[:pagestyle] if opts[:has_subnav]}
|
|
106
108
|
#{chapheading opts[:chapheading]}
|
|
107
109
|
<h1 class="chaptitle">#{opts[:chapsubheading]}</h1>
|
|
@@ -161,27 +163,35 @@ module Asciidoctor
|
|
|
161
163
|
HTML
|
|
162
164
|
end
|
|
163
165
|
|
|
164
|
-
def self.highlightjs(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
166
|
+
def self.highlightjs(opts)
|
|
167
|
+
return "" unless opts[:langs]
|
|
168
|
+
|
|
169
|
+
html = [
|
|
170
|
+
<<~HTML
|
|
171
|
+
<link rel="stylesheet" href="#{Highlightjs::CDN_PATH}/styles/tomorrow-night-blue.min.css">
|
|
172
|
+
<script defer src="#{Highlightjs::CDN_PATH}/highlight.min.js"></script>
|
|
173
|
+
HTML
|
|
174
|
+
]
|
|
175
|
+
opts[:langs].each do |lang|
|
|
176
|
+
html << %(<script defer src="#{Highlightjs::CDN_PATH}/languages/#{lang}.min.js"></script>)
|
|
177
|
+
end
|
|
178
|
+
html << %(<script defer src="#{Highlightjs::LN_PLUGIN_PATH}"></script>) if opts[:linenumbering]
|
|
179
|
+
html.join "\n"
|
|
168
180
|
end
|
|
169
181
|
|
|
170
|
-
def self.head(
|
|
182
|
+
def self.head(opts)
|
|
171
183
|
<<~HTML
|
|
172
184
|
<meta charset="utf-8">
|
|
173
185
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
174
|
-
#{%(<meta name="description" content="#{description}">) if description}
|
|
175
|
-
#{%(<meta name="author" content="#{authors}">) if authors}
|
|
176
|
-
<title>#{title}</title>
|
|
186
|
+
#{%(<meta name="description" content="#{opts[:description]}">) if opts[:description]}
|
|
187
|
+
#{%(<meta name="author" content="#{opts[:authors]}">) if opts[:authors]}
|
|
188
|
+
<title>#{opts[:title]}</title>
|
|
177
189
|
<link rel="apple-touch-icon" sizes="180x180" href="#{FAVICON_PATH}/apple-touch-icon.png">
|
|
178
190
|
<link rel="icon" type="image/png" sizes="32x32" href="#{FAVICON_PATH}/favicon-32x32.png">
|
|
179
191
|
<link rel="icon" type="image/png" sizes="16x16" href="#{FAVICON_PATH}/favicon-16x16.png">
|
|
180
192
|
<link rel="manifest" href="#{FAVICON_PATH}/site.webmanifest" crossorigin="anonymous">
|
|
181
193
|
<link rel="stylesheet" href="#{CSS_PATH}/styles.css">
|
|
182
|
-
|
|
183
|
-
<script defer src="#{Highlightjs::CDN_PATH}/highlight.min.js"></script>
|
|
184
|
-
#{highlightjs langs}
|
|
194
|
+
#{highlightjs(opts)}
|
|
185
195
|
<script>
|
|
186
196
|
MathJax = {
|
|
187
197
|
tex: {
|
|
@@ -202,6 +212,7 @@ module Asciidoctor
|
|
|
202
212
|
|
|
203
213
|
# opts:
|
|
204
214
|
# - has_subnav: Boolean
|
|
215
|
+
# - has_live: Boolean
|
|
205
216
|
# - title: String
|
|
206
217
|
# - short_title: String
|
|
207
218
|
# - authors: String
|
|
@@ -223,7 +234,7 @@ module Asciidoctor
|
|
|
223
234
|
<!DOCTYPE html>
|
|
224
235
|
<html lang="en">
|
|
225
236
|
<head>
|
|
226
|
-
#{head
|
|
237
|
+
#{head(opts)}
|
|
227
238
|
#{opts[:at_head_end]}
|
|
228
239
|
</head>
|
|
229
240
|
<body>
|
|
@@ -235,11 +246,12 @@ module Asciidoctor
|
|
|
235
246
|
</div> <!-- .page -->
|
|
236
247
|
<script>document.getElementById("cr-year").textContent = (new Date()).getFullYear();</script>
|
|
237
248
|
<script type="module">
|
|
238
|
-
#{Highlightjs::PLUGIN}
|
|
249
|
+
#{Highlightjs::PLUGIN if opts[:langs]}
|
|
239
250
|
#{Popovers::POPOVERS}
|
|
240
251
|
#{Sidebar::TOGGLE if nav}
|
|
241
252
|
#{Scroll::SCROLL}
|
|
242
253
|
#{Flip::FLIP}
|
|
254
|
+
#{Live::LIVE if opts[:has_live]}
|
|
243
255
|
</script>
|
|
244
256
|
#{opts[:at_body_end]}
|
|
245
257
|
</body>
|
|
@@ -29,7 +29,7 @@ module Asciidoctor
|
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
def convert_preamble(node)
|
|
32
|
-
%(<div class="preamble d-block">\n#{node.content}</div> <!-- .preamble -->\n)
|
|
32
|
+
%(<div class="preamble flip d-block">\n#{node.content}</div> <!-- .preamble.flip -->\n)
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
def convert_section(node)
|
|
@@ -38,9 +38,10 @@ module Asciidoctor
|
|
|
38
38
|
show_sectnum = node.numbered && level <= (document.attr("sectnumlevels") || 1).to_i
|
|
39
39
|
tag_level = [level == 1 ? level + 1 : level + 2, 6].min
|
|
40
40
|
tag_name = %(h#{tag_level})
|
|
41
|
+
classes = "section#{" flip" if level == 1}#{" #{node.role}" if node.role}"
|
|
41
42
|
display_sectnum = Utils.display_sectnum(node, level) if show_sectnum
|
|
42
43
|
content = %(<#{tag_name}>#{display_sectnum}#{node.title}</#{tag_name}>\n#{node.content})
|
|
43
|
-
Utils.
|
|
44
|
+
Utils.wrap_id_classes content, node.id, classes, :section
|
|
44
45
|
end
|
|
45
46
|
|
|
46
47
|
def convert_paragraph(node)
|
|
@@ -120,8 +121,11 @@ module Asciidoctor
|
|
|
120
121
|
def convert_listing(node)
|
|
121
122
|
nowrap = (node.option? "nowrap") || !(node.document.attr? "prewrap")
|
|
122
123
|
if node.style == "source"
|
|
123
|
-
|
|
124
|
-
|
|
124
|
+
classes = []
|
|
125
|
+
classes << "language-#{node.attr "language"}" if node.attr?("language")
|
|
126
|
+
classes << "linenums" if (has_linenums = node.option? "linenums")
|
|
127
|
+
classes << "ln-plugin" if has_linenums || node.attr?("live")
|
|
128
|
+
code_open = %(<code#{%( class="#{classes.join " "}") unless classes.empty?}>)
|
|
125
129
|
pre_open = %(<pre#{%( class="nowrap") if nowrap}>#{code_open})
|
|
126
130
|
pre_close = "</code></pre>"
|
|
127
131
|
else
|
|
@@ -130,7 +134,7 @@ module Asciidoctor
|
|
|
130
134
|
end
|
|
131
135
|
title = Utils.display_title(node)
|
|
132
136
|
content = title + pre_open + node.content + pre_close
|
|
133
|
-
Utils.wrap_node
|
|
137
|
+
Utils.wrap_live Utils.wrap_node(content, node), node.attr("live")
|
|
134
138
|
end
|
|
135
139
|
|
|
136
140
|
def convert_literal(node)
|
|
@@ -192,19 +196,24 @@ module Asciidoctor
|
|
|
192
196
|
def convert_dlist(node)
|
|
193
197
|
classes = ["dlist", node.style, node.role].compact.join(" ")
|
|
194
198
|
result = [%(<dl#{Utils.dyn_id_class_attr_str node, classes}>)]
|
|
199
|
+
live = node.attr? "live"
|
|
200
|
+
line_number = 1
|
|
195
201
|
node.items.each do |terms, dd|
|
|
196
202
|
terms.each do |dt|
|
|
197
|
-
result << %(<dt>#{dt.text}</dt>)
|
|
203
|
+
result << %(<dt class="dterm"#{Utils.line_number_attr line_number, live:}>#{dt.text}</dt>)
|
|
204
|
+
line_number += 1
|
|
198
205
|
end
|
|
199
206
|
next unless dd
|
|
200
207
|
|
|
201
|
-
result << "<dd>"
|
|
208
|
+
result << "<dd#{Utils.line_number_attr line_number, live:}>"
|
|
209
|
+
line_number += 1
|
|
202
210
|
result << %(<p>#{dd.text}</p>) if dd.text?
|
|
203
211
|
result << dd.content if dd.blocks?
|
|
204
212
|
result << "</dd>"
|
|
205
213
|
end
|
|
206
214
|
result << "</dl>\n"
|
|
207
|
-
Utils.wrap_id_classes_with_title
|
|
215
|
+
Utils.wrap_live(Utils.wrap_id_classes_with_title(result.join("\n"), node, node.id, "dlist-wrapper"),
|
|
216
|
+
node.attr("live"))
|
|
208
217
|
end
|
|
209
218
|
|
|
210
219
|
def convert_inline_anchor(node)
|
|
@@ -233,7 +242,7 @@ module Asciidoctor
|
|
|
233
242
|
end
|
|
234
243
|
|
|
235
244
|
def convert_table(node)
|
|
236
|
-
classes = ["table"
|
|
245
|
+
classes = ["table"]
|
|
237
246
|
classes << "table-striped" if node.option? "striped"
|
|
238
247
|
classes << "table-bordered" if node.option? "bordered"
|
|
239
248
|
classes << "table-sm" if node.option? "compact"
|
|
@@ -246,7 +255,9 @@ module Asciidoctor
|
|
|
246
255
|
width_attribute = %( width="#{tablewidth}%")
|
|
247
256
|
end
|
|
248
257
|
result = [%(<table#{Utils.id_class_attr_str node.id, classes.join(" ")}#{width_attribute}>)]
|
|
249
|
-
|
|
258
|
+
unless node.option? "nocaption"
|
|
259
|
+
result << %(<caption class="table-title">#{Utils.display_title_prefix node}#{node.title}</caption>)
|
|
260
|
+
end
|
|
250
261
|
if node.attr("rowcount").positive? && node.attr?("cols")
|
|
251
262
|
result << "<colgroup>"
|
|
252
263
|
if autowidth
|
|
@@ -259,7 +270,8 @@ module Asciidoctor
|
|
|
259
270
|
result << "</colgroup>"
|
|
260
271
|
end
|
|
261
272
|
result << "#{Table.display_rows(node)}</table>"
|
|
262
|
-
|
|
273
|
+
wrap_classes = "table-responsive#{" #{node.role}" if node.role}"
|
|
274
|
+
Utils.wrap_live Utils.wrap_id_classes(result.join("\n"), nil, wrap_classes), node.attr("live")
|
|
263
275
|
end
|
|
264
276
|
end
|
|
265
277
|
end
|
|
@@ -6,7 +6,6 @@ module Asciidoctor
|
|
|
6
6
|
module Flip
|
|
7
7
|
FLIP = <<~JS
|
|
8
8
|
(function() {
|
|
9
|
-
const sectSelector = '.content-container > .section';
|
|
10
9
|
// Holds replaced pagination links to prev/next chapter
|
|
11
10
|
const chapPagination = {
|
|
12
11
|
prevChap: null,
|
|
@@ -25,11 +24,7 @@ module Asciidoctor
|
|
|
25
24
|
const nav = document.querySelectorAll('#sidebar nav > ul > li.active > ul > li');
|
|
26
25
|
|
|
27
26
|
let currentId = "page";
|
|
28
|
-
|
|
29
|
-
sectsById[currentId].push(el);
|
|
30
|
-
el.dataset.withSect = currentId;
|
|
31
|
-
});
|
|
32
|
-
document.querySelectorAll(sectSelector).forEach(el => {
|
|
27
|
+
focusEl.querySelectorAll(':scope > .flip').forEach(el => {
|
|
33
28
|
if(el.id) {
|
|
34
29
|
el.dataset.prevPage = currentId;
|
|
35
30
|
currentId = el.id;
|
|
@@ -50,7 +45,7 @@ module Asciidoctor
|
|
|
50
45
|
function focusOnLoad() {
|
|
51
46
|
if(searchForm) return;
|
|
52
47
|
|
|
53
|
-
focusEl.focus({preventScroll:
|
|
48
|
+
focusEl.focus({preventScroll: !page.classList.contains('presentation')});
|
|
54
49
|
}
|
|
55
50
|
|
|
56
51
|
function updatePaginator(prev, next) {
|
|
@@ -112,7 +107,7 @@ module Asciidoctor
|
|
|
112
107
|
document.querySelector('.breadcrumb').classList.toggle('d-block', id != 'page' && !isPresentation);
|
|
113
108
|
document.querySelector('.chapauthors').classList.toggle('d-block', isPresentation);
|
|
114
109
|
|
|
115
|
-
let section = target && target.closest(
|
|
110
|
+
let section = target && target.closest('.content-container > .section');
|
|
116
111
|
if(section) {
|
|
117
112
|
id = section.dataset.withSect;
|
|
118
113
|
section = sectsById[id][0];
|
|
@@ -151,6 +146,7 @@ module Asciidoctor
|
|
|
151
146
|
}
|
|
152
147
|
|
|
153
148
|
focusOnLoad();
|
|
149
|
+
if(isPresentation) focusEl.dataset.flip = id;
|
|
154
150
|
}
|
|
155
151
|
flip();
|
|
156
152
|
|
|
@@ -183,7 +179,7 @@ module Asciidoctor
|
|
|
183
179
|
switch(e.key) {
|
|
184
180
|
case 'ArrowLeft': move('left'); break;
|
|
185
181
|
case 'ArrowRight': move('right'); break;
|
|
186
|
-
case '
|
|
182
|
+
case 'q':
|
|
187
183
|
case 'Escape':
|
|
188
184
|
page.classList.contains('presentation') && changeViewmode('multi');
|
|
189
185
|
}
|
|
@@ -196,6 +192,7 @@ module Asciidoctor
|
|
|
196
192
|
}));
|
|
197
193
|
|
|
198
194
|
page.classList.add('loaded');
|
|
195
|
+
ADHT.move = move;
|
|
199
196
|
})();
|
|
200
197
|
JS
|
|
201
198
|
end
|
|
@@ -6,6 +6,8 @@ module Asciidoctor
|
|
|
6
6
|
module Highlightjs
|
|
7
7
|
CDN_PATH = "https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.11.1/build"
|
|
8
8
|
|
|
9
|
+
LN_PLUGIN_PATH = "https://cdn.jsdelivr.net/npm/highlightjs-line-numbers.js@2.9.0/dist/highlightjs-line-numbers.min.js"
|
|
10
|
+
|
|
9
11
|
INCLUDED_LANGS = {
|
|
10
12
|
"bash" => true,
|
|
11
13
|
"c" => true,
|
|
@@ -106,6 +108,10 @@ module Asciidoctor
|
|
|
106
108
|
}
|
|
107
109
|
});
|
|
108
110
|
hljs.highlightAll();
|
|
111
|
+
|
|
112
|
+
if(Object.hasOwn(hljs, "lineNumbersBlock")) {
|
|
113
|
+
document.querySelectorAll('code.ln-plugin').forEach(block => hljs.lineNumbersBlock(block));
|
|
114
|
+
}
|
|
109
115
|
})();
|
|
110
116
|
JS
|
|
111
117
|
end
|
|
@@ -26,13 +26,14 @@ module Asciidoctor
|
|
|
26
26
|
end
|
|
27
27
|
result << %(</#{tag_name}> <!-- .level-#{level} -->\n)
|
|
28
28
|
wrap_classes = %(list-wrapper#{" #{node.role}" if node.title? && node.role})
|
|
29
|
-
Utils.wrap_id_classes_with_title
|
|
29
|
+
Utils.wrap_live Utils.wrap_id_classes_with_title(result.join("\n"), node, node.id, wrap_classes), node.attr("live")
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
def self.display_list_item(item, inside: false)
|
|
33
33
|
result = []
|
|
34
|
+
lineno_attr = Utils.line_number_attr item.attr("line-number"), live: item.attr?("line-number")
|
|
34
35
|
inside_mark = %(<span class="li-mark-inside">#{item.attr "mark"} </span>) if inside
|
|
35
|
-
result << %(<li#{Utils.id_class_attr_str item.id, item.role}>)
|
|
36
|
+
result << %(<li#{Utils.id_class_attr_str item.id, item.role}#{lineno_attr}>)
|
|
36
37
|
result << %(<div class="li-mark">#{item.attr "mark"}</div><div class="li-content">) unless inside
|
|
37
38
|
result << %(<p>#{inside_mark}#{item.text}</p>) unless item.text.empty?
|
|
38
39
|
result << "\n#{item.content}" if item.blocks?
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Asciidoctor
|
|
4
|
+
module Html
|
|
5
|
+
# Script for live presentations
|
|
6
|
+
module Live
|
|
7
|
+
LIVE = <<~JS
|
|
8
|
+
(function() {
|
|
9
|
+
const page = document.getElementById('page');
|
|
10
|
+
const container = document.getElementById('content-container');
|
|
11
|
+
const liveBlocksSelector = ':scope > .flip.d-block .live';
|
|
12
|
+
|
|
13
|
+
let liveBlocks = container.querySelectorAll(liveBlocksSelector);
|
|
14
|
+
let liveBlockIdx = 0;
|
|
15
|
+
selectBlock();
|
|
16
|
+
|
|
17
|
+
const observer = new MutationObserver(() => {
|
|
18
|
+
liveBlocks = container.querySelectorAll(liveBlocksSelector);
|
|
19
|
+
liveBlockIdx = 0;
|
|
20
|
+
selectBlock();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
function selectBlock() {
|
|
24
|
+
liveBlocks.forEach((block, idx) => {
|
|
25
|
+
block.firstElementChild.classList.toggle('selected', idx === liveBlockIdx);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function getLines(block, lineNumber = -1, selected) {
|
|
30
|
+
let selector = '[data-line-number]';
|
|
31
|
+
if(lineNumber > -1) selector = `[data-line-number="${lineNumber}"]`;
|
|
32
|
+
if(selected === false) selector += ':not(.emph)';
|
|
33
|
+
if(selected === true) selector += '.emph';
|
|
34
|
+
return block.querySelectorAll(selector);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function getNextLines() {
|
|
38
|
+
while(liveBlocks.length > 0 && liveBlockIdx < liveBlocks.length) {
|
|
39
|
+
selectBlock();
|
|
40
|
+
const currentBlock = liveBlocks[liveBlockIdx];
|
|
41
|
+
if(currentBlock) {
|
|
42
|
+
toggleDefault(currentBlock);
|
|
43
|
+
let lines = getLines(currentBlock, -1, true);
|
|
44
|
+
if(lines.length > 0) {
|
|
45
|
+
const lineNumber = parseInt(lines[lines.length - 1].dataset.lineNumber) + 1;
|
|
46
|
+
lines = getLines(currentBlock, lineNumber);
|
|
47
|
+
if(lines.length > 0) return lines;
|
|
48
|
+
} else {
|
|
49
|
+
lines = getLines(currentBlock, -1, false);
|
|
50
|
+
if(lines.length > 0) return getLines(currentBlock, lines[0].dataset.lineNumber);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
liveBlockIdx++;
|
|
54
|
+
}
|
|
55
|
+
ADHT.move('right');
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function nextBlock() {
|
|
60
|
+
if(liveBlockIdx < liveBlocks.length - 1) {
|
|
61
|
+
liveBlockIdx++;
|
|
62
|
+
selectBlock();
|
|
63
|
+
} else {
|
|
64
|
+
ADHT.move('right');
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function prevBlock() {
|
|
69
|
+
if(liveBlockIdx > 0) {
|
|
70
|
+
liveBlockIdx--;
|
|
71
|
+
selectBlock();
|
|
72
|
+
} else {
|
|
73
|
+
ADHT.move('left');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function getPrevLines() {
|
|
78
|
+
while(liveBlocks.length > 0 && liveBlockIdx > -1) {
|
|
79
|
+
selectBlock();
|
|
80
|
+
const currentBlock = liveBlocks[liveBlockIdx];
|
|
81
|
+
if(currentBlock) {
|
|
82
|
+
const lines = getLines(currentBlock, -1, true);
|
|
83
|
+
if(lines.length > 0) {
|
|
84
|
+
const line = lines[lines.length - 1];
|
|
85
|
+
return getLines(currentBlock, line.dataset.lineNumber);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
liveBlockIdx--;
|
|
89
|
+
}
|
|
90
|
+
ADHT.move('left');
|
|
91
|
+
return [];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function toggleDefault(block, reset = false) {
|
|
95
|
+
const token = block.dataset.reset;
|
|
96
|
+
if(reset) {
|
|
97
|
+
block.classList.add(token);
|
|
98
|
+
getLines(block).forEach(el => el.classList.remove('emph'));
|
|
99
|
+
} else {
|
|
100
|
+
block.classList.remove(token);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
observer.observe(container, { attributes: true, attributeFilter: ['data-flip'] });
|
|
105
|
+
addEventListener('keyup', function(e) {
|
|
106
|
+
if(!page.classList.contains('presentation')) return;
|
|
107
|
+
|
|
108
|
+
const currentBlock = liveBlocks[liveBlockIdx];
|
|
109
|
+
if(/^\\d$/.test(e.key)) {
|
|
110
|
+
toggleDefault(currentBlock);
|
|
111
|
+
const key = e.key === "0" ? "10" : e.key;
|
|
112
|
+
getLines(currentBlock, e.key).forEach(el => el.classList.toggle('emph'));
|
|
113
|
+
} else {
|
|
114
|
+
switch(e.key) {
|
|
115
|
+
case 'r':
|
|
116
|
+
toggleDefault(currentBlock, true);
|
|
117
|
+
break;
|
|
118
|
+
case 'R':
|
|
119
|
+
liveBlocks.forEach(block => toggleDefault(block, true));
|
|
120
|
+
break;
|
|
121
|
+
case 'n':
|
|
122
|
+
getNextLines().forEach(el => el.classList.add('emph'));
|
|
123
|
+
break;
|
|
124
|
+
case 'b':
|
|
125
|
+
getPrevLines().forEach(el => el.classList.remove('emph'));
|
|
126
|
+
break;
|
|
127
|
+
case 'N':
|
|
128
|
+
nextBlock();
|
|
129
|
+
break;
|
|
130
|
+
case 'B':
|
|
131
|
+
prevBlock();
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
})();
|
|
137
|
+
JS
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
@@ -69,6 +69,8 @@ module Asciidoctor
|
|
|
69
69
|
block.style == "figlist"
|
|
70
70
|
when :stem, :listing
|
|
71
71
|
block.option? "numbered"
|
|
72
|
+
when :table
|
|
73
|
+
!block.option? "nocaption"
|
|
72
74
|
else
|
|
73
75
|
NUMBERED_CONTEXTS.include? context
|
|
74
76
|
end
|
|
@@ -152,7 +154,7 @@ module Asciidoctor
|
|
|
152
154
|
end
|
|
153
155
|
block.set_attr "list-depth", depth
|
|
154
156
|
if flat_style
|
|
155
|
-
block.set_attr
|
|
157
|
+
block.set_attr "flat-style", true
|
|
156
158
|
else
|
|
157
159
|
offset = offset block
|
|
158
160
|
style = block.style
|
|
@@ -194,8 +196,9 @@ module Asciidoctor
|
|
|
194
196
|
register_reftext! item, mark
|
|
195
197
|
end
|
|
196
198
|
|
|
197
|
-
def process_source_code!(document, lang)
|
|
199
|
+
def process_source_code!(document, lang, linenums: false)
|
|
198
200
|
document.set_attr("source-langs", {}) unless document.attr?("source-langs")
|
|
201
|
+
document.set_attr("linenumbering", true) if !document.attr?("linenumbering") && linenums
|
|
199
202
|
langs = document.attr "source-langs"
|
|
200
203
|
langs[lang] = true unless Highlightjs::INCLUDED_LANGS.include?(lang)
|
|
201
204
|
end
|
|
@@ -225,29 +228,39 @@ module Asciidoctor
|
|
|
225
228
|
end
|
|
226
229
|
|
|
227
230
|
def process(document)
|
|
228
|
-
listdepth = 0
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
flat_idx = 0 # flat index for (pseudocode) list
|
|
231
|
+
listdepth = bulletdepth = flat_idx = 0
|
|
232
|
+
flat_style = live = false
|
|
233
|
+
line_number = 1
|
|
232
234
|
tw = TreeWalker.new document
|
|
233
235
|
while (block = tw.next_block)
|
|
234
236
|
unless block.attr? "refprocessed"
|
|
235
237
|
process_numbered_block!(block, document) if process_numbered_block?(block)
|
|
236
238
|
if colist? block
|
|
237
239
|
process_colist! block
|
|
238
|
-
elsif olist? block
|
|
239
|
-
if listdepth.zero?
|
|
240
|
+
elsif (is_olist = olist? block) || (is_ulist = ulist? block)
|
|
241
|
+
if is_olist && listdepth.zero?
|
|
240
242
|
flat_style = (block.style == "pseudocode")
|
|
241
243
|
flat_idx = offset block
|
|
242
244
|
end
|
|
243
|
-
process_olist!
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
245
|
+
process_olist!(block, listdepth, flat_style:) if is_olist
|
|
246
|
+
process_ulist!(block, bulletdepth) if is_ulist
|
|
247
|
+
if (listdepth + bulletdepth).zero?
|
|
248
|
+
live = block.attr?("live")
|
|
249
|
+
document.set_attr "live", true if live && !document.attr?("live")
|
|
250
|
+
line_number = offset(block) + 1
|
|
251
|
+
end
|
|
252
|
+
elsif (is_olist_item = olist_item? block) || ulist_item?(block)
|
|
253
|
+
if is_olist_item && flat_style
|
|
254
|
+
process_flat_item! block, flat_idx
|
|
255
|
+
flat_idx += 1
|
|
256
|
+
end
|
|
257
|
+
if live
|
|
258
|
+
block.set_attr "line-number", line_number
|
|
259
|
+
line_number += 1
|
|
260
|
+
end
|
|
247
261
|
elsif source_code? block
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
process_ulist! block, bulletdepth
|
|
262
|
+
linenums = block.option?("linenums") || block.attr?("live")
|
|
263
|
+
process_source_code! document, block.attr("language"), linenums:
|
|
251
264
|
end
|
|
252
265
|
block.set_attr "refprocessed", true
|
|
253
266
|
end
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "utils"
|
|
4
|
+
|
|
3
5
|
module Asciidoctor
|
|
4
6
|
module Html
|
|
5
7
|
# Helpers for the table conversion
|
|
6
8
|
module Table
|
|
7
|
-
def self.display_row(tsec, row)
|
|
8
|
-
result = ["<tr>"]
|
|
9
|
+
def self.display_row(tsec, row, line_number, live: false)
|
|
10
|
+
result = ["<tr#{Utils.line_number_attr line_number, live:}>"]
|
|
9
11
|
row.each do |cell|
|
|
10
12
|
cell_content = if tsec == :head
|
|
11
13
|
cell.text
|
|
@@ -31,10 +33,17 @@ module Asciidoctor
|
|
|
31
33
|
end
|
|
32
34
|
|
|
33
35
|
def self.display_rows(node)
|
|
36
|
+
line_number = 0
|
|
37
|
+
live = node.attr? "live"
|
|
34
38
|
node.rows.to_h.map do |tsec, rows|
|
|
35
39
|
next if rows.empty?
|
|
36
40
|
|
|
37
|
-
|
|
41
|
+
result = rows.map do |row|
|
|
42
|
+
show_lineno = live && tsec != :head
|
|
43
|
+
line_number += 1 if show_lineno
|
|
44
|
+
display_row(tsec, row, line_number, live: show_lineno)
|
|
45
|
+
end
|
|
46
|
+
"<t#{tsec}>\n#{result.join "\n"}\n</t#{tsec}>"
|
|
38
47
|
end.join("\n")
|
|
39
48
|
end
|
|
40
49
|
end
|
|
@@ -85,6 +85,24 @@ module Asciidoctor
|
|
|
85
85
|
end
|
|
86
86
|
%(<span class="title-mark">#{sectnum}</span>)
|
|
87
87
|
end
|
|
88
|
+
|
|
89
|
+
def self.wrap_live(content, live_attr)
|
|
90
|
+
return content unless live_attr
|
|
91
|
+
|
|
92
|
+
/\A(?<default>normal|faded|covered)-(?<live>faded|covered)\Z/ =~ live_attr
|
|
93
|
+
|
|
94
|
+
live_class = %(live-#{live || "faded"})
|
|
95
|
+
default_class = %(live-default-#{default || "normal"})
|
|
96
|
+
<<~HTML
|
|
97
|
+
<div class="live #{default_class} #{live_class}" data-reset="#{default_class}">
|
|
98
|
+
<div class="live-select"><i class="bi bi-eye"></i></div>
|
|
99
|
+
#{content}</div> <!-- .live -->
|
|
100
|
+
HTML
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def self.line_number_attr(line_number, live: false)
|
|
104
|
+
live ? %( data-line-number="#{line_number}") : ""
|
|
105
|
+
end
|
|
88
106
|
end
|
|
89
107
|
end
|
|
90
108
|
end
|
data/lib/minitest/html_plugin.rb
CHANGED
|
@@ -35,7 +35,7 @@ module Minitest
|
|
|
35
35
|
color = failed ? "danger" : "success"
|
|
36
36
|
id = "test-#{name.tr "_", "-"}"
|
|
37
37
|
title = display_result_title name, failed, color
|
|
38
|
-
pre = %([
|
|
38
|
+
pre = %([live=normal-faded,asciidoc]\n------\n#{adoc}\n------\n)
|
|
39
39
|
fail = failed ? display_failure(@results[key].join("\n")) : ""
|
|
40
40
|
%([##{id}]\n== #{title}\n\n#{pre}#{fail}\n\n#{adoc}\n\n)
|
|
41
41
|
end
|