asciidoctor-html 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -43,12 +43,14 @@ module Asciidoctor
43
43
  block.set_attr("showcaption", true) unless context == :stem
44
44
  assign_numeral! block, document, NUMBERED_CONTEXTS[context]
45
45
  relative_numeral = relative_numeral block, document
46
+
46
47
  reftext = if context == :stem
47
48
  "(#{relative_numeral})"
48
49
  else
49
50
  "#{env.capitalize} #{relative_numeral}"
50
51
  end
51
- block.set_attr "reftext", reftext
52
+ block.set_attr "reftext", reftext unless block.reftext?
53
+ block.set_attr "title-prefix", reftext
52
54
  end
53
55
 
54
56
  def env(context, style)
@@ -156,9 +158,10 @@ module Asciidoctor
156
158
  def process_colist!(block)
157
159
  block.set_attr "list-depth", 0
158
160
  block.items.each_with_index do |item, idx|
159
- icon = %(<i class="bi bi-#{idx + 1}-circle"></i>)
161
+ icon_type = "#{idx + 1}-circle"
162
+ icon = %(<i class="bi bi-#{icon_type}"></i>)
160
163
  item.set_attr "mark", icon
161
- register_reftext! item, icon
164
+ register_reftext! item, "bi:#{icon_type}[]"
162
165
  end
163
166
  end
164
167
 
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "asciidoctor"
4
+
5
+ module Asciidoctor
6
+ module Html
7
+ # Convert text to small caps
8
+ class ScInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
9
+ use_dsl
10
+
11
+ named :sc
12
+ name_positional_attributes "text"
13
+ format :short
14
+
15
+ def process(parent, target, _attrs)
16
+ create_inline_pass parent, "[.smallcaps]##{target}#",
17
+ attributes: { "subs" => :normal }
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Asciidoctor
4
+ module Html
5
+ # Due to mobile dynamic viewport heights, we need custom code for
6
+ # reliable anchor scrolling.
7
+ module Scroll
8
+ SCROLL = <<~JS
9
+ (function() {
10
+ const page = document.getElementById('page');
11
+ function scrollToElement(e) {
12
+ e.preventDefault();
13
+ const href = location.hash;
14
+ const id = href.substring(1);
15
+ const target = document.getElementById(id);
16
+ if(!target) return;
17
+
18
+ const rect = target.getBoundingClientRect()
19
+ page.scrollTo({
20
+ top: rect.top + page.scrollTop,
21
+ left: 0,
22
+ behavior: 'smooth'
23
+ });
24
+ }
25
+ addEventListener('hashchange', scrollToElement);
26
+ })();
27
+ JS
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Asciidoctor
4
+ module Html
5
+ # Toggle behaviour of sidebar
6
+ module Sidebar
7
+ TOGGLE = <<~JS
8
+ (function() {
9
+ const page = document.getElementById('page');
10
+ const sidebar = document.getElementById('sidebar');
11
+ const dismissBtn = document.getElementById('sidebar-dismiss-btn');
12
+ function hideSidebar() {
13
+ sidebar && sidebar.classList.remove('shown');
14
+ page.classList.remove('noscroll');
15
+ }
16
+
17
+ // Sidebar should be hidden on any local link click
18
+ document.querySelectorAll('a[href^="#"]').forEach(el => {
19
+ el.addEventListener('click', hideSidebar);
20
+ });
21
+ addEventListener('resize', hideSidebar);
22
+ dismissBtn && dismissBtn.addEventListener('click', hideSidebar);
23
+
24
+ const menuBtn = document.getElementById('menu-btn');
25
+ if(!menuBtn) return;
26
+
27
+ // Nudge menuBtn in case there is a scrollbar
28
+ const main = document.getElementById('main');
29
+ const scrollbarWidth = page.offsetWidth - main.offsetWidth;
30
+ menuBtn.style.right = (scrollbarWidth + 12) + 'px';
31
+
32
+ // Add click listener to toggle sidebar
33
+ menuBtn.addEventListener('click', function() {
34
+ sidebar && sidebar.classList.toggle('shown');
35
+ if(scrollbarWidth > 0) page.classList.toggle('noscroll');
36
+ });
37
+ })();
38
+ JS
39
+ end
40
+ end
41
+ end
@@ -4,7 +4,7 @@ module Asciidoctor
4
4
  module Html
5
5
  # Helpers for the table conversion
6
6
  module Table
