Module: IsoDoc::WordFunction::Body

Included in:
IsoDoc::WordConvert
Defined in:
lib/isodoc/word_function/body.rb,
lib/isodoc/word_function/lists.rb,
lib/isodoc/word_function/table.rb,
lib/isodoc/word_function/inline.rb

Constant Summary collapse

MAIN_ELEMENTS =
"//sections/*[@displayorder] | //annex[@displayorder] | " \
"//bibliography/*[@displayorder] | //colophon/*[@displayorder] | " \
"//indexsect[@displayorder]".freeze
WORD_DT_ATTRS =
{ class: @note ? "Note" : nil, align: "left",
style: "margin-left:0pt;text-align:left;" }.freeze
WORD_EMBED_DL_ATTRS =
"text-indent: -2.0cm; margin-left: 2.0cm; tab-stops: 2.0cm;".freeze
SW1 =
"solid windowtext".freeze

Instance Method Summary collapse

Instance Method Details

#body_attrObject



26
27
28
# File 'lib/isodoc/word_function/body.rb', line 26

def body_attr
  { lang: "EN-US", link: "blue", vlink: "#954F72" }
end

#colgroup(node, table) ⇒ Object



86
87
88
89
90
91
92
93
# File 'lib/isodoc/word_function/table.rb', line 86

def colgroup(node, table)
  colgroup = node.at(ns("./colgroup")) or return
  table.colgroup do |cg|
    colgroup.xpath(ns("./col")).each do |c|
      cg.col width: c["width"]
    end
  end
end

#convert1_namespaces(html) ⇒ Object



8
9
10
11
12
13
14
# File 'lib/isodoc/word_function/body.rb', line 8

def convert1_namespaces(html)
  super
  html.add_namespace("v", "urn:schemas-microsoft-com:vml")
  html.add_namespace("o", "urn:schemas-microsoft-com:office:office")
  html.add_namespace("w", "urn:schemas-microsoft-com:office:word")
  html.add_namespace("m", "http://schemas.microsoft.com/office/2004/12/omml")
end

#ddef_first_para(out, ddef) ⇒ Object



49
50
51
52
53
54
55
# File 'lib/isodoc/word_function/lists.rb', line 49

def ddef_first_para(out, ddef)
  if ddef.elements&.first&.name == "p"
    ddef.children.first.children.each { |n| parse(n, out) }
  else
    ddef.children.each { |n| parse(n, out) }
  end
end

#ddef_other_paras(out, ddef) ⇒ Object



57
58
59
60
# File 'lib/isodoc/word_function/lists.rb', line 57

def ddef_other_paras(out, ddef)
  ddef.elements&.first&.name == "p" or return
  ddef.children[1..-1].each { |n| parse(n, out) }
end

#define_head(head, filename, _dir) ⇒ Object



16
17
18
19
20
21
22
23
24
# File 'lib/isodoc/word_function/body.rb', line 16

def define_head(head, filename, _dir)
  head.style do |style|
    loc = File.join(File.dirname(__FILE__), "..", "base_style",
                    "metanorma_word.scss")
    stylesheet = File.read(loc, encoding: "utf-8")
    style.comment "\n#{stylesheet}\n"
  end
  super
end

#dl_parse(node, out) ⇒ Object



20
21
22
23
24
# File 'lib/isodoc/word_function/lists.rb', line 20

def dl_parse(node, out)
  node.ancestors("table, dl").empty? or
    return dl_parse_nontable(node, out)
  dl_parse_table(node, out)
end

#dl_parse_nontable(node, out) ⇒ Object



26
27
28
29
30
31
32
33
34
# File 'lib/isodoc/word_function/lists.rb', line 26

def dl_parse_nontable(node, out)
  node["id"] and bookmark_parse(node, out)
  list_title_parse(node, out)
  node.elements.select { |n| dt_dd?(n) }
    .each_slice(2) do |dt, dd|
    dl_parse_nontable1(out, dt, dd)
  end
  dl_parse_notes(node, out)
