asciidoctor-html 2.0.3 → 2.1.1
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/jupyterlite.css +1 -0
- data/assets/css/styles.css +2 -2
- data/jupyterlite/.gitignore +116 -0
- data/jupyterlite/content/data/matplotlib.png +0 -0
- data/jupyterlite/content/pyodide/matplotlib.ipynb +113 -0
- data/jupyterlite/content/python.ipynb +721 -0
- data/jupyterlite/overrides.json +5 -0
- data/jupyterlite/repl/jupyter-lite.json +12 -0
- data/jupyterlite/requirements.txt +7 -0
- data/lib/asciidoctor/html/book.rb +9 -2
- data/lib/asciidoctor/html/book_template.rb +28 -16
- data/lib/asciidoctor/html/cli.rb +12 -2
- data/lib/asciidoctor/html/converter.rb +33 -12
- data/lib/asciidoctor/html/cref_inline_macro.rb +2 -2
- data/lib/asciidoctor/html/flip.rb +5 -8
- data/lib/asciidoctor/html/highlightjs.rb +6 -0
- data/lib/asciidoctor/html/jupyterlite.rb +64 -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 +31 -16
- 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/asciidoctor/html.rb +0 -1
- data/lib/minitest/html_plugin.rb +1 -1
- metadata +11 -1
|
@@ -31,6 +31,7 @@ module Asciidoctor
|
|
|
31
31
|
|
|
32
32
|
DOCATTRS = {
|
|
33
33
|
"sectids" => false,
|
|
34
|
+
"xrefstyle" => "short",
|
|
34
35
|
"stem" => "latexmath",
|
|
35
36
|
"hide-uri-scheme" => true,
|
|
36
37
|
"source-highlighter" => "highlight.js",
|
|
@@ -59,6 +60,7 @@ module Asciidoctor
|
|
|
59
60
|
# - short_title
|
|
60
61
|
# - authors
|
|
61
62
|
# - chapname
|
|
63
|
+
# - base_url
|
|
62
64
|
def initialize(opts = {})
|
|
63
65
|
opts = DEFAULT_OPTS.merge opts
|
|
64
66
|
@title = ERB::Escape.html_escape opts[:title]
|
|
@@ -116,7 +118,7 @@ module Asciidoctor
|
|
|
116
118
|
end
|
|
117
119
|
|
|
118
120
|
def langs(doc)
|
|
119
|
-
doc.attr
|
|
121
|
+
doc.attr("source-langs").keys if doc.attr?("source-langs")
|
|
120
122
|
end
|
|
121
123
|
|
|
122
124
|
def doctitle(doc)
|
|
@@ -207,12 +209,15 @@ module Asciidoctor
|
|
|
207
209
|
|
|
208
210
|
def outline(key, doc, absolute: true)
|
|
209
211
|
items = []
|
|
212
|
+
line_number = 0
|
|
210
213
|
doc.sections.each do |section|
|
|
214
|
+
next if section.option? "skipnav"
|
|
211
215
|
next unless section.id && section.level == 1
|
|
212
216
|
|
|
213
217
|
prefix = Utils.display_sectnum(section) if section.numbered
|
|
214
218
|
url = "#{"#{key}.html" if absolute}##{section.id}"
|
|
215
|
-
|
|
219
|
+
line_number += 1
|
|
220
|
+
items << BookTemplate.nav_item(url, "#{prefix}#{section.title}", line_number:)
|
|
216
221
|
end
|
|
217
222
|
return "" unless items.size > 1
|
|
218
223
|
|
|
@@ -256,6 +261,7 @@ module Asciidoctor
|
|
|
256
261
|
content,
|
|
257
262
|
nav_items,
|
|
258
263
|
has_subnav: !outline.empty?,
|
|
264
|
+
has_live: doc.attr?("live"),
|
|
259
265
|
title: @title,
|
|
260
266
|
short_title: @short_title,
|
|
261
267
|
authors: display_authors(doc),
|
|
@@ -264,6 +270,7 @@ module Asciidoctor
|
|
|
264
270
|
chapheading: tdata.chapheading,
|
|
265
271
|
chapsubheading: tdata.chapsubheading,
|
|
266
272
|
langs: langs(doc),
|
|
273
|
+
linenumbering: doc.attr?("linenumbering"),
|
|
267
274
|
paginator: pagination(key),
|
|
268
275
|
pagestyle: doc.attr?("pagestyle") ? doc.attr("pagestyle").to_sym : :single
|
|
269
276
|
)
|
|
@@ -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>
|
data/lib/asciidoctor/html/cli.rb
CHANGED
|
@@ -8,6 +8,7 @@ require "psych"
|
|
|
8
8
|
require_relative "book"
|
|
9
9
|
require_relative "webmanifest"
|
|
10
10
|
require_relative "version"
|
|
11
|
+
require_relative "jupyterlite"
|
|
11
12
|
|
|
12
13
|
module Asciidoctor
|
|
13
14
|
module Html
|
|
@@ -53,10 +54,11 @@ module Asciidoctor
|
|
|
53
54
|
"#{config["srcdir"]}/#{f}"
|
|
54
55
|
end
|
|
55
56
|
end
|
|
57
|
+
config["jupyterlite"] = config["jupyterlite"] || false
|
|
56
58
|
config
|
|
57
59
|
end
|
|
58
60
|
|
|
59
|
-
def self.setup_outdir(srcdir, outdir)
|
|
61
|
+
def self.setup_outdir(srcdir, outdir, jupyterlite: false)
|
|
60
62
|
assets_out = "#{outdir}/#{ASSETS_PATH}"
|
|
61
63
|
FileUtils.mkdir_p assets_out unless File.directory?(assets_out)
|
|
62
64
|
%W[#{IMG_PATH} #{CSS_PATH} #{FAVICON_PATH}].each do |p|
|
|
@@ -76,6 +78,7 @@ module Asciidoctor
|
|
|
76
78
|
puts
|
|
77
79
|
FileUtils.cp_r "#{rootdir}/#{p}", assets_out
|
|
78
80
|
end
|
|
81
|
+
build_jupyterlite(rootdir, outdir) if jupyterlite
|
|
79
82
|
end
|
|
80
83
|
|
|
81
84
|
def self.generate_webmanifest(outdir, name, short_name)
|
|
@@ -95,6 +98,13 @@ module Asciidoctor
|
|
|
95
98
|
book_opts
|
|
96
99
|
end
|
|
97
100
|
|
|
101
|
+
def self.build_jupyterlite(rootdir, outdir)
|
|
102
|
+
jupyterlite_outdir = "#{outdir}/#{Jupyterlite::PATH}"
|
|
103
|
+
return if File.directory?(jupyterlite_outdir)
|
|
104
|
+
|
|
105
|
+
system %(#{rootdir}/bin/build-jupyterlite -o "#{jupyterlite_outdir}" "#{rootdir}/#{Jupyterlite::PATH}")
|
|
106
|
+
end
|
|
107
|
+
|
|
98
108
|
def self.run(opts = nil)
|
|
99
109
|
opts ||= parse_opts
|
|
100
110
|
if opts[:version]
|
|
@@ -105,7 +115,7 @@ module Asciidoctor
|
|
|
105
115
|
outdir = config["outdir"]
|
|
106
116
|
srcdir = config["srcdir"]
|
|
107
117
|
book_opts = generate_bookopts config
|
|
108
|
-
setup_outdir srcdir, outdir
|
|
118
|
+
setup_outdir srcdir, outdir, jupyterlite: config["jupyterlite"]
|
|
109
119
|
generate_webmanifest outdir, book_opts[:title], book_opts[:short_title]
|
|
110
120
|
book = Book.new book_opts
|
|
111
121
|
puts "Writing book to\n #{outdir}"
|
|
@@ -5,6 +5,7 @@ require_relative "list"
|
|
|
5
5
|
require_relative "utils"
|
|
6
6
|
require_relative "figure"
|
|
7
7
|
require_relative "table"
|
|
8
|
+
require_relative "jupyterlite"
|
|
8
9
|
|
|
9
10
|
module Asciidoctor
|
|
10
11
|
module Html
|
|
@@ -29,7 +30,7 @@ module Asciidoctor
|
|
|
29
30
|
end
|
|
30
31
|
|
|
31
32
|
def convert_preamble(node)
|
|
32
|
-
%(<div class="preamble d-block">\n#{node.content}</div> <!-- .preamble -->\n)
|
|
33
|
+
%(<div class="preamble flip d-block">\n#{node.content}</div> <!-- .preamble.flip -->\n)
|
|
33
34
|
end
|
|
34
35
|
|
|
35
36
|
def convert_section(node)
|
|
@@ -38,9 +39,10 @@ module Asciidoctor
|
|
|
38
39
|
show_sectnum = node.numbered && level <= (document.attr("sectnumlevels") || 1).to_i
|
|
39
40
|
tag_level = [level == 1 ? level + 1 : level + 2, 6].min
|
|
40
41
|
tag_name = %(h#{tag_level})
|
|
42
|
+
classes = "section#{" flip" if level == 1}#{" #{node.role}" if node.role}"
|
|
41
43
|
display_sectnum = Utils.display_sectnum(node, level) if show_sectnum
|
|
42
44
|
content = %(<#{tag_name}>#{display_sectnum}#{node.title}</#{tag_name}>\n#{node.content})
|
|
43
|
-
Utils.
|
|
45
|
+
Utils.wrap_id_classes content, node.id, classes, :section
|
|
44
46
|
end
|
|
45
47
|
|
|
46
48
|
def convert_paragraph(node)
|
|
@@ -118,19 +120,30 @@ module Asciidoctor
|
|
|
118
120
|
end
|
|
119
121
|
|
|
120
122
|
def convert_listing(node)
|
|
123
|
+
if node.option? "jupyter"
|
|
124
|
+
return Utils.wrap_id_classes(
|
|
125
|
+
"#{Utils.display_title node}#{Jupyterlite.html node}",
|
|
126
|
+
node.id,
|
|
127
|
+
"jupyter-cell-wrapper"
|
|
128
|
+
)
|
|
129
|
+
end
|
|
130
|
+
|
|
121
131
|
nowrap = (node.option? "nowrap") || !(node.document.attr? "prewrap")
|
|
122
132
|
if node.style == "source"
|
|
123
|
-
|
|
124
|
-
|
|
133
|
+
classes = []
|
|
134
|
+
classes << "language-#{node.attr "language"}" if node.attr?("language")
|
|
135
|
+
classes << "linenums" if (has_linenums = node.option? "linenums")
|
|
136
|
+
classes << "ln-plugin" if has_linenums || node.attr?("live")
|
|
137
|
+
code_open = %(<code#{%( class="#{classes.join " "}") unless classes.empty?}>)
|
|
125
138
|
pre_open = %(<pre#{%( class="nowrap") if nowrap}>#{code_open})
|
|
126
139
|
pre_close = "</code></pre>"
|
|
127
140
|
else
|
|
128
141
|
pre_open = %(<pre#{%( class="nowrap") if nowrap}>)
|
|
129
142
|
pre_close = "</pre>"
|
|
130
143
|
end
|
|
131
|
-
title = Utils.display_title
|
|
144
|
+
title = Utils.display_title node
|
|
132
145
|
content = title + pre_open + node.content + pre_close
|
|
133
|
-
Utils.wrap_node
|
|
146
|
+
Utils.wrap_live Utils.wrap_node(content, node), node.attr("live")
|
|
134
147
|
end
|
|
135
148
|
|
|
136
149
|
def convert_literal(node)
|
|
@@ -192,19 +205,24 @@ module Asciidoctor
|
|
|
192
205
|
def convert_dlist(node)
|
|
193
206
|
classes = ["dlist", node.style, node.role].compact.join(" ")
|
|
194
207
|
result = [%(<dl#{Utils.dyn_id_class_attr_str node, classes}>)]
|
|
208
|
+
live = node.attr? "live"
|
|
209
|
+
line_number = 1
|
|
195
210
|
node.items.each do |terms, dd|
|
|
196
211
|
terms.each do |dt|
|
|
197
|
-
result << %(<dt>#{dt.text}</dt>)
|
|
212
|
+
result << %(<dt class="dterm"#{Utils.line_number_attr line_number, live:}>#{dt.text}</dt>)
|
|
213
|
+
line_number += 1
|
|
198
214
|
end
|
|
199
215
|
next unless dd
|
|
200
216
|
|
|
201
|
-
result << "<dd>"
|
|
217
|
+
result << "<dd#{Utils.line_number_attr line_number, live:}>"
|
|
218
|
+
line_number += 1
|
|
202
219
|
result << %(<p>#{dd.text}</p>) if dd.text?
|
|
203
220
|
result << dd.content if dd.blocks?
|
|
204
221
|
result << "</dd>"
|
|
205
222
|
end
|
|
206
223
|
result << "</dl>\n"
|
|
207
|
-
Utils.wrap_id_classes_with_title
|
|
224
|
+
Utils.wrap_live(Utils.wrap_id_classes_with_title(result.join("\n"), node, node.id, "dlist-wrapper"),
|
|
225
|
+
node.attr("live"))
|
|
208
226
|
end
|
|
209
227
|
|
|
210
228
|
def convert_inline_anchor(node)
|
|
@@ -233,7 +251,7 @@ module Asciidoctor
|
|
|
233
251
|
end
|
|
234
252
|
|
|
235
253
|
def convert_table(node)
|
|
236
|
-
classes = ["table"
|
|
254
|
+
classes = ["table"]
|
|
237
255
|
classes << "table-striped" if node.option? "striped"
|
|
238
256
|
classes << "table-bordered" if node.option? "bordered"
|
|
239
257
|
classes << "table-sm" if node.option? "compact"
|
|
@@ -246,7 +264,9 @@ module Asciidoctor
|
|
|
246
264
|
width_attribute = %( width="#{tablewidth}%")
|
|
247
265
|
end
|
|
248
266
|
result = [%(<table#{Utils.id_class_attr_str node.id, classes.join(" ")}#{width_attribute}>)]
|
|
249
|
-
|
|
267
|
+
unless node.option? "nocaption"
|
|
268
|
+
result << %(<caption class="table-title">#{Utils.display_title_prefix node}#{node.title}</caption>)
|
|
269
|
+
end
|
|
250
270
|
if node.attr("rowcount").positive? && node.attr?("cols")
|
|
251
271
|
result << "<colgroup>"
|
|
252
272
|
if autowidth
|
|
@@ -259,7 +279,8 @@ module Asciidoctor
|
|
|
259
279
|
result << "</colgroup>"
|
|
260
280
|
end
|
|
261
281
|
result << "#{Table.display_rows(node)}</table>"
|
|
262
|
-
|
|
282
|
+
wrap_classes = "table-responsive#{" #{node.role}" if node.role}"
|
|
283
|
+
Utils.wrap_live Utils.wrap_id_classes(result.join("\n"), nil, wrap_classes), node.attr("live")
|
|
263
284
|
end
|
|
264
285
|
end
|
|
265
286
|
end
|
|
@@ -28,8 +28,8 @@ module Asciidoctor
|
|
|
28
28
|
tag = path_tag.size > 1 ? path_tag[1] : "chapref"
|
|
29
29
|
doc_key = Pathname(path).sub_ext ""
|
|
30
30
|
text = attrs["text"] || %(<%= refs.dig("#{doc_key}", "#{tag}") || "[#{doc_key}][#{tag}]" %>)
|
|
31
|
-
|
|
32
|
-
href = "#{Pathname(path).sub_ext ".html"}#{
|
|
31
|
+
hashtag = "##{path_tag[1]}" if path_tag.size > 1
|
|
32
|
+
href = "#{Pathname(path).sub_ext ".html"}#{hashtag}"
|
|
33
33
|
create_anchor parent, text, type: :link, target: href
|
|
34
34
|
end
|
|
35
35
|
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;
|
|
@@ -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
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Asciidoctor
|
|
4
|
+
module Html
|
|
5
|
+
# Constants for the jupyterlite library
|
|
6
|
+
module Jupyterlite
|
|
7
|
+
class << self
|
|
8
|
+
attr_accessor :cell_id
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
PATH = "jupyterlite"
|
|
12
|
+
REPL_PATH = "repl/index.html"
|
|
13
|
+
|
|
14
|
+
CONFIG = {
|
|
15
|
+
toolbar: true,
|
|
16
|
+
kernel: "python",
|
|
17
|
+
promptCellPosition: "left",
|
|
18
|
+
clearCellsOnExecute: true,
|
|
19
|
+
hideCodeInput: true,
|
|
20
|
+
clearCodeContentOnExecute: false,
|
|
21
|
+
showBanner: false,
|
|
22
|
+
execute: false
|
|
23
|
+
}.freeze
|
|
24
|
+
|
|
25
|
+
def self.repl_path_with_options(node)
|
|
26
|
+
query_string = ["code=#{URI.encode_uri_component node.content}"]
|
|
27
|
+
query_string << CONFIG.merge(
|
|
28
|
+
{ promptCellPosition: node.attr("prompt-position", "left") }
|
|
29
|
+
).map do |k, v|
|
|
30
|
+
value = if v == true
|
|
31
|
+
1
|
|
32
|
+
elsif v == false
|
|
33
|
+
0
|
|
34
|
+
else
|
|
35
|
+
v
|
|
36
|
+
end
|
|
37
|
+
"#{k}=#{URI.encode_uri_component value}"
|
|
38
|
+
end
|
|
39
|
+
"#{REPL_PATH}?#{query_string.join "&"}"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.html(node)
|
|
43
|
+
@cell_id += 1
|
|
44
|
+
cell_id = "jupyter-cell-frame-#{@cell_id}"
|
|
45
|
+
height_attr = %( style="height: #{node.attr("height")}px;") if node.attr?("height")
|
|
46
|
+
<<~HTML
|
|
47
|
+
<div id="#{cell_id}"#{height_attr} class="jupyter-cell"></div>
|
|
48
|
+
<script>
|
|
49
|
+
(function(){
|
|
50
|
+
const cell = document.getElementById('#{cell_id}');
|
|
51
|
+
addEventListener('load', () => {
|
|
52
|
+
const frame = document.createElement('iframe');
|
|
53
|
+
frame.src = '#{PATH}/#{repl_path_with_options node}';
|
|
54
|
+
frame.width = '100%';
|
|
55
|
+
frame.height = '100%';
|
|
56
|
+
cell.appendChild(frame);
|
|
57
|
+
});
|
|
58
|
+
})();
|
|
59
|
+
</script>
|
|
60
|
+
HTML
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
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
|