7
- def self.display_row(tsec, row)
7
+ def self.display_row(node, tsec, row)
8
8
  result = ["<tr>"]
9
9
  row.each do |cell|
10
10
  cell_content = if tsec == :head
@@ -14,8 +14,11 @@ module Asciidoctor
14
14
  else
15
15
  cell.content.join "\n"
16
16
  end
17
- cell_tag_name = (tsec == :head || cell.style == :header ? %(th scope="col") : "td")
18
- cell_class_attribute = %( class="halign-#{cell.attr "halign"} align-#{cell.attr "valign"}")
17
+ cell_tag_name = (tsec == :head || cell.style == :header ? "th" : "td")
18
+ cell_attrs = []
19
+ cell_attrs << %(halign-#{cell.attr "halign"}) unless node.attr?("halign")
20
+ cell_attrs << %(align-#{cell.attr "valign"}) unless node.attr?("valign")
21
+ cell_class_attribute = %( class="#{cell_attrs.join " "}") unless cell_attrs.empty?
19
22
  cell_colspan_attribute = cell.colspan ? %( colspan="#{cell.colspan}") : ""
20
23
  cell_rowspan_attribute = cell.rowspan ? %( rowspan="#{cell.rowspan}") : ""
21
24
  cell_attributes = "#{cell_class_attribute}#{cell_colspan_attribute}#{cell_rowspan_attribute}"
@@ -29,7 +32,7 @@ module Asciidoctor
29
32
  node.rows.to_h.map do |tsec, rows|
30
33
  next if rows.empty?
31
34
 
32
- "<t#{tsec}>\n#{rows.map { |row| display_row(tsec, row) }.join("\n")}\n</t#{tsec}>"
35
+ "<t#{tsec}>\n#{rows.map { |row| display_row(node, tsec, row) }.join("\n")}\n</t#{tsec}>"
33
36
  end.join("\n")
34
37
  end
35
38
  end
@@ -3,11 +3,20 @@
3
3
  require "date"
4
4
  require_relative "highlightjs"
5
5
  require_relative "popovers"
6
+ require_relative "sidebar"
7
+ require_relative "scroll"
6
8
 
7
9
  module Asciidoctor
8
10
  module Html
9
11
  # The template for the book layout
10
12
  module Template
13
+ MENU_BTN = <<~HTML
14
+ <button type="button" id="menu-btn" class="btn menu"
15
+ aria-expanded="false" aria-controls="sidebar">
16
+ <i class="bi bi-list"></i>
17
+ </button>
18
+ HTML
19
+
11
20
  def self.nav_item(target, text, content = "", active: false)
12
21
  active_class = active ? %( class="active") : ""
13
22
  link = %(<a href="#{target}">#{text}</a>)
@@ -15,10 +24,10 @@ module Asciidoctor
15
24
  %(<li#{active_class}>#{link}#{subnav}</li>\n)
16
25
  end
17
26
 
18
- def self.nav_text(chapnum, chaptitle)
19
- return chaptitle if chapnum.empty?
27
+ def self.nav_text(chapprefix, chaptitle)
28
+ return chaptitle if chapprefix.empty?
20
29
 
21
- %(<span class="title-mark">#{chapnum}</span>#{chaptitle})
30
+ %(<span class="title-mark">#{chapprefix}</span>#{chaptitle})
22
31
  end
23
32
 
24
33
  def self.appendix_title(chapname, numeral, doctitle, num_appendices)
@@ -28,21 +37,29 @@ module Asciidoctor
28
37
 
29
38
  def self.sidebar(nav_items)
30
39
  <<~HTML
31
- <div id="sidebar" class="sidebar collapse collapse-horizontal">
32
- <nav id="sidenav"><ul>
40
+ <div id="sidebar" class="sidebar">
41
+ <button id="sidebar-dismiss-btn" class="btn dismiss"><i class="bi bi-x-lg"></i></button>
42
+ <nav><ul>
33
43
  #{nav_items.join "\n"}
34
44
  </ul></nav>
35
45
  </div> <!-- .sidebar -->
36
46
  HTML
37
47
  end
38
48
 
39
- def self.main(content, chapnum, chaptitle, author, year)
49
+ # opts:
50
+ # - chapheading: String
51
+ # - chapsubheading: String
52
+ # - content: String
53
+ # - author: String
54
+ # - date: Date
55
+ def self.main(opts)
40
56
  <<~HTML
41
- <main class="main">
42
- <div class="content-container">
43
- <h1>#{nav_text chapnum, chaptitle}</h1>
44
- #{content}
45
- #{footer author, year}
57
+ <main id="main" class="main">
58
+ <div id="content-container" class="content-container">
59
+ #{%(<h1 class="chapheading">#{opts[:chapheading]}</h1>) if opts[:chapheading]}
60
+ <h1 class="chaptitle">#{opts[:chapsubheading]}</h1>
61
+ #{opts[:content]}
62
+ #{footer opts[:author], opts[:date].year}
46
63
  </div>
47
64
  </main>
48
65
  HTML
@@ -66,23 +83,11 @@ module Asciidoctor
66
83
  XML
67
84
  end
68
85
 
69
- def self.header(title, short_title, nav: true)
70
- nav_btn = if nav
71
- <<~HTML
72
- <button type="button" class="btn menu"
73
- data-bs-toggle="collapse" data-bs-target="#sidebar"
74
- aria-expanded="false" aria-controls="sidebar">
75
- <i class="bi bi-list"></i>
76
- </button>
77
- HTML
78
- else
79
- ""
80
- end
86
+ def self.header(title, short_title)
81
87
  <<~HTML
82
88
  <header class="header">
83
89
  <a class="home d-none d-sm-block" href="./">#{title}</a>
84
90
  <a class="home d-block d-sm-none" href="./">#{short_title}</a>
85
- #{nav_btn}
86
91
  </header>
87
92
  HTML
88
93
  end
@@ -100,7 +105,7 @@ module Asciidoctor
100
105
 
101
106
  def self.highlightjs(langs)
102
107
  langs.map do |lang|
103
- %(<script src="#{Highlightjs::CDN_PATH}/languages/#{lang}.min.js"></script>)
108
+ %(<script defer src="#{Highlightjs::CDN_PATH}/languages/#{lang}.min.js"></script>)
104
109
  end.join("\n ")
105
110
  end
106
111
 
@@ -118,9 +123,19 @@ module Asciidoctor
118
123
  <link rel="manifest" href="#{FAVICON_PATH}/site.webmanifest">
119
124
  <link rel="stylesheet" href="#{CSS_PATH}/styles.css">
120
125
  <link rel="stylesheet" href="#{Highlightjs::CDN_PATH}/styles/tomorrow-night-blue.min.css">
121
- <script src="#{Highlightjs::CDN_PATH}/highlight.min.js"></script>
126
+ <script defer src="#{Highlightjs::CDN_PATH}/highlight.min.js"></script>
122
127
  #{highlightjs langs}
123
- <script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
128
+ <script>
129
+ MathJax = {
130
+ tex: {
131
+ inlineMath: {'[+]': [['$', '$']]}
132
+ }
133
+ };
134
+ </script>
135
+ <script defer src="https://cdn.jsdelivr.net/npm/mathjax@4/tex-chtml.js"></script>
136
+ <script defer src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.6/dist/js/bootstrap.bundle.min.js"
137
+ integrity="sha384-j1CDi7MgGQ12Z7Qab0qlWQ/Qqz24Gc6BM0thvEMVjHnfYGF0rmFCozFSxQBxwHKO"
138
+ crossorigin="anonymous"></script>
124
139
  </head>
125
140
  HTML
126
141
  end
@@ -131,38 +146,28 @@ module Asciidoctor
131
146
  # - author: String
132
147
  # - description: String
133
148
  # - date: Date
134
- # - chapnum: Int
149
+ # - chapheading: String
135
150
  # - chaptitle: String
136
151
  # - langs: Array[String]
137
152
  def self.html(content, nav_items, opts = {})
138
153
  nav = (nav_items.size > 1)
139
- hash_listener = if nav
140
- <<~JS
141
- addEventListener('hashchange', function() {
142
- collapse = bootstrap.Collapse.getInstance('#sidebar');
143
- if(collapse) collapse.hide();
144
- });
145
- JS
146
- else
147
- ""
148
- end
149
154
  <<~HTML
150
155
  <!DOCTYPE html>
151
156
  <html lang="en">
152
157
  #{head opts[:title], opts[:description], opts[:author], opts[:langs]}
153
158
  <body>
154
- #{header opts[:title], opts[:short_title], nav:}
155
159
  #{sidebar(nav_items) if nav}
156
- #{main content, opts[:chapnum], opts[:chaptitle], opts[:author], opts[:date].year}
157
- <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.6/dist/js/bootstrap.bundle.min.js"
158
- integrity="sha384-j1CDi7MgGQ12Z7Qab0qlWQ/Qqz24Gc6BM0thvEMVjHnfYGF0rmFCozFSxQBxwHKO"
159
- crossorigin="anonymous"></script>
160
- <script>
161
- const touch = matchMedia('(hover: none)').matches;
160
+ <div id="page" class="page">
161
+ #{MENU_BTN if nav}
162
+ #{header opts[:title], opts[:short_title]}
163
+ #{main content:, **opts}
164
+ </div> <!-- .page -->
165
+ <script type="module">
162
166
  #{Highlightjs::PLUGIN}
163
167
  hljs.highlightAll();
164
- #{hash_listener}
165
168
  #{Popovers::POPOVERS}
169
+ #{Sidebar::TOGGLE if nav}
170
+ #{Scroll::SCROLL}
166
171
  </script>
167
172
  </body>
168
173
  </html>
@@ -31,14 +31,23 @@ module Asciidoctor
31
31
  node.attr?("showcaption") || node.title?
32
32
  end
33
33
 
34
- def self.display_title(node, needs_prefix: true)
35
- prefix = needs_prefix ? display_title_prefix(node) : ""
36
- show_title?(node) ? %(<h6 class="block-title">#{prefix}#{node.title}</h6>\n) : ""
34
+ def self.display_title(node)
35
+ prefix = display_title_prefix node
36
+ suffix = display_title_suffix node
37
+ show_title?(node) ? %(<h6 class="block-title">#{prefix}#{node.title}#{suffix}</h6>\n) : ""
38
+ end
39
+
40
+ def self.display_title_suffix(node)
41
+ return "" unless node.attr?("title-suffix")
42
+
43
+ suffix = node.attr "title-suffix"
44
+ %(<span class="title-suffix">#{node.apply_subs suffix}</span>)
37
45
  end
38
46
 
39
47
  def self.display_title_prefix(node)
40
- prefix = node.reftext? ? node.reftext : ""
41
- node.title? && !node.title.empty? ? %(<span class="title-prefix">#{prefix}</span>) : prefix
48
+ prefix = node.attr?("title-prefix") ? node.attr("title-prefix") : ""
49
+ prefix = %(<span class="title-prefix">#{prefix}</span>) if node.title? && !node.title.empty? && !prefix.empty?
50
+ prefix
42
51
  end
43
52
 
44
53
  def self.wrap_id_classes(content, id, classes, tag_name = :div)
@@ -54,12 +63,12 @@ module Asciidoctor
54
63
  wrap_id_classes content, node.id, classes, tag_name
55
64
  end
56
65
 
57
- def self.wrap_node_with_title(content, node, tag_name = :div, needs_prefix: false)
58
- show_title?(node) ? wrap_node(display_title(node, needs_prefix:) + content, node, tag_name) : content
66
+ def self.wrap_node_with_title(content, node, tag_name = :div)
67
+ show_title?(node) ? wrap_node(display_title(node) + content, node, tag_name) : content
59
68
  end
60
69
 
61
- def self.wrap_id_classes_with_title(content, node, id, classes, needs_prefix: false)
62
- show_title?(node) ? wrap_id_classes(display_title(node, needs_prefix:) + content, id, classes) : content
70
+ def self.wrap_id_classes_with_title(content, node, id, classes)
71
+ show_title?(node) ? wrap_id_classes(display_title(node) + content, id, classes) : content
63
72
  end
64
73
 
65
74
  def self.popover_button(content, content_id, classes = nil)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asciidoctor-html
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ravi Rajani
@@ -98,8 +98,12 @@ files:
98
98
  - lib/asciidoctor/html/figure.rb
99
99
  - lib/asciidoctor/html/highlightjs.rb
100
100
  - lib/asciidoctor/html/list.rb
101
+ - lib/asciidoctor/html/pagination.rb
101
102
  - lib/asciidoctor/html/popovers.rb
102
103
  - lib/asciidoctor/html/ref_tree_processor.rb
104
+ - lib/asciidoctor/html/sc_inline_macro.rb
105
+ - lib/asciidoctor/html/scroll.rb
106
+ - lib/asciidoctor/html/sidebar.rb
103
107
  - lib/asciidoctor/html/table.rb
104
108
  - lib/asciidoctor/html/template.rb
105
109
  - lib/asciidoctor/html/tree_walker.rb