end

#dl_parse_nontable1(out, dterm, ddef) ⇒ Object



39
40
41
42
43
44
45
46
47
# File 'lib/isodoc/word_function/lists.rb', line 39

def dl_parse_nontable1(out, dterm, ddef)
  out.p **attr_code(style: WORD_EMBED_DL_ATTRS, id: dterm["id"]) do |p|
    dterm.children.each { |n| parse(n, p) }
    insert_tab(p, 1)
    ddef["id"] and bookmark_parse(ddef, out)
    ddef_first_para(out, ddef)
  end
  ddef_other_paras(out, ddef)
end

#dl_parse_table(node, out) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
# File 'lib/isodoc/word_function/lists.rb', line 62

def dl_parse_table(node, out)
  list_title_parse(node, out)
  out.table **attr_code(id: node["id"],
                        class: (node["class"] || "dl")) do |v|
    node.elements.select { |n| dt_dd?(n) }
      .each_slice(2) do |dt, dd|
      dl_parse_table1(v, dt, dd)
    end
    dl_parse_table_notes(node, v)
  end
end

#dl_parse_table1(table, dterm, ddefn) ⇒ Object



74
75
76
77
78
79
80
81
82
83
# File 'lib/isodoc/word_function/lists.rb', line 74

def dl_parse_table1(table, dterm, ddefn)
  table.tr do |tr|
    tr.td valign: "top", align: "left" do |term|
      dt_parse(dterm, term)
    end
    tr.td valign: "top" do |listitem|
      ddefn.children.each { |n| parse(n, listitem) }
    end
  end
end

#dl_parse_table_notes(node, out) ⇒ Object



85
86
87
88
89
90
91
92
93
# File 'lib/isodoc/word_function/lists.rb', line 85

def dl_parse_table_notes(node, out)
  remainder = node.elements.reject { |n| dt_dd?(n) || n.name == "name" }
  remainder.empty? and return
  out.tr do |tr|
    tr.td colspan: 2 do |td|
      remainder.each { |n| parse(n, td) }
    end
  end
end

#dt_parse(dterm, term) ⇒ Object



10
11
12
13
14
15
16
17
18
# File 'lib/isodoc/word_function/lists.rb', line 10

def dt_parse(dterm, term)
  term.p **attr_code(WORD_DT_ATTRS) do |p|
    if dterm.elements.empty?
      p << dterm.text
    else
      dterm.children.each { |n| parse(n, p) }
    end
  end
end

#emf_attributes(node) ⇒ Object



53
54
55
56
57
58
59
60
61
# File 'lib/isodoc/word_function/inline.rb', line 53

def emf_attributes(node)
  if emf = node.at(ns("./emf"))
    node["src"] = emf["src"]
    node["height"] ||= emf["height"]
    node["width"] ||= emf["width"]
    node["mimetype"] = "image/x-emf"
    node.children.remove
  end
end

#example_table_attr(node) ⇒ Object



152
153
154
155
156
157
158
159
160
# File 'lib/isodoc/word_function/body.rb', line 152

def example_table_attr(node)
  super.merge(
    style: "mso-table-lspace:15.0cm;margin-left:423.0pt;" \
           "mso-table-rspace:15.0cm;margin-right:423.0pt;" \
           "mso-table-anchor-horizontal:column;" \
           "mso-table-overlap:never;border-collapse:collapse;" \
           "#{keep_style(node)}",
  )
end

#figure_aside_process(fig, aside, key) ⇒ Object

get rid of footnote link, it is in diagram



92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/isodoc/word_function/body.rb', line 92

def figure_aside_process(fig, aside, key)
  fig.at("./a[@class='TableFootnoteRef']")&.remove
  fnref = fig.at(".//span[@class='TableFootnoteRef']/..")
  tr = key.add_child("<tr></tr>").first
  dt = tr.add_child("<td valign='top' align='left'></td>").first
  dd = tr.add_child("<td valign='top'></td>").first
  fnref.parent = dt
  aside.xpath(".//p").each do |a|
    a.delete("class")
    a.parent = dd
  end
