require "isodoc" require_relative "metadata" require "fileutils" require "roman-numerals" module IsoDoc module Unece # A {Converter} implementation that generates Word output, and a document # schema encapsulation of the document for validation class WordConvert < IsoDoc::WordConvert def initialize(options) @libdir = File.dirname(__FILE__) super @toc = options[:toc] FileUtils.cp html_doc_path('logo.jpg'), "logo.jpg" end def default_fonts(options) { bodyfont: (options[:script] == "Hans" ? '"SimSun",serif' : '"Times New Roman",serif'), headerfont: (options[:script] == "Hans" ? '"SimHei",sans-serif' : '"Times New Roman",serif'), monospacefont: '"Courier New",monospace' } end def default_file_locations(options) { wordstylesheet: html_doc_path("wordstyle.scss"), standardstylesheet: html_doc_path("unece.scss"), header: html_doc_path("header.html"), wordcoverpage: html_doc_path("word_unece_titlepage.html"), wordintropage: html_doc_path("word_unece_intro.html"), ulstyle: "l3", olstyle: "l2", } end def metadata_init(lang, script, labels) @meta = Metadata.new(lang, script, labels) @meta.set(:toc, @toc) end def footnotes(div) if @meta.get[:item_footnote] fn = noko do |xml| xml.aside **{ id: "ftnitem" } do |div| div.p @meta.get[:item_footnote] end end.join("\n") @footnotes.unshift fn end super end def make_body(xml, docxml) plenary = docxml.at(ns("//bibdata[@type = 'plenary']")) if plenary && @wordcoverpage == html_doc_path("word_unece_titlepage.html") @wordcoverpage = html_doc_path("word_unece_plenary_titlepage.html") end @wordintropage = nil if plenary && !@toc body_attr = { lang: "EN-US", link: "blue", vlink: "#954F72" } xml.body **body_attr do |body| make_body1(body, docxml) make_body2(body, docxml) make_body3(body, docxml) end end def make_body2(body, docxml) body.div **{ class: "WordSection2" } do |div2| info docxml, div2 abstract docxml, div2 foreword docxml, div2 introduction docxml, div2 div2.p { |p| p << " " } # placeholder end section_break(body) end ENDLINE = <<~END.freeze END def end_line(_isoxml, out) out.parent.add_child(ENDLINE) end def middle(isoxml, out) clause isoxml, out annex isoxml, out bibliography isoxml, out end_line(isoxml, out) end def clause_parse_title(node, div, c1, out) if node["inline-header"] == "true" inline_header_title(out, node, c1) else div.send "h#{get_anchors[node['id']][:level]}" do |h| lbl = get_anchors[node['id']][:label] h << "#{lbl}. " if lbl && !@suppressheadingnumbers insert_tab(h, 1) c1&.children&.each { |c2| parse(c2, h) } end end end def introduction(isoxml, out) f = isoxml.at(ns("//introduction")) || return out.div **{ class: "Section3", id: f["id"] } do |div| page_break(out) div.p(**{ class: "IntroTitle" }) do |h1| h1 << @introduction_lbl end f.elements.each do |e| parse(e, div) unless e.name == "title" end end end def foreword(isoxml, out) f = isoxml.at(ns("//foreword")) || return out.div **attr_code(id: f["id"]) do |s| page_break(out) s.p(**{ class: "ForewordTitle" }) do |h1| h1 << @foreword_lbl end f.elements.each { |e| parse(e, s) unless e.name == "title" } end end def word_preface(docxml) super preface_container = docxml.at("//div[@id = 'preface_container']") # recommendation abstractbox = docxml.at("//div[@id = 'abstractbox']") # plenary foreword = docxml.at("//p[@class = 'ForewordTitle']/..") intro = docxml.at("//p[@class = 'IntroTitle']/..") abstract = docxml.at("//p[@class = 'AbstractTitle']/..") abstract.parent = (abstractbox || preface_container) if abstract abstractbox and abstract&.xpath("./br")&.each do |a| a.remove if /page-break-before:always/.match(a["style"]) end docxml&.at("//p[@class = 'AbstractTitle']")&.remove if abstractbox foreword.parent = preface_container if foreword && preface_container intro.parent = preface_container if intro && preface_container if preface_container && (foreword || intro) preface_container.at("./div/br").remove # remove initial page break end if abstractbox && !intro && !foreword && !@toc sect2 = docxml.at("//div[@class='WordSection2']") sect2.next_element.remove # pagebreak sect2.remove # pagebreak end end # SAME as html_convert.rb from here on, starting with annex_name def annex_name(annex, name, div) div.h1 **{ class: "Annex" } do |t| t << "#{get_anchors[annex['id']][:label]}" t.br t.b do |b| name&.children&.each { |c2| parse(c2, b) } end end end def i18n_init(lang, script) super @admonition_lbl = "Box" @abstract_lbl = "Summary" end def fileloc(loc) File.join(File.dirname(__FILE__), loc) end MIDDLE_CLAUSE = "//clause[parent::sections]".freeze def initial_anchor_names(d) preface_names(d.at(ns("//foreword"))) preface_names(d.at(ns("//introduction"))) sequential_asset_names(d.xpath(ns("//foreword | //introduction"))) middle_section_asset_names(d) clause_names(d, 0) termnote_anchor_names(d) termexample_anchor_names(d) end def clause_names(docxml, sect_num) q = "//clause[parent::sections]" @paranumber = 0 docxml.xpath(ns(q)).each_with_index do |c, i| section_names(c, (i + sect_num), 1) end end def levelnumber(num, lvl) case lvl % 3 when 1 then RomanNumerals.to_roman(num) when 2 then ("A".ord + num - 1).chr when 0 then num.to_s end end def annex_levelnumber(num, lvl) case lvl % 3 when 0 then RomanNumerals.to_roman(num) when 1 then ("A".ord + num - 1).chr when 2 then num.to_s end end def leaf_section(clause, lvl) @paranumber += 1 @anchors[clause["id"]] = {label: @paranumber.to_s, xref: "paragraph #{@paranumber}", level: lvl, type: "paragraph" } end def annex_leaf_section(clause, num, lvl) @paranumber += 1 @anchors[clause["id"]] = {label: @paranumber.to_s, xref: "paragraph #{num}.#{@paranumber}", level: lvl, type: "paragraph" } end def section_names(clause, num, lvl) return num if clause.nil? clause.at(ns("./clause | ./term | ./terms | ./definitions")) or leaf_section(clause, lvl) && return num = num + 1 lbl = levelnumber(num, 1) @anchors[clause["id"]] = { label: lbl, xref: l10n("#{@clause_lbl} #{lbl}"), level: lvl, type: "clause" } i = 1 clause.xpath(ns("./clause | ./term | ./terms | ./definitions")).each do |c| section_names1(c, "#{lbl}.#{levelnumber(i, lvl + 1)}", lvl + 1) i += 1 if c.at(ns("./clause | ./term | ./terms | ./definitions")) end num end def section_names1(clause, num, level) unless clause.at(ns("./clause | ./term | ./terms | ./definitions")) leaf_section(clause, level) and return end /\.(?[^.]+$)/ =~ num @anchors[clause["id"]] = { label: leafnum, level: level, xref: l10n("#{@clause_lbl} #{num}"), type: "clause" } i = 1 clause.xpath(ns("./clause | ./terms | ./term | ./definitions")).each do |c| section_names1(c, "#{num}.#{levelnumber(i, level + 1)}", level + 1) i += 1 if c.at(ns("./clause | ./term | ./terms | ./definitions")) end end def annex_name_lbl(clause, num) l10n("#{@annex_lbl} #{num}") end def annex_names(clause, num) hierarchical_asset_names(clause, num) unless clause.at(ns("./clause | ./term | ./terms | ./definitions")) annex_leaf_section(clause, num, 1) and return end @anchors[clause["id"]] = { label: annex_name_lbl(clause, num), type: "clause", xref: "#{@annex_lbl} #{num}", level: 1 } i = 1 clause.xpath(ns("./clause")).each do |c| annex_names1(c, "#{num}.#{annex_levelnumber(i, 2)}", 2) i += 1 if c.at(ns("./clause | ./term | ./terms | ./definitions")) end end def annex_names1(clause, num, level) unless clause.at(ns("./clause | ./term | ./terms | ./definitions")) annex_leaf_section(clause, num, level) and return end /\.(?[^.]+$)/ =~ num @anchors[clause["id"]] = { label: leafnum, xref: "#{@annex_lbl} #{num}", level: level, type: "clause" } i = 1 clause.xpath(ns("./clause")).each do |c| annex_names1(c, "#{num}.#{annex_levelnumber(i, level + 1)}", level + 1) i += 1 if c.at(ns("./clause | ./term | ./terms | ./definitions")) end end def back_anchor_names(docxml) docxml.xpath(ns("//annex")).each_with_index do |c, i| @paranumber = 0 annex_names(c, RomanNumerals.to_roman(i + 1)) end docxml.xpath(ns("//bibitem[not(ancestor::bibitem)]")).each do |ref| reference_names(ref) end end def sequential_admonition_names(clause) i = 0 clause.xpath(ns(".//admonition")).each do |t| i += 1 next if t["id"].nil? || t["id"].empty? @anchors[t["id"]] = anchor_struct(i.to_s, nil, @admonition_lbl, "box") end end def hierarchical_admonition_names(clause, num) i = 0 clause.xpath(ns(".//admonition")).each do |t| i += 1 next if t["id"].nil? || t["id"].empty? @anchors[t["id"]] = anchor_struct("#{num}.#{i}", nil, @admonition_lbl, "box") end end def sequential_asset_names(clause) super sequential_admonition_names(clause) end def hierarchical_asset_names(clause, num) super hierarchical_admonition_names(clause, num) end def admonition_name_parse(node, div, name) div.p **{ class: "FigureTitle", align: "center" } do |p| p << l10n("#{@admonition_lbl} #{get_anchors[node['id']][:label]}") if name p << " — " name.children.each { |n| parse(n, div) } end end end def admonition_parse(node, out) name = node.at(ns("./name")) out.div **{ class: "Admonition" } do |t| admonition_name_parse(node, t, name) if name node.children.each do |n| parse(n, t) unless n.name == "name" end end end def inline_header_title(out, node, c1) title = c1&.content || "" out.span **{ class: "zzMoveToFollowing" } do |s| if get_anchors[node['id']][:label] s << "#{get_anchors[node['id']][:label]}. " unless @suppressheadingnumbers insert_tab(s, 1) end s << "#{title} " end end def abstract(isoxml, out) f = isoxml.at(ns("//abstract")) || return out.div **attr_code(id: f["id"]) do |s| page_break(out) s.p(**{ class: "AbstractTitle" }) { |h1| h1 << @abstract_lbl } f.elements.each { |e| parse(e, s) unless e.name == "title" } end end end end end