require "isodoc"
require "htmlentities"
require_relative "fileprocess"
require_relative "../../util/fontist_helper"
require_relative "../../util/util"
require_relative "../filelookup/filelookup"
require_relative "../multilingual/multilingual"
require_relative "utils"
require_relative "render_word"
require_relative "navigation"
module Metanorma
class Collection
class Renderer
FORMATS = %i[html xml doc pdf].freeze
attr_accessor :isodoc, :nested
attr_reader :xml, :compile, :compile_options, :documents, :outdir,
:manifest
# This is only going to render the HTML collection
# @param xml [Metanorma::Collection] input XML collection
# @param folder [String] input folder
# @param options [Hash]
# @option options [String] :coverpage cover page HTML (Liquid template)
# @option options [Array] :format list of formats (xml,html,doc,pdf)
# @option options [String] :output_folder output directory
#
# We presuppose that the bibdata of the document is equivalent to that of
# the collection, and that the flavour gem can sensibly process it. We may
# need to enhance metadata in the flavour gems isodoc/metadata.rb with
# collection metadata
def initialize(collection, folder, options = {}) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
check_options options
@xml = Nokogiri::XML collection.to_xml # @xml is the collection manifest
@xml.root.default_namespace = "http://metanorma.org"
@lang = collection.bibdata.language.first || "en"
@script = collection.bibdata.script.first || "Latn"
@locale = @xml.at("//xmlns:bibdata/xmlns:locale")&.text
@registry = Metanorma::Registry.instance
@doctype = doctype
@compile = Compile.new
@compile.load_flavor(@doctype)
@isodoc = isodoc_create # output processor for flavour
@outdir = dir_name_cleanse(options[:output_folder])
@coverpage = options[:coverpage] || collection.coverpage
@format = ::Metanorma::Util.sort_extensions_execution(options[:format])
@compile_options = options[:compile] || {}
@compile_options[:install_fonts] = true if options[:install_fonts]
@log = options[:log]
@bibdata = collection.bibdata
@documents = collection.documents
@bibdatas = collection.documents
@directives = collection.directives
@dirname = collection.dirname
@manifest = collection.manifest.config
@disambig = Util::DisambigFiles.new
@prefatory = collection.prefatory
@final = collection.final
@c = HTMLEntities.new
@files_to_delete = []
@nested = options[:nested]
# if false, this is the root instance of Renderer
# if true, then this is not the last time Renderer will be run
# (e.g. this is sectionsplit)
# list of files in the collection
@files = Metanorma::Collection::FileLookup.new(folder, self)
@files.add_section_split
isodoc_populate
create_non_existing_directory(@outdir)
end
def flush_files
warn "\n\n\n\n\nDone: #{DateTime.now.strftime('%H:%M:%S')}"
warn @files.files_to_delete
@files.files_to_delete.each { |f| FileUtils.rm_f(f) }
@files_to_delete.each { |f| FileUtils.rm_f(f) }
end
# @param col [Metanorma::Collection] XML collection
# @param options [Hash]
# @option options [String] :coverpage cover page HTML (Liquid template)
# @option options [Array] :format list of formats
# @option options [Strong] :ourput_folder output directory
def self.render(col, options = {})
warn "\n\n\n\n\nRender Init: #{DateTime.now.strftime('%H:%M:%S')}"
cr = new(col, File.dirname(col.file), options)
cr.files
cr.concatenate(col, options)
options[:format]&.include?(:html) and cr.coverpage
cr.flush_files
cr
end
def concatenate(col, options)
warn "\n\n\n\n\nConcatenate: #{DateTime.now.strftime('%H:%M:%S')}"
concatenate_presentation?(options) and
options[:format] << :presentation
concatenate_prep(col, options)
concatenate_outputs(options)
end
def concatenate_presentation?(options)
!(options[:format] & %i(pdf doc)).empty? ||
(@directives.detect { |d| d.key == "bilingual" } &&
options[:format].include?(:html))
end
def concatenate_prep(col, options)
%i(xml presentation).each do |e|
options[:format].include?(e) or next
ext = e == :presentation ? "presentation.xml" : e.to_s
File.open(File.join(@outdir, "collection.#{ext}"), "w:UTF-8") do |f|
b = concatenate1(col.clone, e).to_xml
e == :presentation and b = concatenate_presentation(b)
f.write(b)
end
end
end
def concatenate_presentation(xml)
xml.sub!("", "")
# TODO BEING FORCED TO DO THAT BECAUSE SHALE IS NOT DEALING WITH DEFAULT NAMESPACES
@directives.detect { |d| d.key == "bilingual" } and
xml = Metanorma::Collection::Multilingual
.new({ align_cross_elements: %w(p note) }).to_bilingual(xml)
xml
end
def concatenate_outputs(options)
pres = File.join(@outdir, "collection.presentation.xml")
options[:format].include?(:pdf) and pdfconv.convert(pres)
options[:format].include?(:doc) and docconv_convert(pres)
@directives.detect { |d| d.key == "bilingual" } &&
options[:format].include?(:html) and
Metanorma::Collection::Multilingual.new(
{ doctype: doctype.to_sym,
converter_options: PdfOptionsNode.new(doctype, @compile_options),
outdir: @outdir },
).to_html(pres)
end
def concatenate1(out, ext)
out.directives << ::Metanorma::Collection::Config::Directive
.new(key: "documents-inline")
out.bibdatas.each_key do |ident|
id = @isodoc.docid_prefix(nil, ident.dup)
@files.get(id, :attachment) || @files.get(id, :outputs).nil? and next
out.documents[Util::key id] =
Metanorma::Collection::Document
.raw_file(@files.get(id, :outputs)[ext])
end
out
end
# infer the flavour from the first document identifier; relaton does that
def doctype
if (docid = @xml.at("//bibdata/docidentifier/@type")&.text)
dt = docid.downcase
elsif (docid = @xml.at("//bibdata/docidentifier")&.text)
dt = docid.sub(/\s.*$/, "").lowercase
else return "standoc"
end
@registry.alias(dt.to_sym)&.to_s || dt
end
# populate liquid template of ARGV[1] with metadata extracted from
# collection manifest
def coverpage
@coverpage or return
warn "\n\n\n\n\nCoverpage: #{DateTime.now.strftime('%H:%M:%S')}"
File.open(File.join(@outdir, "index.html"), "w:UTF-8") do |f|
f.write @isodoc.populate_template(File.read(@coverpage))
end
end
end
end
end