end

#figure_get_or_make_dl(node) ⇒ Object



82
83
84
85
86
87
88
89
# File 'lib/isodoc/word_function/body.rb', line 82

def figure_get_or_make_dl(node)
  dl = node.at(".//table[@class = 'dl']")
  if dl.nil?
    node.add_child("<p><b>#{@i18n.key}</b></p><table class='dl'></table>")
    dl = node.at(".//table[@class = 'dl']")
  end
  dl
end

#formula_parse1(node, out) ⇒ Object



162
163
164
165
166
167
168
169
170
171
172
# File 'lib/isodoc/word_function/body.rb', line 162

def formula_parse1(node, out)
  out.div **attr_code(class: "formula") do |div|
    div.p do |_p|
      parse(node.at(ns("./stem")), div)
      insert_tab(div, 1)
      if lbl = node&.at(ns("./name"))&.text
        div << "(#{lbl})"
      end
    end
  end
end

#image_parse(node, out, caption) ⇒ Object



44
45
46
47
48
49
50
51
# File 'lib/isodoc/word_function/inline.rb', line 44

def image_parse(node, out, caption)
  emf_attributes(node)
  attrs = { src: imgsrc(node),
            height: node["height"], alt: node["alt"],
            title: node["title"], width: node["width"] }
  out.img **attr_code(attrs)
  image_title_parse(out, caption)
end

#imgsrc(node) ⇒ Object



38
39
40
41
42
# File 'lib/isodoc/word_function/inline.rb', line 38

def imgsrc(node)
  return node["src"] unless %r{^data:}.match? node["src"]

  save_dataimage(node["src"])
end

#info(xml, out) ⇒ Object



174
175
176
177
178
179
180
181
182
# File 'lib/isodoc/word_function/body.rb', line 174

def info(xml, out)
  @tocfigurestitle =
    xml.at(ns("//metanorma-extension/toc[@type = 'figure']/title"))&.text
  @toctablestitle =
    xml.at(ns("//metanorma-extension/toc[@type = 'table']/title"))&.text
  @tocrecommendationstitle = xml
    .at(ns("//metanorma-extension/toc[@type = 'recommendation']/title"))&.text
  super
end

#insert_tab(out, count) ⇒ Object



4
5
6
7
8
# File 'lib/isodoc/word_function/inline.rb', line 4

def insert_tab(out, count)
  out.span **attr_code(style: "mso-tab-count:#{count}") do |span|
    [1..count].each { span << "&#xA0; " }
  end
end

#keep_rows_together(_cell, rowmax, totalrows, opt) ⇒ Object



46
47
48
49
50
# File 'lib/isodoc/word_function/table.rb', line 46

def keep_rows_together(_cell, rowmax, totalrows, opt)
  opt[:header] and return true
  @table_line_count > 15 and return false
  (totalrows <= 10 && rowmax < totalrows)
end

#li_parse(node, out) ⇒ Object



95
96
97
98
99
100
101
102
103
104
# File 'lib/isodoc/word_function/lists.rb', line 95

def li_parse(node, out)
  out.li **attr_code(id: node["id"]) do |li|
    if node["uncheckedcheckbox"] == "true"
      li << '<span class="zzMoveToFollowing">&#x2610; </span>'
    elsif node["checkedcheckbox"] == "true"
      li << '<span class="zzMoveToFollowing">&#x2611; </span>'
    end
    node.children.each { |n| parse(n, li) }
  end
end

#make_body1(body, _docxml) ⇒ Object



30
31
32
33
34
35
# File 'lib/isodoc/word_function/body.rb', line 30

def make_body1(body, _docxml)
  body.div class: "WordSection1" do |div1|
    div1.p { |p| p << "&#xa0;" } # placeholder
  end
  section_break(body)
