asciidoctor-html 2.1.5 → 2.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.
@@ -220,7 +220,7 @@ module Asciidoctor
220
220
  line_number += 1
221
221
  items << BookTemplate.nav_item(url, "#{prefix}#{section.title}", line_number:)
222
222
  end
223
- return "" unless items.size > 1
223
+ return unless items.size > 1
224
224
 
225
225
  "<ul>#{items.join "\n"}</ul>"
226
226
  end
@@ -240,7 +240,7 @@ module Asciidoctor
240
240
  def nav_items(active_key = -1, doc = nil)
241
241
  items = @templates.map do |k, td|
242
242
  active = (k == active_key)
243
- subnav = active && doc ? outline(k, doc, absolute: false) : ""
243
+ subnav = active && doc ? outline(k, doc, absolute: false) : td.outline
244
244
  navtext = BookTemplate.nav_text td.chapprefix, td.chaptitle
245
245
  BookTemplate.nav_item "#{k}.html", navtext, subnav, active:
246
246
  end
@@ -261,7 +261,7 @@ module Asciidoctor
261
261
  BookTemplate.html(
262
262
  content,
263
263
  nav_items,
264
- has_subnav: !outline.empty?,
264
+ has_subnav: !outline.nil?,
265
265
  has_live: doc.attr?("live"),
266
266
  title: @title,
267
267
  short_title: @short_title,
@@ -18,10 +18,26 @@ module Asciidoctor
18
18
  </button>
19
19
  HTML
20
20
 
21
- def self.nav_item(target, text, content = "", active: false, line_number: 0)
22
- active_class = active ? %( class="active") : ""
23
- link = %(<a href="#{target}">#{text}</a>)
24
- subnav = content.empty? ? content : "\n#{content}\n"
21
+ def self.nav_item(target, text, content = nil, active: false, line_number: 0)
22
+ if content
23
+ id = target.sub(/\.html$/, "-subnav").tr ".", "-"
24
+ show_class = " show" if active
25
+ subnav = %(<div class="collapse#{show_class}" id="#{id}">\n#{content}\n</div>)
26
+ toggle = <<~HTML
27
+ <button class="btn subnav-toggle#{" collapsed" unless active}"
28
+ type="button"
29
+ data-bs-toggle="collapse"
30
+ data-bs-target="##{id}"
31
+ aria-expanded="#{active ? "true" : "false"}"
32
+ aria-controls="#{id}">
33
+ <svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" class="caret" viewBox="0 0 16 16">
34
+ <path d="M7.247 11.14 2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z"/>
35
+ </svg>
36
+ </button>
37
+ HTML
38
+ end
39
+ active_class = %( class="active") if active
40
+ link = %(<a href="#{target}">#{text}</a>#{toggle})
25
41
  live_attr = Utils.line_number_attr(line_number, live: line_number.positive?)
26
42
  %(<li#{active_class}#{live_attr}>#{link}#{subnav}</li>\n)
27
43
  end
@@ -186,12 +202,12 @@ module Asciidoctor
186
202
  #{%(<meta name="description" content="#{opts[:description]}">) if opts[:description]}
187
203
  #{%(<meta name="author" content="#{opts[:authors]}">) if opts[:authors]}
188
204
  <title>#{opts[:title]}</title>
189
- <link rel="icon" type="image/png" href="#{FAVICON_PATH}/favicon-96x96.png" sizes="96x96" />
190
- <link rel="icon" type="image/svg+xml" href="#{FAVICON_PATH}/favicon.svg" />
191
- <link rel="shortcut icon" href="#{FAVICON_PATH}/favicon.ico" />
192
- <link rel="apple-touch-icon" sizes="180x180" href="#{FAVICON_PATH}/apple-touch-icon.png" />
193
- <meta name="apple-mobile-web-app-title" content="#{opts[:short_title]}" />
194
- <link rel="manifest" href="site.webmanifest" />
205
+ <link rel="icon" type="image/png" href="#{FAVICON_PATH}/favicon-96x96.png" sizes="96x96">
206
+ <link rel="icon" type="image/svg+xml" href="#{FAVICON_PATH}/favicon.svg">
207
+ <link rel="shortcut icon" href="#{FAVICON_PATH}/favicon.ico">
208
+ <link rel="apple-touch-icon" sizes="180x180" href="#{FAVICON_PATH}/apple-touch-icon.png">
209
+ <meta name="apple-mobile-web-app-title" content="#{opts[:short_title]}">
210
+ <link rel="manifest" href="site.webmanifest">
195
211
  <link rel="stylesheet" href="#{CSS_PATH}/styles.css">
196
212
  #{highlightjs(opts)}
197
213
  <script>
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pathname"
4
+ require "zlib"
5
+ require "strscan"
6
+
7
+ module Asciidoctor
8
+ module Html
9
+ # Postprocess site with cachebusting paths
10
+ module CacheBuster
11
+ AssetData = Struct.new("AssetData", :filehash, :newpath)
12
+
13
+ def self.process(outdir)
14
+ puts "-- Begin cache busting --"
15
+ puts
16
+ cache = {} # assetpath => {:filehash,:newpath}
17
+ glob = ["**/*.html", "*.webmanifest"]
18
+ Pathname(outdir).glob(glob) do |filepath|
19
+ puts "Processing"
20
+ puts " #{filepath}"
21
+ scanner = StringScanner.new(filepath.read)
22
+ rgx = %r{"((?<prefix>[\./]*?#{ASSETS_PATH}/.+?)(?<hash>\.|\.[a-f0-9]{8}\.)(?<ext>[a-z]+?))"}
23
+ buffer = []
24
+ while (scanned = scanner.scan_until(rgx))
25
+ matched = scanner.matched
26
+ buffer << scanned[0, scanned.size - matched.size]
27
+ matchedpath = Pathname(matched[1..-2])
28
+ assetpath = filepath.dirname / matchedpath
29
+ if assetpath.file?
30
+ assetpath = assetpath.realpath
31
+ captures = scanner.named_captures
32
+ cache[assetpath] ||= AssetData.new
33
+ assetdata = cache[assetpath]
34
+ assetdata.filehash ||= format("%08x", Zlib.crc32(assetpath.read))
35
+ new_hash = assetdata.filehash
36
+ found_hash = captures["hash"][1..-2] unless captures["hash"] == "."
37
+ if new_hash == found_hash
38
+ buffer << matched
39
+ else
40
+ new_name = "#{captures["prefix"]}.#{new_hash}.#{captures["ext"]}"
41
+ buffer << %("#{new_name}")
42
+ assetdata.newpath = filepath.dirname / Pathname(new_name)
43
+ end
44
+ else
45
+ buffer << matched
46
+ end
47
+ end
48
+ buffer << scanner.rest
49
+ filepath.write buffer.join
50
+ end
51
+ cache.each_pair do |assetpath, assetdata|
52
+ next unless assetdata.newpath
53
+
54
+ puts
55
+ puts "Renaming:"
56
+ puts " #{assetpath}"
57
+ puts "->#{assetdata.newpath}"
58
+ assetpath.rename(assetdata.newpath)
59
+ end
60
+ puts
61
+ puts "-- End cache busting --"
62
+ end
63
+ end
64
+ end
65
+ end
@@ -9,6 +9,7 @@ require_relative "book"
9
9
  require_relative "webmanifest"
10
10
  require_relative "version"
11
11
  require_relative "jupyterlite"
12
+ require_relative "cache_buster"
12
13
 
13
14
  module Asciidoctor
14
15
  module Html
@@ -16,6 +17,7 @@ module Asciidoctor
16
17
  module CLI
17
18
  DEFAULT_OPTIONS = {
18
19
  "config-file": "config.yml",
20
+ "bust-cache": false,
19
21
  watch: false
20
22
  }.freeze
21
23
 
@@ -29,6 +31,8 @@ module Asciidoctor
29
31
  OptionParser.new do |parser|
30
32
  parser.on("-w", "--watch",
31
33
  "Watch for file changes in SRCDIR. Default: unset")
34
+ parser.on("-b", "--bust-cache",
35
+ "Modify asset names for cache busting. Default: #{options[:"bust-cache"]}")
32
36
  parser.on("-c", "--config-file CONFIG",
33
37
  "Location of config file. Default: #{options[:"config-file"]}")
34
38
  parser.on("-v", "--version", "Print version and exit.")
@@ -121,6 +125,7 @@ module Asciidoctor
121
125
  puts "Writing book to\n #{outdir}"
122
126
  puts
123
127
  book.write config["chapters"], config["appendices"], outdir, sitemap: true
128
+ CacheBuster.process(outdir) if opts[:"bust-cache"]
124
129
  return unless opts[:watch]
125
130
 
126
131
  Filewatcher.new("#{srcdir}/*.adoc").watch do |changes|
@@ -84,7 +84,7 @@ module Asciidoctor
84
84
 
85
85
  def convert_sidebar(node)
86
86
  classes = ["aside", node.role].compact.join(" ")
87
- title = node.title? ? %(<h5 class="aside-title">#{node.title}</h5>\n) : ""
87
+ title = node.title? ? %(<div class="aside-title">#{node.title}</div>\n) : ""
88
88
  content = "#{title}#{node.content}"
89
89
  %(<aside#{Utils.id_class_attr_str node.id, classes}>\n#{content}\n</aside>\n)
90
90
  end
@@ -24,7 +24,7 @@ module Asciidoctor
24
24
  const chapheading = page.querySelector('.chapheading');
25
25
  const chaptitle = page.querySelector('.chaptitle');
26
26
 
27
- const nav = document.querySelectorAll('#sidebar nav > ul > li.active > ul > li');
27
+ const nav = document.querySelectorAll('#sidebar nav > ul > li.active ul li');
28
28
 
29
29
  let currentId = "page";
30
30
  focusEl.querySelectorAll(':scope > .flip').forEach(el => {
@@ -23,7 +23,7 @@ module Asciidoctor
23
23
  </form>
24
24
  </div>
25
25
  <div id="search-results-container" class="hidden">
26
- <h5 class="search-matches-title">Found <span id="search-nmatches">0 matches</span></h5>
26
+ <div class="h4 search-matches-title">Found <span id="search-nmatches">0 matches</span></div>
27
27
  <ul id="search-results" class="search-results list-group list-group-flush"></ul>
28
28
  </div>
29
29
  HTML
@@ -14,13 +14,14 @@ module Asciidoctor
14
14
 
15
15
  def process(parent, target, attrs)
16
16
  doc_key = Pathname(target).sub_ext "" unless target.empty?
17
- title = %(<h5 class="block-title">#{parent.apply_subs attrs["title"]}</h5>) if attrs.include?("title")
17
+ title = %(<div class="block-title">#{parent.apply_subs attrs["title"]}</div>) if attrs.include?("title")
18
18
  bordered_class = " bordered" if attrs.include?("border")
19
19
  border_width = attrs["border"].to_i if bordered_class
20
20
  style = %( style="border-top-width: #{border_width}px; border-bottom-width: #{border_width}px;") if border_width
21
21
  roles = " #{attrs["role"]}" if attrs.include?("role")
22
+ id_attr = %( id="#{attrs["id"]}") if attrs.include?("id")
22
23
  content = <<~HTML
23
- <div class="subnav#{bordered_class}#{roles}"#{style}>
24
+ <div#{id_attr} class="subnav#{bordered_class}#{roles}"#{style}>
24
25
  #{title}
25
26
  <nav>
26
27
  <%= templates.dig("#{doc_key}", "outline") || outline %>
@@ -34,7 +34,7 @@ module Asciidoctor
34
34
  def self.display_title(node)
35
35
  prefix = display_title_prefix node
36
36
  suffix = display_title_suffix node
37
- show_title?(node) ? %(<h6 class="block-title">#{prefix}#{node.title}#{suffix}</h6>\n) : ""
37
+ show_title?(node) ? %(<div class="block-title">#{prefix}#{node.title}#{suffix}</div>\n) : ""
38
38
  end
39
39
 
40
40
  def self.display_title_suffix(node)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Asciidoctor
4
4
  module Html
5
- VERSION = "2.1.5"
5
+ VERSION = "2.1.7"
6
6
  end
7
7
  end
@@ -15,3 +15,4 @@ require_relative "html/converter"
15
15
  require_relative "html/ref_tree_processor"
16
16
  require_relative "html/book"
17
17
  require_relative "html/cli"
18
+ require_relative "html/cache_buster"
@@ -9,7 +9,6 @@ module Minitest
9
9
  class HTMLReporter < AbstractReporter
10
10
  DOCS_DIR = "#{__dir__}/../../docs/asciidoc".freeze
11
11
  TESTS_DIR = "#{__dir__}/../../test/asciidoctor/html".freeze
12
- CONFIG_FILE = "#{DOCS_DIR}/config.yml".freeze
13
12
 
14
13
  def initialize
15
14
  @results = {}
@@ -57,7 +56,6 @@ module Minitest
57
56
  end
58
57
  adoc = %(= Test Results\n:pagestyle: multi\n\n#{time}\n\nsubnav::[border=1]\n\n#{results.join "\n"})
59
58
  File.write("#{DOCS_DIR}/tests.adoc", adoc)
60
- Asciidoctor::Html::CLI.run({ "config-file": CONFIG_FILE, watch: false })
61
59
  end
62
60
  end
63
61
 
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: 2.1.5
4
+ version: 2.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ravi Rajani
@@ -118,6 +118,7 @@ files:
118
118
  - lib/asciidoctor/html/bi_inline_macro.rb
119
119
  - lib/asciidoctor/html/book.rb
120
120
  - lib/asciidoctor/html/book_template.rb
121
+ - lib/asciidoctor/html/cache_buster.rb
121
122
  - lib/asciidoctor/html/cli.rb
122
123
  - lib/asciidoctor/html/converter.rb
123
124
  - lib/asciidoctor/html/cref_inline_macro.rb