resources/asciidoctor/lib/chunker/extension.rb (138 lines of code) (raw):
# frozen_string_literal: true
require 'asciidoctor/extensions'
require_relative '../delegating_converter'
require_relative '../strip_tags'
require_relative 'breadcrumbs'
require_relative 'convert_outline'
require_relative 'extra_docinfo'
require_relative 'find_related'
require_relative 'footnotes'
require_relative 'nav'
require_relative 'url_to_v3'
##
# HTML5 converter that chunks like docbook.
module Chunker
def self.activate(registry)
doc = registry.document
return unless doc.attr 'outdir'
return unless (chunk_level = doc.attr 'chunk_level')
doc.extend ExtraDocinfo
return if doc.attr 'subdoc'
doc.attributes['toclevels'] ||= doc.attributes['chunk_level']
DelegatingConverter.setup(registry.document) do |d|
Converter.new d, chunk_level.to_i
end
end
##
# A Converter implementation that chunks like docbook.
class Converter < DelegatingConverter
include Breadcrumbs
include ConvertOutline
include FindRelated
include Footnotes
include StripTags
def initialize(delegate, chunk_level)
super(delegate)
@chunk_level = chunk_level
end
def convert_document(doc)
title = doc.doctitle partition: true
doc.attributes['home'] = strip_tags(
title.main.strip + doc.attr('title-extra', '')
)
doc.attributes['next_section'] = find_next_in doc, 0
add_nav doc
add_url_to_v3 doc
yield
end
def convert_section(section)
doc = section.document
return yield unless section.level <= @chunk_level
html = form_section_into_page doc, section, yield
# Replace the breadcrumbs placeholder with
# the generated breadcrumbs
if html =~ %r{<div id="breadcrumbs-go-here"></div>}
html.gsub!(
%r{<div id="breadcrumbs-go-here"></div>},
generate_breadcrumbs(doc, section).to_s
)
end
html.gsub!(%r{</h1>}, "</h1>#{section.attr('edit_me_link', '')}")
write doc, "#{section.id}.html", html
''
end
def convert_inline_anchor(node)
correct_xref node if node.type == :xref
yield
end
def add_nav(doc)
nav = Nav.new doc
doc.blocks.insert 0, nav.header
doc.blocks.append nav.footer
end
def add_url_to_v3(doc)
url_to_v3 = UrlToV3.new doc
doc.blocks.insert 0, url_to_v3.url
end
def correct_xref(node)
refid = node.attributes['refid']
return unless (ref = node.document.catalog[:refs][refid])
page = page_containing ref
node.target = "#{page.id}.html"
node.target += "##{ref.id}" unless page == ref
end
def page_containing(node)
page = node
while page.context != :section || page.level > @chunk_level
page = page.parent
end
page
end
def form_section_into_page(doc, section, html)
# We don't use asciidoctor's "parent" documents here because they don't
# seem to buy us much and they are an "internal" detail.
subdoc = Asciidoctor::Document.new [], subdoc_opts(doc, section)
add_subdoc_sections doc, subdoc, html
subdoc.convert
end
def add_subdoc_sections(doc, subdoc, html)
nav = Nav.new subdoc
url_to_v3 = UrlToV3.new subdoc
subdoc << url_to_v3.url
subdoc << nav.header
subdoc << Asciidoctor::Block.new(subdoc, :pass, source: html)
subdoc << footnotes(doc, subdoc) if doc.footnotes?
subdoc << nav.footer
end
def subdoc_opts(doc, section)
{
attributes: subdoc_attrs(doc, section),
safe: doc.safe,
backend: doc.backend,
sourcemap: doc.sourcemap,
base_dir: doc.base_dir,
to_dir: doc.options[:to_dir],
standalone: true,
}
end
def subdoc_attrs(doc, section)
attrs = doc.attributes.dup
maintitle = doc.doctitle partition: true
# Rendered h1 heading
attrs['doctitle'] = subdoc_doctitle section
# Value of `title` in the `head`
attrs['title'] = subdoc_title section, maintitle
# Asciidoctor defaults these attribute to empty string if they aren't
# specified and setting them to `nil` clears them. Since we want to
# preserve the configuration from the parent into the child, we clear
# explicitly them if they aren't found in the parent. If we didn't then
# they'd default to fale.
attrs['stylesheet'] = nil unless attrs['stylesheet']
attrs['icons'] = nil unless attrs['icons']
attrs['subdoc'] = true # Mark the subdoc so we don't try and chunk it
attrs['title-separator'] = ''
attrs['canonical-url'] = section.attributes['canonical-url']
attrs['current-url'] = "#{section.id}.html"
attrs.merge! find_related(section)
attrs
end
# For the `h1` heading that appears on the rendered page,
# use just the page title
def subdoc_doctitle(section)
strip_tags section.captioned_title.to_s
end
# For the `title` in the `head`, use the page title followed
# by the site title ("Elastic")
def subdoc_title(section, maintitle)
strip_tags "#{section.captioned_title} | #{maintitle.main}"
end
def write(doc, file, html)
dir = doc.attr 'outdir'
path = File.join dir, file
File.open path, 'w:UTF-8' do |f|
f.write html
end
file
end
end
end