end

#make_body2(body, docxml) ⇒ Object



37
38
39
40
41
42
43
44
# File 'lib/isodoc/word_function/body.rb', line 37

def make_body2(body, docxml)
  body.div class: "WordSection2" do |div2|
    boilerplate docxml, div2
    content(div2, docxml, ns("//preface/*[@displayorder]"))
    div2.p { |p| p << "&#xa0;" } # placeholder
  end
  section_break(body)
end

#make_body3(body, docxml) ⇒ Object



51
52
53
54
55
56
57
# File 'lib/isodoc/word_function/body.rb', line 51

def make_body3(body, docxml)
  body.div class: "WordSection3" do |div3|
    content(div3, docxml, ns(self.class::MAIN_ELEMENTS))
    footnotes div3
    comments div3
  end
end

#make_tr_attr(cell, row, totalrows, header, bordered) ⇒ Object



24
25
26
27
28
29
30
31
32
# File 'lib/isodoc/word_function/table.rb', line 24

def make_tr_attr(cell, row, totalrows, header, bordered)
  style = cell.name == "th" ? "font-weight:bold;" : ""
  rowmax = cell["rowspan"] ? row + cell["rowspan"].to_i - 1 : row
  style += make_tr_attr_style(cell, row, rowmax, totalrows,
                              { header: header, bordered: bordered })
  { rowspan: cell["rowspan"], colspan: cell["colspan"],
    valign: cell["valign"], align: cell["align"], style: style,
    class: cell["class"] }
end

#make_tr_attr_style(cell, row, rowmax, totalrows, opt) ⇒ Object



34
35
36
37
38
39
40
41
42
43
44
# File 'lib/isodoc/word_function/table.rb', line 34

def make_tr_attr_style(cell, row, rowmax, totalrows, opt)
  top = row.zero? ? "#{SW1} 1.5pt;" : "none;"
  bottom = "#{SW1} #{rowmax >= totalrows ? '1.5' : '1.0'}pt;"
  ret = <<~STYLE.gsub(/\n/, "")
    border-top:#{top}mso-border-top-alt:#{top}
    border-bottom:#{bottom}mso-border-bottom-alt:#{bottom}
  STYLE
  opt[:bordered] or ret = ""
  pb = keep_rows_together(cell, rowmax, totalrows, opt) ? "avoid" : "auto"
  "#{ret}page-break-after:#{pb};"
end

#new_fullcolspan_row(table, tfoot) ⇒ Object



12
13
14
15
16
17
18
19
20
21
22
# File 'lib/isodoc/word_function/table.rb', line 12

def new_fullcolspan_row(table, tfoot)
  # how many columns in the table?
  cols = 0
  table.at(".//tr").xpath("./td | ./th").each do |td|
    cols += (td["colspan"] ? td["colspan"].to_i : 1)
  end
  style = "border-top:0pt;mso-border-top-alt:0pt;" \
          "border-bottom:#{SW1} 1.5pt;mso-border-bottom-alt:#{SW1} 1.5pt;"
  tfoot.add_child("<tr><td colspan='#{cols}' style='#{style}'/></tr>")
  tfoot.xpath(".//td").last
end

#note_p_parse(node, div) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
# File 'lib/isodoc/word_function/body.rb', line 105

def note_p_parse(node, div)
  name = node.at(ns("./name"))&.remove
  div.p class: "Note" do |p|
    p.span class: "note_label" do |s|
      name&.children&.each { |n| parse(n, s) }
    end
    insert_tab(p, 1)
    node.first_element_child.children.each { |n| parse(n, p) }
  end
  node.element_children[1..-1].each { |n| parse(n, div) }
end

#note_parse1(node, div) ⇒ Object



117
118
119
120
121
122
123
124
125
126
# File 'lib/isodoc/word_function/body.rb', line 117

