require "fileutils"
require "base64"
module IsoDoc::HtmlFunction
module Html
def make_body1(body, _docxml)
body.div **{ class: "title-section" } do |div1|
div1.p { |p| p << " " } # placeholder
end
section_break(body)
end
def make_body2(body, docxml)
body.div **{ class: "prefatory-section" } do |div2|
div2.p { |p| p << " " } # placeholder
end
section_break(body)
end
def make_body3(body, docxml)
body.div **{ class: "main-section" } do |div3|
abstract docxml, div3
foreword docxml, div3
introduction docxml, div3
middle docxml, div3
footnotes div3
comments div3
end
end
def postprocess(result, filename, dir)
result = from_xhtml(cleanup(to_xhtml(result)))
toHTML(result, filename)
@files_to_delete.each { |f| FileUtils.rm_rf f }
end
def script_cdata(result)
result.gsub(%r{}, "").
gsub(%r{]*)>}m, "\s*\]\]>}, "")
end
def toHTML(result, filename)
result = (from_xhtml(html_cleanup(to_xhtml(result))))
result = populate_template(result, :html)
result = script_cdata(from_xhtml(move_images(to_xhtml(result))))
File.open("#{filename}.html", "w:UTF-8") do |f|
f.write(result)
end
end
def html_cleanup(x)
footnote_backlinks(html_toc(
term_header((html_footnote_filter(html_preface(htmlstyle(x))))))
)
end
MATHJAX_ADDR =
"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/latest.js".freeze
MATHJAX = <<~"MATHJAX".freeze
MATHJAX
def mathjax(open, close)
MATHJAX.gsub("OPEN", open).gsub("CLOSE", close)
end
def term_header(docxml)
%w(h1 h2 h3 h4 h5 h6 h7 h8).each do |h|
docxml.xpath("//p[@class = 'TermNum'][../#{h}]").each do |p|
p.name = "h#{h[1].to_i + 1}"
end
end
docxml
end
def googlefonts()
<<~HEAD.freeze
HEAD
end
def toclevel
<<~HEAD.freeze
function toclevel() { var i; var text = "";
for(i = 1; i <= #{@htmlToClevels}; i++) {
if (i > 1) { text += ","; } text += "h" + i + ":not(:empty):not(.TermNum)"; }
return text;}
HEAD
end
def html_head()
<<~HEAD.freeze
{{ doctitle }}
#{googlefonts}
HEAD
end
def html_button()
''.freeze
end
def html_main(docxml)
docxml.at("//head").add_child(html_head())
d = docxml.at('//div[@class="main-section"]')
d.name = "main"
d.children.empty? or d.children.first.previous = html_button()
end
def sourcecode_highlighter
''
end
def sourcecodelang(lang)
return unless lang
case lang.downcase
when "javascript" then "lang-js"
when "c" then "lang-c"
when "c+" then "lang-cpp"
when "console" then "lang-bsh"
when "ruby" then "lang-rb"
when "html" then "lang-html"
when "java" then "lang-java"
when "xml" then "lang-xml"
when "perl" then "lang-perl"
when "python" then "lang-py"
when "xsl" then "lang-xsl"
else
""
end
end
def sourcecode_parse(node, out)
name = node.at(ns("./name"))
out.pre **attr_code(id: node["id"],
class: "prettyprint #{sourcecodelang(node&.at(ns('./@lang'))&.value)}") do |div|
@sourcecode = true
node.children.each do |n|
parse(n, div) unless n.name == "name"
end
@sourcecode = false
sourcecode_name_parse(node, div, name) if name
end
end
def html_preface(docxml)
html_cover(docxml) if @htmlcoverpage
html_intro(docxml) if @htmlintropage
docxml.at("//body") << mathjax(@openmathdelim, @closemathdelim)
docxml.at("//body") << sourcecode_highlighter
if @scripts
scripts = File.read(@scripts, encoding: "UTF-8")
a = docxml.at("//body").add_child docxml.create_cdata(scripts)
end
html_main(docxml)
docxml
end
def html_cover(docxml)
cover = File.read(@htmlcoverpage, encoding: "UTF-8")
coverxml = to_xhtml_fragment(cover)
d = docxml.at('//div[@class="title-section"]')
d.children.first.add_previous_sibling coverxml.to_xml(encoding: "US-ASCII")
end
def html_intro(docxml)
intro = File.read(@htmlintropage, encoding: "UTF-8")
introxml = to_xhtml_fragment(intro)
d = docxml.at('//div[@class="prefatory-section"]')
d.children.first.add_previous_sibling introxml.to_xml(encoding: "US-ASCII")
end
def htmlstylesheet
stylesheet = File.read(@htmlstylesheet, encoding: "UTF-8")
xml = Nokogiri::XML("")
xml.children.first << Nokogiri::XML::Comment.new(xml, "\n#{stylesheet}\n")
xml.root.to_s
end
def htmlstyle(docxml)
return docxml unless @htmlstylesheet
title = docxml.at("//*[local-name() = 'head']/*[local-name() = 'title']")
head = docxml.at("//*[local-name() = 'head']")
css = htmlstylesheet
if title.nil? then head.children.first.add_previous_sibling css
else
title.add_next_sibling css
end
docxml
end
def update_footnote_filter(fn, x, i, seen)
if seen[fn.text]
x.at("./sup").content = seen[fn.text][:num].to_s
fn.remove unless x["href"] == seen[fn.text][:href]
x["href"] = seen[fn.text][:href]
else
seen[fn.text] = { num: i, href: x["href"] }
x.at("./sup").content = i.to_s
i += 1
end
[i, seen]
end
def html_footnote_filter(docxml)
seen = {}
i = 1
docxml.xpath('//a[@epub:type = "footnote"]').each do |x|
fn = docxml.at(%/*[@id = '#{x['href'].sub(/^#/, '')}']>) || next
i, seen = update_footnote_filter(fn, x, i, seen)
end
docxml
end
def footnote_backlinks(docxml)
seen = {}
docxml.xpath('//a[@epub:type = "footnote"]').each_with_index do |x, i|
next if seen[x["href"]]
seen[x["href"]] = true
fn = docxml.at(%/*[@id = '#{x['href'].sub(/^#/, '')}']>) || next
x["id"] || x["id"] = "fnref:#{i + 1}"
fn.elements.first.children.first.previous = x.dup
fn.add_child "↩"
end
docxml
end
# presupposes that the image source is local
def move_images(docxml)
FileUtils.rm_rf tmpimagedir
FileUtils.mkdir tmpimagedir
docxml.xpath("//*[local-name() = 'img']").each do |i|
next if /^data:image/.match i["src"]
@datauriimage ? datauri(i) : move_image1(i)
end
docxml
end
def datauri(i)
type = i["src"].split(".")[-1]
bin = IO.binread(File.join(@localdir, i["src"]))
data = Base64.strict_encode64(bin)
i["src"] = "data:image/#{type};base64,#{data}"
end
def move_image1(i)
matched = /\.(?[^. \r\n\t]+)$/.match i["src"]
uuid = UUIDTools::UUID.random_create.to_s
fname = "#{uuid}.#{matched[:suffix]}"
new_full_filename = File.join(tmpimagedir, fname)
local_filename = File.join(@localdir, i["src"])
FileUtils.cp local_filename, new_full_filename
i["src"] = File.join(rel_tmpimagedir, fname)
i["width"], i["height"] = Html2Doc.image_resize(i, local_filename, @maxheight, @maxwidth)
end
def html_toc_entry(level, header)
%(