Top Level Namespace
Defined Under Namespace
Constant Summary collapse
- COMMENT_IN_COMMENT_LIST1 =
COMMENT_IN_COMMENT_LIST =
'//div[@style="mso-element:comment-list"]//'\ 'span[@style="MsoCommentReference"]'.freeze
- COMMENT_TARGET_XREFS1 =
COMMENT_TARGET_XREFS =
"//span[@style='mso-special-character:comment']/@target".freeze
- SW1 =
SW1 = IsoDoc::SW
"solid windowtext".freeze
- WORD_TOC_PREFACE1 =
WORD_TOC_PREFACE = <<~TOC.freeze
<<~TOC.freeze <span lang="EN-GB"><span style='mso-element:field-begin'></span><span style='mso-spacerun:yes'> </span>TOC \\o "1-2" \\h \\z \\u <span style='mso-element:field-separator'></span></span> TOC
- WORD_TOC_SUFFIX1 =
WORD_TOC_SUFFIX = <<~TOC.freeze
<<~TOC.freeze <p class="MsoToc1"><span lang="EN-GB"><span style='mso-element:field-end'></span></span><span lang="EN-GB"><o:p> </o:p></span></p> TOC
Instance Method Summary collapse
- #comment_attributes(docxml, x) ⇒ Object
- #comment_cleanup(docxml) ⇒ Object
- #comment_link_attrs(fn, node) ⇒ Object
- #comments(div) ⇒ Object
- #dl_parse(node, out) ⇒ Object
- #dt_parse(dt, term) ⇒ Object
- #embed_comment_in_comment_list(docxml) ⇒ Object
- #footnote_parse(node, out) ⇒ Object
-
#footnotes(div) ⇒ Object
base.class_eval do.
- #generate_header(filename, _dir) ⇒ Object
- #get_comments_from_text(docxml, link_order) ⇒ Object
- #get_table_ancestor_id(node) ⇒ Object
-
#in_comment ⇒ Object
base.class_eval do.
- #insert_comment_cont(from, to, target) ⇒ Object
-
#insert_tab(out, n) ⇒ Object
module IsoDoc class WordConvert < Convert module WordConvertModule def self.included base base.class_eval do.
-
#make_comment_link(out, fn, node) ⇒ Object
add in from and to links to move the comment into place.
- #make_comment_target(out) ⇒ Object
- #make_comment_text(node, fn) ⇒ Object
- #make_generic_footnote_text(node, fnid) ⇒ Object
- #make_table_footnote_link(out, fnid, fnref) ⇒ Object
- #make_table_footnote_target(out, fnid, fnref) ⇒ Object
- #make_table_footnote_text(node, fnid, fnref) ⇒ Object
- #make_tr_attr(td, row, totalrows) ⇒ Object
- #make_WordToC(docxml) ⇒ Object
- #move_comment_link_to_from(docxml) ⇒ Object
- #move_comment_link_to_from1(x, fromlink) ⇒ Object
- #new_fullcolspan_row(t, tfoot) ⇒ Object
- #page_break(out) ⇒ Object
- #para_attrs(node) ⇒ Object
- #postprocess(result, filename, dir) ⇒ Object
- #remove_bottom_border(td) ⇒ Object
- #reorder_comments_by_comment_link(docxml) ⇒ Object
- #review_note_parse(node, out) ⇒ Object
- #section_break(body) ⇒ Object
- #skip_comment_wrap(from) ⇒ Object
- #table_footnote_parse(node, out) ⇒ Object
- #toWord(result, filename, dir) ⇒ Object
-
#word_annex_cleanup(docxml) ⇒ Object
force Annex h2 to be p.h2Annex, so it is not picked up by ToC.
- #word_cleanup(docxml) ⇒ Object
- #word_cover(docxml) ⇒ Object
- #word_intro(docxml) ⇒ Object
- #word_preface(docxml) ⇒ Object
- #word_toc_entry(toclevel, heading) ⇒ Object
- #wrap_comment_cont(from, target) ⇒ Object
Instance Method Details
#comment_attributes(docxml, x) ⇒ Object
91 92 93 94 95 96 97 |
# File 'lib/isodoc/wordconvert/comments.rb', line 91 def comment_attributes(docxml, x) fromlink = docxml.at("//*[@id='#{x['from']}']") return(nil) if fromlink.nil? tolink = docxml.at("//*[@id='#{x['to']}']") || fromlink target = docxml.at("//*[@id='#{x['target']}']") { from: fromlink, to: tolink, target: target } end |
#comment_cleanup(docxml) ⇒ Object
64 65 66 67 68 |
# File 'lib/isodoc/wordconvert/comments.rb', line 64 def comment_cleanup(docxml) move_comment_link_to_from(docxml) reorder_comments_by_comment_link(docxml) (docxml) end |
#comment_link_attrs(fn, node) ⇒ Object
28 29 30 31 32 |
# File 'lib/isodoc/wordconvert/comments.rb', line 28 def comment_link_attrs(fn, node) { style: "MsoCommentReference", target: fn, class: "commentLink", from: node["from"], to: node["to"] } end |
#comments(div) ⇒ Object
13 14 15 16 17 18 |
# File 'lib/isodoc/wordconvert/comments.rb', line 13 def comments(div) return if @comments.empty? div.div **{ style: "mso-element:comment-list" } do |div1| @comments.each { |fn| div1.parent << fn } end end |
#dl_parse(node, out) ⇒ Object
85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/isodoc/wordconvert/wordconvertmodule.rb', line 85 def dl_parse(node, out) out.table **{ class: "dl" } do |v| node.elements.each_slice(2) do |dt, dd| v.tr do |tr| tr.td **{ valign: "top", align: "left" } do |term| dt_parse(dt, term) end tr.td **{ valign: "top" } do |listitem| dd.children.each { |n| parse(n, listitem) } end end end end end |
#dt_parse(dt, term) ⇒ Object
74 75 76 77 78 79 80 81 82 83 |
# File 'lib/isodoc/wordconvert/wordconvertmodule.rb', line 74 def dt_parse(dt, term) if dt.elements.empty? term.p **attr_code(class: note? ? "Note" : nil, style: "text-align: left;") do |p| p << dt.text end else dt.children.each { |n| parse(n, term) } end end |
#embed_comment_in_comment_list(docxml) ⇒ Object
75 76 77 78 79 80 81 82 |
# File 'lib/isodoc/wordconvert/comments.rb', line 75 def (docxml) #docxml.xpath(COMMENT_IN_COMMENT_LIST).each do |x| docxml.xpath(COMMENT_IN_COMMENT_LIST1).each do |x| n = x.next_element n&.children&.first&.add_previous_sibling(x.remove) end docxml end |
#footnote_parse(node, out) ⇒ Object
65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/isodoc/wordconvert/footnotes.rb', line 65 def footnote_parse(node, out) return table_footnote_parse(node, out) if @in_table || @in_figure fn = node["reference"] out.a **{ "epub:type": "footnote", href: "#ftn#{fn}" } do |a| a.sup { |sup| sup << fn } end return if @seen_footnote.include?(fn) @in_footnote = true @footnotes << make_generic_footnote_text(node, fn) @in_footnote = false @seen_footnote << fn end |
#footnotes(div) ⇒ Object
base.class_eval do
9 10 11 12 |
# File 'lib/isodoc/wordconvert/footnotes.rb', line 9 def footnotes(div) return if @footnotes.empty? @footnotes.each { |fn| div.parent << fn } end |
#generate_header(filename, _dir) ⇒ Object
149 150 151 152 153 154 155 156 157 158 |
# File 'lib/isodoc/wordconvert/wordconvertmodule.rb', line 149 def generate_header(filename, _dir) return unless @header template = Liquid::Template.parse(File.read(@header, encoding: "UTF-8")) = [:filename] = filename params = .map { |k, v| [k.to_s, v] }.to_h File.open("header.html", "w") do |f| f.write(template.render(params)) end end |
#get_comments_from_text(docxml, link_order) ⇒ Object
128 129 130 131 132 133 134 135 136 |
# File 'lib/isodoc/wordconvert/comments.rb', line 128 def get_comments_from_text(docxml, link_order) comments = [] docxml.xpath("//div[@style='mso-element:comment']").each do |c| next unless c["id"] && !link_order[c["id"]].nil? comments << { text: c.remove.to_s, id: c["id"] } end comments.sort! { |a, b| link_order[a[:id]] <=> link_order[b[:id]] } # comments end |
#get_table_ancestor_id(node) ⇒ Object
47 48 49 50 51 |
# File 'lib/isodoc/wordconvert/footnotes.rb', line 47 def get_table_ancestor_id(node) table = node.ancestors("table") || node.ancestors("figure") return UUIDTools::UUID.random_create.to_s if table.empty? table.last["id"] end |
#in_comment ⇒ Object
base.class_eval do
9 10 11 |
# File 'lib/isodoc/wordconvert/comments.rb', line 9 def in_comment @in_comment end |
#insert_comment_cont(from, to, target) ⇒ Object
108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/isodoc/wordconvert/comments.rb', line 108 def insert_comment_cont(from, to, target) # includes_to = from.at(".//*[@id='#{to}']") while !from.nil? && from["id"] != to following = from.xpath("./following::*") (from = following.shift) && incl_to = from.at(".//*[@id='#{to}']") while !incl_to.nil? && !from.nil? && skip_comment_wrap(from) (from = following.shift) && incl_to = from.at(".//*[@id='#{to}']") end wrap_comment_cont(from, target) if !from.nil? end end |
#insert_tab(out, n) ⇒ Object
module IsoDoc class WordConvert < Convert module WordConvertModule def self.included base base.class_eval do
10 11 12 13 14 |
# File 'lib/isodoc/wordconvert/wordconvertmodule.rb', line 10 def insert_tab(out, n) out.span **attr_code(style: "mso-tab-count:#{n}") do |span| [1..n].each { span << "  " } end end |
#make_comment_link(out, fn, node) ⇒ Object
add in from and to links to move the comment into place
35 36 37 38 39 40 41 42 43 44 |
# File 'lib/isodoc/wordconvert/comments.rb', line 35 def make_comment_link(out, fn, node) out.span(**comment_link_attrs(fn, node)) do |s1| s1.span **{ lang: "EN-GB", style: "font-size:9.0pt" } do |s2| s2.a **{ style: "mso-comment-reference:SMC_#{fn};"\ "mso-comment-date:#{node['date']}" } s2.span **{ style: "mso-special-character:comment", target: fn } # do |s| end end end |
#make_comment_target(out) ⇒ Object
46 47 48 49 50 51 52 |
# File 'lib/isodoc/wordconvert/comments.rb', line 46 def make_comment_target(out) out.span **{ style: "MsoCommentReference" } do |s1| s1.span **{ lang: "EN-GB", style: "font-size:9.0pt" } do |s2| s2.span **{ style: "mso-special-character:comment" } end end end |
#make_comment_text(node, fn) ⇒ Object
54 55 56 57 58 59 60 61 62 |
# File 'lib/isodoc/wordconvert/comments.rb', line 54 def make_comment_text(node, fn) noko do |xml| xml.div **{ style: "mso-element:comment", id: fn } do |div| div.span **{ style: %{mso-comment-author:"#{node['reviewer']}"} } make_comment_target(div) node.children.each { |n| parse(n, div) } end end.join("\n") end |
#make_generic_footnote_text(node, fnid) ⇒ Object
39 40 41 42 43 44 45 |
# File 'lib/isodoc/wordconvert/footnotes.rb', line 39 def make_generic_footnote_text(node, fnid) noko do |xml| xml.aside **{ id: "ftn#{fnid}" } do |div| node.children.each { |n| parse(n, div) } end end.join("\n") end |
#make_table_footnote_link(out, fnid, fnref) ⇒ Object
14 15 16 17 18 19 |
# File 'lib/isodoc/wordconvert/footnotes.rb', line 14 def make_table_footnote_link(out, fnid, fnref) attrs = { href: "##{fnid}", class: "TableFootnoteRef" } out.a **attrs do |a| a << fnref end end |
#make_table_footnote_target(out, fnid, fnref) ⇒ Object
21 22 23 24 25 26 27 |
# File 'lib/isodoc/wordconvert/footnotes.rb', line 21 def make_table_footnote_target(out, fnid, fnref) attrs = { id: fnid, class: "TableFootnoteRef" } out.a **attrs do |a| a << fnref insert_tab(a, 1) end end |
#make_table_footnote_text(node, fnid, fnref) ⇒ Object
29 30 31 32 33 34 35 36 37 |
# File 'lib/isodoc/wordconvert/footnotes.rb', line 29 def make_table_footnote_text(node, fnid, fnref) attrs = { id: "ftn#{fnid}" } noko do |xml| xml.div **attr_code(attrs) do |div| make_table_footnote_target(div, fnid, fnref) node.children.each { |n| parse(n, div) } end end.join("\n") end |
#make_tr_attr(td, row, totalrows) ⇒ Object
50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/isodoc/wordconvert/wordconvertmodule.rb', line 50 def make_tr_attr(td, row, totalrows) style = td.name == "th" ? "font-weight:bold;" : "" rowmax = td["rowspan"] ? row + td["rowspan"].to_i - 1 : row style += <<~STYLE border-top:#{row.zero? ? "#{SW1} 1.5pt;" : 'none;'} mso-border-top-alt:#{row.zero? ? "#{SW1} 1.5pt;" : 'none;'} border-bottom:#{SW1} #{rowmax == totalrows ? '1.5' : '1.0'}pt; mso-border-bottom-alt:#{SW1} #{rowmax == totalrows ? '1.5' : '1.0'}pt; STYLE { rowspan: td["rowspan"], colspan: td["colspan"], align: td["align"], style: style.gsub(/\n/, "") } end |
#make_WordToC(docxml) ⇒ Object
199 200 201 202 203 204 205 206 207 208 |
# File 'lib/isodoc/wordconvert/wordconvertmodule.rb', line 199 def make_WordToC(docxml) toc = "" docxml.xpath("//h1 | //h2[not(ancestor::*[@class = 'Section3'])]"). each do |h| toc += word_toc_entry(h.name == "h1" ? 1 : 2, header_strip(h)) end toc.sub(/(<p class="MsoToc1">)/, #%{\\1#{WORD_TOC_PREFACE}}) + WORD_TOC_SUFFIX %{\\1#{WORD_TOC_PREFACE1}}) + WORD_TOC_SUFFIX1 end |
#move_comment_link_to_from(docxml) ⇒ Object
120 121 122 123 124 125 126 |
# File 'lib/isodoc/wordconvert/comments.rb', line 120 def move_comment_link_to_from(docxml) docxml.xpath('//span[@style="MsoCommentReference"][@from]').each do |x| attrs = comment_attributes(docxml, x) || next move_comment_link_to_from1(x, attrs[:from]) insert_comment_cont(attrs[:from], x["to"], x["target"]) end end |
#move_comment_link_to_from1(x, fromlink) ⇒ Object
84 85 86 87 88 89 |
# File 'lib/isodoc/wordconvert/comments.rb', line 84 def move_comment_link_to_from1(x, fromlink) x.remove link = x.at(".//a") fromlink.replace(x) link.children = fromlink end |
#new_fullcolspan_row(t, tfoot) ⇒ Object
38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/isodoc/wordconvert/wordconvertmodule.rb', line 38 def new_fullcolspan_row(t, tfoot) # how many columns in the table? cols = 0 t.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 |
#page_break(out) ⇒ Object
67 68 69 70 71 72 |
# File 'lib/isodoc/wordconvert/wordconvertmodule.rb', line 67 def page_break(out) out.br **{ clear: "all", style: "mso-special-character:line-break;page-break-before:always", } end |
#para_attrs(node) ⇒ Object
16 17 18 19 20 21 22 23 24 25 26 27 |
# File 'lib/isodoc/wordconvert/wordconvertmodule.rb', line 16 def para_attrs(node) classtype = nil classtype = "Note" if @note classtype = "MsoCommentText" if in_comment classtype = "Sourcecode" if @annotation attrs = { class: classtype, id: node["id"] } unless node["align"].nil? attrs[:align] = node["align"] unless node["align"] == "justify" attrs[:style] = "text-align:#{node['align']}" end attrs end |
#postprocess(result, filename, dir) ⇒ Object
102 103 104 105 106 |
# File 'lib/isodoc/wordconvert/wordconvertmodule.rb', line 102 def postprocess(result, filename, dir) generate_header(filename, dir) result = from_xhtml(cleanup(to_xhtml(result))) toWord(result, filename, dir) end |
#remove_bottom_border(td) ⇒ Object
29 30 31 32 33 |
# File 'lib/isodoc/wordconvert/wordconvertmodule.rb', line 29 def remove_bottom_border(td) td["style"] = td["style"].gsub(/border-bottom:[^;]+;/, "border-bottom:0pt;"). gsub(/mso-border-bottom-alt:[^;]+;/, "mso-border-bottom-alt:0pt;") end |
#reorder_comments_by_comment_link(docxml) ⇒ Object
142 143 144 145 146 147 148 149 150 151 |
# File 'lib/isodoc/wordconvert/comments.rb', line 142 def reorder_comments_by_comment_link(docxml) link_order = {} #docxml.xpath(COMMENT_TARGET_XREFS).each_with_index do |target, i| docxml.xpath(COMMENT_TARGET_XREFS1).each_with_index do |target, i| link_order[target.value] = i end comments = get_comments_from_text(docxml, link_order) list = docxml.at("//*[@style='mso-element:comment-list']") || return list.children = comments.map { |c| c[:text] }.join("\n") end |
#review_note_parse(node, out) ⇒ Object
20 21 22 23 24 25 26 |
# File 'lib/isodoc/wordconvert/comments.rb', line 20 def review_note_parse(node, out) fn = @comments.length + 1 make_comment_link(out, fn, node) @in_comment = true @comments << make_comment_text(node, fn) @in_comment = false end |
#section_break(body) ⇒ Object
63 64 65 |
# File 'lib/isodoc/wordconvert/wordconvertmodule.rb', line 63 def section_break(body) body.br **{ clear: "all", class: "section" } end |
#skip_comment_wrap(from) ⇒ Object
104 105 106 |
# File 'lib/isodoc/wordconvert/comments.rb', line 104 def skip_comment_wrap(from) from["style"] != "mso-special-character:comment" end |
#table_footnote_parse(node, out) ⇒ Object
53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/isodoc/wordconvert/footnotes.rb', line 53 def table_footnote_parse(node, out) fn = node["reference"] tid = get_table_ancestor_id(node) make_table_footnote_link(out, tid + fn, fn) # do not output footnote text if we have already seen it for this table return if @seen_footnote.include?(tid + fn) @in_footnote = true out.aside { |a| a << make_table_footnote_text(node, tid + fn, fn) } @in_footnote = false @seen_footnote << (tid + fn) end |
#toWord(result, filename, dir) ⇒ Object
108 109 110 111 112 113 114 115 |
# File 'lib/isodoc/wordconvert/wordconvertmodule.rb', line 108 def toWord(result, filename, dir) result = from_xhtml(word_cleanup(to_xhtml(result))) result = populate_template(result, :word) Html2Doc.process(result, filename: filename, stylesheet: @wordstylesheet, header_file: "header.html", dir: dir, asciimathdelims: [@openmathdelim, @closemathdelim], liststyles: { ul: @ulstyle, ol: @olstyle }) end |
#word_annex_cleanup(docxml) ⇒ Object
force Annex h2 to be p.h2Annex, so it is not picked up by ToC
124 125 126 127 128 129 |
# File 'lib/isodoc/wordconvert/wordconvertmodule.rb', line 124 def word_annex_cleanup(docxml) docxml.xpath("//h2[ancestor::*[@class = 'Section3']]").each do |h2| h2.name = "p" h2["class"] = "h2Annex" end end |
#word_cleanup(docxml) ⇒ Object
117 118 119 120 121 |
# File 'lib/isodoc/wordconvert/wordconvertmodule.rb', line 117 def word_cleanup(docxml) word_preface(docxml) word_annex_cleanup(docxml) docxml end |
#word_cover(docxml) ⇒ Object
136 137 138 139 140 |
# File 'lib/isodoc/wordconvert/wordconvertmodule.rb', line 136 def word_cover(docxml) cover = to_xhtml_fragment(File.read(@wordcoverpage, encoding: "UTF-8")) docxml.at('//div[@class="WordSection1"]').children.first.previous = cover.to_xml(encoding: "US-ASCII") end |
#word_intro(docxml) ⇒ Object
142 143 144 145 146 147 |
# File 'lib/isodoc/wordconvert/wordconvertmodule.rb', line 142 def word_intro(docxml) intro = to_xhtml_fragment(File.read(@wordintropage, encoding: "UTF-8"). sub(/WORDTOC/, make_WordToC(docxml))) docxml.at('//div[@class="WordSection2"]').children.first.previous = intro.to_xml(encoding: "US-ASCII") end |
#word_preface(docxml) ⇒ Object
131 132 133 134 |
# File 'lib/isodoc/wordconvert/wordconvertmodule.rb', line 131 def word_preface(docxml) word_cover(docxml) if @wordcoverpage word_intro(docxml) if @wordintropage end |
#word_toc_entry(toclevel, heading) ⇒ Object
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/isodoc/wordconvert/wordconvertmodule.rb', line 160 def word_toc_entry(toclevel, heading) bookmark = Random.rand(1000000000) <<~TOC <p class="MsoToc#{toclevel}"><span class="MsoHyperlink"><span lang="EN-GB" style='mso-no-proof:yes'> <a href="#_Toc#{bookmark}">#{heading}<span lang="EN-GB" class="MsoTocTextSpan"> <span style='mso-tab-count:1 dotted'>. </span> </span><span lang="EN-GB" class="MsoTocTextSpan"> <span style='mso-element:field-begin'></span></span> <span lang="EN-GB" class="MsoTocTextSpan"> PAGEREF _Toc#{bookmark} \\h </span> <span lang="EN-GB" class="MsoTocTextSpan"><span style='mso-element:field-separator'></span></span><span lang="EN-GB" class="MsoTocTextSpan">1</span> <span lang="EN-GB" class="MsoTocTextSpan"></span><span lang="EN-GB" class="MsoTocTextSpan"><span style='mso-element:field-end'></span></span></a></span></span></p> TOC end |
#wrap_comment_cont(from, target) ⇒ Object
99 100 101 102 |
# File 'lib/isodoc/wordconvert/comments.rb', line 99 def wrap_comment_cont(from, target) s = from.replace("<span style='mso-comment-continuation:#{target}'>") s.first.children = from end |