def note_parse1(node, div)
  name = node.at(ns("./name"))&.remove
  div.p class: "Note" do |p|
    p.span class: "note_label" do |s|
      name&.children&.each { |n| parse(n, s) }
    end
    insert_tab(p, 1)
  end
  node.children.each { |n| parse(n, div) }
end

#page_break(out) ⇒ Object



21
22
23
24
25
26
27
# File 'lib/isodoc/word_function/inline.rb', line 21

def page_break(out)
  out.p class: "page-break" do |p|
    p.br clear: "all",
         style: "mso-special-character:line-break;" \
                "page-break-before:always"
  end
end

#pagebreak_parse(node, out) ⇒ Object



29
30
31
32
33
34
35
36
# File 'lib/isodoc/word_function/inline.rb', line 29

def pagebreak_parse(node, out)
  return page_break(out) if node["orientation"].nil?

  out.p do |p|
    p.br clear: "all", class: "section",
         orientation: node["orientation"]
  end
end

#para_attrs(node) ⇒ Object



141
142
143
144
145
146
147
148
149
150
# File 'lib/isodoc/word_function/body.rb', line 141

def para_attrs(node)
  attrs = { class: para_class(node), id: node["id"], style: "" }
  unless node["align"].nil?
    attrs[:align] = node["align"] unless node["align"] == "justify"
    attrs[:style] += "text-align:#{node['align']};"
  end
  attrs[:style] += keep_style(node).to_s
  attrs[:style] = nil if attrs[:style].empty?
  attrs
end

#para_class(node) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
# File 'lib/isodoc/word_function/body.rb', line 59

def para_class(node)
  return "Sourcecode" if @annotation
  return "MsoCommentText" if @in_comment
  return "Note" if @note
  if node["type"] == "floating-title"
    return "h#{node['depth']}"
  end

  n = node["class"] and return n
  nil
end

#para_parse(node, out) ⇒ Object



71
72
73
74
75
76
77
78
79
80
# File 'lib/isodoc/word_function/body.rb', line 71

def para_parse(node, out)
  out.p **attr_code(para_attrs(node)) do |p|
    unless @termdomain.empty?
      p << "&#x3c;#{@termdomain}&#x3e; "
      @termdomain = ""
    end
    node.children.each { |n| parse(n, p) unless n.name == "note" }
  end
  node.xpath(ns("./note")).each { |n| parse(n, out) }
end

#remove_bottom_border(cell) ⇒ Object



4
5
6
7
8
# File 'lib/isodoc/word_function/table.rb', line 4

def remove_bottom_border(cell)
  cell["style"] =
    cell["style"].gsub(/border-bottom:[^;]+;/, "border-bottom:0pt;")
      .gsub(/mso-border-bottom-alt:[^;]+;/, "mso-border-bottom-alt:0pt;")
end

#rt_parse(node, out) ⇒ Object



92
93
94
95
96
# File 'lib/isodoc/word_function/inline.rb', line 92

def rt_parse(node, out)
  out.rt **{ style: "font-size: 6pt;" } do |e|
    node.children.each { |n| parse(n, e) }
  end
end

#ruby_parse(node, out) ⇒ Object



81
82
83
84
85
86
87
88
89
90
# File 'lib/isodoc/word_function/inline.rb', line 81

def ruby_parse(node, out)
  if r = node.at(ns("./rb[ruby]"))
    double_ruby = r.at(ns("./ruby/rt")).remove
    r.replace(r.at(ns("./ruby/rb")))
  end
  out.ruby do |e|
    node.children.each { |n| parse(n, e) }
  end
  double_ruby and out << "(#{double_ruby.text})"
end

#section_break(body, continuous: false) ⇒ Object



10
11
12
13
14
15
16
17
18
19
# File 'lib/isodoc/word_function/inline.rb', line 10

def section_break(body, continuous: false)
  body.p class: "section-break" do |p|
    if continuous
      p.br clear: "all", style: "page-break-before:auto;" \
                                "mso-break-type:section-break"
    else
      p.br clear: "all", class: "section"
    end
  end
end

#suffix_url(url) ⇒ Object



74
75
76
77
78
79
# File 'lib/isodoc/word_function/inline.rb', line 74

def suffix_url(url)
  return url if url.nil? || %r{^https?://|^#}.match?(url)
  return url unless File.extname(url).empty?

  url.sub(/#{File.extname(url)}$/, ".doc")
end

#table_attrs(node) ⇒ Object



72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/isodoc/word_function/table.rb', line 72

def table_attrs(node)
  c = node["class"]
  bordered = "border-spacing:0;border-width:1px;"
  (%w(modspec).include?(c) || !c) or bordered = nil
  ret = {
    summary: node["summary"], width: node["width"],
    style: "mso-table-anchor-horizontal:column;mso-table-overlap:never;" \
           "#{bordered}#{keep_style(node)}",
    class: (node.text.length > 4000 ? "MsoISOTableBig" : "MsoISOTable")
  }
  bordered or ret.delete(:class)
  super.merge(attr_code(ret))
end

#table_line_count(tbody) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/isodoc/word_function/table.rb', line 58

def table_line_count(tbody)
  sum = 0
  tbody.xpath(ns(".//tr")).size > 15 and return 16 # short-circuit
  tbody.xpath(ns(".//tr")).each do |r|
    i = 1
    r.xpath(ns(".//td | .//th")).each do |c|
      n = c.xpath(ns(".//li | .//p | .//br")).size
      n > i and i = n
    end
    sum += i
  end
  sum
end

#table_of_contents(clause, out) ⇒ Object



184
185
186
187
188
189
190
191
192
193
194
# File 'lib/isodoc/word_function/body.rb', line 184

def table_of_contents(clause, out)
  page_break(out)
  out.div **attr_code(preface_attrs(clause)) do |div|
    div.p class: "zzContents" do |p|
      clause.at(ns("./title"))&.children&.each { |c| parse(c, p) }
    end
    clause.elements.each do |e|
      parse(e, div) unless e.name == "title"
    end
  end
end

#table_parse(node, out) ⇒ Object



95
96
97
98
99
100
101
102
103
104
105
# File 'lib/isodoc/word_function/table.rb', line 95

def table_parse(node, out)
  @in_table = true
  table_title_parse(node, out)
  out.div align: "center", class: "table_container" do |div|
    div.table **table_attrs(node) do |t|
      table_parse_core(node, t)
      table_parse_tail(node, t)
    end
  end
  @in_table = false
end

#table_parse_core(node, out) ⇒ Object



107
108
109
110
111
112
# File 'lib/isodoc/word_function/table.rb', line 107

def table_parse_core(node, out)
  colgroup(node, out)
  thead_parse(node, out)
  tbody_parse(node, out)
  tfoot_parse(node, out)
end

#tbody_parse(node, table) ⇒ Object



52
53
54
55
56
# File 'lib/isodoc/word_function/table.rb', line 52

def tbody_parse(node, table)
  tbody = node.at(ns("./tbody")) or return
  @table_line_count = table_line_count(tbody)
  super
end

#termnote_parse(node, out) ⇒ Object



128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/isodoc/word_function/body.rb', line 128

def termnote_parse(node, out)
  name = node&.at(ns("./name"))&.remove
  out.div **note_attrs(node) do |div|
    div.p class: "Note" do |p|
      if name
        name.children.each { |n| parse(n, p) }
        p << termnote_delim
      end
      para_then_remainder(node.first_element_child, node, p, div)
    end
  end
end

#xref_parse(node, out) ⇒ Object



63
64
65
66
67
68
69
70
71
72
# File 'lib/isodoc/word_function/inline.rb', line 63

def xref_parse(node, out)
  target = if /#/.match?(node["target"])
             node["target"].sub("#", ".doc#")
           else
             "##{node['target']}"
           end
  out.a(href: target) do |l|
    node.children.each { |n| parse(n, l) }
  end
end