isodoc 1.7.4 → 1.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/isodoc.gemspec +7 -5
- data/lib/isodoc/class_utils.rb +25 -2
- data/lib/isodoc/convert.rb +2 -0
- data/lib/isodoc/function/to_word_html.rb +2 -1
- data/lib/isodoc/function/utils.rb +34 -14
- data/lib/isodoc/html_function/comments.rb +107 -111
- data/lib/isodoc/html_function/footnotes.rb +68 -67
- data/lib/isodoc/html_function/html.rb +113 -103
- data/lib/isodoc/presentation_function/block.rb +73 -78
- data/lib/isodoc/presentation_function/concept.rb +68 -0
- data/lib/isodoc/presentation_function/image.rb +112 -0
- data/lib/isodoc/presentation_function/inline.rb +20 -49
- data/lib/isodoc/presentation_xml_convert.rb +1 -0
- data/lib/isodoc/version.rb +1 -1
- data/lib/isodoc/word_function/body.rb +176 -174
- data/lib/isodoc/word_function/comments.rb +117 -112
- data/lib/isodoc/word_function/footnotes.rb +88 -86
- data/lib/isodoc/word_function/inline.rb +42 -67
- data/lib/isodoc/word_function/postprocess_cover.rb +121 -110
- data/lib/isodoc/xref/xref_gen.rb +153 -150
- data/lib/isodoc/xref/xref_sect_gen.rb +134 -129
- data/lib/isodoc/xslfo_convert.rb +7 -6
- data/spec/assets/i18n.yaml +3 -1
- data/spec/assets/odf.svg +1 -4
- data/spec/isodoc/blocks_spec.rb +229 -157
- data/spec/isodoc/i18n_spec.rb +3 -3
- data/spec/isodoc/inline_spec.rb +304 -105
- data/spec/isodoc/postproc_spec.rb +38 -0
- data/spec/isodoc/presentation_xml_spec.rb +60 -0
- data/spec/isodoc/section_spec.rb +125 -0
- data/spec/isodoc/terms_spec.rb +116 -0
- data/spec/isodoc/xslfo_convert_spec.rb +16 -4
- metadata +57 -27
@@ -1,129 +1,139 @@
|
|
1
1
|
require "fileutils"
|
2
2
|
require "base64"
|
3
3
|
|
4
|
-
module IsoDoc
|
5
|
-
module
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
4
|
+
module IsoDoc
|
5
|
+
module HtmlFunction
|
6
|
+
module Html
|
7
|
+
def convert1(docxml, filename, dir)
|
8
|
+
noko do |xml|
|
9
|
+
xml.html **{ lang: @lang.to_s } do |html|
|
10
|
+
info docxml, nil
|
11
|
+
populate_css
|
12
|
+
html.head { |head| define_head head, filename, dir }
|
13
|
+
make_body(html, docxml)
|
14
|
+
end
|
15
|
+
end.join("\n")
|
16
|
+
end
|
16
17
|
|
17
|
-
|
18
|
-
|
18
|
+
def make_body1(body, _docxml)
|
19
|
+
return if @bare
|
19
20
|
|
20
|
-
|
21
|
-
|
21
|
+
body.div **{ class: "title-section" } do |div1|
|
22
|
+
div1.p { |p| p << " " } # placeholder
|
23
|
+
end
|
24
|
+
section_break(body)
|
22
25
|
end
|
23
|
-
section_break(body)
|
24
|
-
end
|
25
26
|
|
26
|
-
|
27
|
-
|
27
|
+
def make_body2(body, _docxml)
|
28
|
+
return if @bare
|
28
29
|
|
29
|
-
|
30
|
-
|
30
|
+
body.div **{ class: "prefatory-section" } do |div2|
|
31
|
+
div2.p { |p| p << " " } # placeholder
|
32
|
+
end
|
33
|
+
section_break(body)
|
31
34
|
end
|
32
|
-
section_break(body)
|
33
|
-
end
|
34
35
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
36
|
+
def make_body3(body, docxml)
|
37
|
+
body.div **{ class: "main-section" } do |div3|
|
38
|
+
boilerplate docxml, div3
|
39
|
+
preface_block docxml, div3
|
40
|
+
abstract docxml, div3
|
41
|
+
foreword docxml, div3
|
42
|
+
introduction docxml, div3
|
43
|
+
preface docxml, div3
|
44
|
+
acknowledgements docxml, div3
|
45
|
+
middle docxml, div3
|
46
|
+
footnotes div3
|
47
|
+
comments div3
|
48
|
+
end
|
47
49
|
end
|
48
|
-
end
|
49
50
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
51
|
+
def googlefonts
|
52
|
+
<<~HEAD.freeze
|
53
|
+
<link href="https://fonts.googleapis.com/css?family=Overpass:300,300i,600,900" rel="stylesheet">
|
54
|
+
<link href="https://fonts.googleapis.com/css?family=Lato:400,400i,700,900" rel="stylesheet">
|
55
|
+
HEAD
|
56
|
+
end
|
56
57
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
58
|
+
def html_head
|
59
|
+
<<~HEAD.freeze
|
60
|
+
<title>#{@meta&.get&.dig(:doctitle)}</title>
|
61
|
+
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
|
62
|
+
|
63
|
+
<!--TOC script import-->
|
64
|
+
<script type="text/javascript" src="https://cdn.rawgit.com/jgallen23/toc/0.3.2/dist/toc.min.js"></script>
|
65
|
+
<script type="text/javascript">#{toclevel}</script>
|
66
|
+
|
67
|
+
<!--Google fonts-->
|
68
|
+
<link rel="preconnect" href="https://fonts.gstatic.com">#{' '}
|
69
|
+
#{googlefonts}
|
70
|
+
<!--Font awesome import for the link icon-->
|
71
|
+
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.8/css/solid.css" integrity="sha384-v2Tw72dyUXeU3y4aM2Y0tBJQkGfplr39mxZqlTBDUZAb9BGoC40+rdFCG0m10lXk" crossorigin="anonymous">
|
72
|
+
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.8/css/fontawesome.css" integrity="sha384-q3jl8XQu1OpdLgGFvNRnPdj5VIlCvgsDQTQB6owSOHWlAurxul7f+JpUOVdAiJ5P" crossorigin="anonymous">
|
73
|
+
<style class="anchorjs"></style>
|
74
|
+
HEAD
|
75
|
+
end
|
75
76
|
|
76
|
-
|
77
|
-
|
77
|
+
def html_button
|
78
|
+
return "" if @bare
|
78
79
|
|
79
|
-
|
80
|
+
'<button onclick="topFunction()" id="myBtn" '\
|
80
81
|
'title="Go to top">Top</button>'.freeze
|
81
|
-
|
82
|
+
end
|
82
83
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
84
|
+
def html_main(docxml)
|
85
|
+
docxml.at("//head").add_child(html_head)
|
86
|
+
d = docxml.at('//div[@class="main-section"]')
|
87
|
+
d.name = "main"
|
88
|
+
d.children.empty? or d.children.first.previous = html_button
|
89
|
+
end
|
89
90
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
91
|
+
def sourcecodelang(lang)
|
92
|
+
return unless lang
|
93
|
+
|
94
|
+
case lang.downcase
|
95
|
+
when "javascript" then "lang-js"
|
96
|
+
when "c" then "lang-c"
|
97
|
+
when "c+" then "lang-cpp"
|
98
|
+
when "console" then "lang-bsh"
|
99
|
+
when "ruby" then "lang-rb"
|
100
|
+
when "html" then "lang-html"
|
101
|
+
when "java" then "lang-java"
|
102
|
+
when "xml" then "lang-xml"
|
103
|
+
when "perl" then "lang-perl"
|
104
|
+
when "python" then "lang-py"
|
105
|
+
when "xsl" then "lang-xsl"
|
106
|
+
else
|
107
|
+
""
|
108
|
+
end
|
107
109
|
end
|
108
|
-
end
|
109
110
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
111
|
+
def sourcecode_parse(node, out)
|
112
|
+
name = node.at(ns("./name"))
|
113
|
+
class1 = "prettyprint #{sourcecodelang(node&.at(ns('./@lang'))&.value)}"
|
114
|
+
out.pre **sourcecode_attrs(node).merge(class: class1) do |div|
|
115
|
+
@sourcecode = true
|
116
|
+
node.children.each { |n| parse(n, div) unless n.name == "name" }
|
117
|
+
@sourcecode = false
|
118
|
+
end
|
119
|
+
sourcecode_name_parse(node, out, name)
|
117
120
|
end
|
118
|
-
sourcecode_name_parse(node, out, name)
|
119
|
-
end
|
120
121
|
|
121
|
-
|
122
|
-
|
123
|
-
|
122
|
+
def underline_parse(node, out)
|
123
|
+
out.span **{ style: "text-decoration: underline;" } do |e|
|
124
|
+
node.children.each { |n| parse(n, e) }
|
125
|
+
end
|
124
126
|
end
|
125
|
-
end
|
126
127
|
|
127
|
-
|
128
|
+
def table_long_strings_cleanup(docxml); end
|
129
|
+
|
130
|
+
def image_parse(node, out, caption)
|
131
|
+
if svg = node.at("./m:svg", "m" => "http://www.w3.org/2000/svg")
|
132
|
+
svg_parse(svg, out)
|
133
|
+
return
|
134
|
+
end
|
135
|
+
super
|
136
|
+
end
|
137
|
+
end
|
128
138
|
end
|
129
139
|
end
|
@@ -1,55 +1,24 @@
|
|
1
|
-
|
1
|
+
require_relative "./image"
|
2
2
|
|
3
3
|
module IsoDoc
|
4
4
|
class PresentationXMLConvert < ::IsoDoc::Convert
|
5
|
-
def lower2cap(
|
6
|
-
return
|
5
|
+
def lower2cap(text)
|
6
|
+
return text if /^[[:upper:]][[:upper:]]/.match?(text)
|
7
7
|
|
8
|
-
|
8
|
+
text.capitalize
|
9
9
|
end
|
10
10
|
|
11
|
-
def
|
12
|
-
docxml.xpath(ns("//image")).each { |f| svg_extract(f) }
|
13
|
-
docxml.xpath(ns("//figure")).each { |f| figure1(f) }
|
14
|
-
docxml.xpath(ns("//svgmap")).each do |s|
|
15
|
-
if f = s.at(ns("./figure")) then s.replace(f)
|
16
|
-
else
|
17
|
-
s.remove
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def svg_extract(elem)
|
23
|
-
return unless %r{^data:image/svg\+xml;base64,}.match?(elem["src"])
|
24
|
-
|
25
|
-
svg = Base64.strict_decode64(elem["src"]
|
26
|
-
.sub(%r{^data:image/svg\+xml;base64,}, ""))
|
27
|
-
x = Nokogiri::XML.fragment(svg.sub(/<\?xml[^>]*>/, "")) do |config|
|
28
|
-
config.huge
|
29
|
-
end
|
30
|
-
elem.replace(x)
|
31
|
-
end
|
32
|
-
|
33
|
-
def figure1(f)
|
34
|
-
return sourcecode1(f) if f["class"] == "pseudocode" || f["type"] == "pseudocode"
|
35
|
-
return if labelled_ancestor(f) && f.ancestors("figure").empty?
|
36
|
-
return if f.at(ns("./figure")) and !f.at(ns("./name"))
|
37
|
-
|
38
|
-
lbl = @xrefs.anchor(f['id'], :label, false) or return
|
39
|
-
prefix_name(f, " — ",
|
40
|
-
l10n("#{lower2cap @i18n.figure} #{lbl}"), "name")
|
41
|
-
end
|
42
|
-
|
43
|
-
def prefix_name(f, delim, number, elem)
|
11
|
+
def prefix_name(node, delim, number, elem)
|
44
12
|
return if number.nil? || number.empty?
|
45
13
|
|
46
|
-
unless name =
|
47
|
-
|
48
|
-
|
49
|
-
|
14
|
+
unless name = node.at(ns("./#{elem}"))
|
15
|
+
node.children.empty? and node.add_child("<#{elem}></#{elem}>") or
|
16
|
+
node.children.first.previous = "<#{elem}></#{elem}>"
|
17
|
+
name = node.children.first
|
18
|
+
end
|
19
|
+
if name.children.empty? then name.add_child(number)
|
20
|
+
else (name.children.first.previous = "#{number}#{delim}")
|
50
21
|
end
|
51
|
-
name.children.empty? ? name.add_child(number) :
|
52
|
-
( name.children.first.previous = "#{number}#{delim}" )
|
53
22
|
end
|
54
23
|
|
55
24
|
def sourcecode(docxml)
|
@@ -58,12 +27,13 @@ module IsoDoc
|
|
58
27
|
end
|
59
28
|
end
|
60
29
|
|
61
|
-
def sourcecode1(
|
62
|
-
return if labelled_ancestor(
|
63
|
-
return unless
|
30
|
+
def sourcecode1(elem)
|
31
|
+
return if labelled_ancestor(elem)
|
32
|
+
return unless elem.ancestors("example").empty?
|
64
33
|
|
65
|
-
lbl = @xrefs.anchor(
|
66
|
-
prefix_name(
|
34
|
+
lbl = @xrefs.anchor(elem["id"], :label, false) or return
|
35
|
+
prefix_name(elem, " — ",
|
36
|
+
l10n("#{lower2cap @i18n.figure} #{lbl}"), "name")
|
67
37
|
end
|
68
38
|
|
69
39
|
def formula(docxml)
|
@@ -73,9 +43,9 @@ module IsoDoc
|
|
73
43
|
end
|
74
44
|
|
75
45
|
# introduce name element
|
76
|
-
def formula1(
|
77
|
-
lbl = @xrefs.anchor(
|
78
|
-
prefix_name(
|
46
|
+
def formula1(elem)
|
47
|
+
lbl = @xrefs.anchor(elem["id"], :label, false)
|
48
|
+
prefix_name(elem, "", lbl, "name")
|
79
49
|
end
|
80
50
|
|
81
51
|
def example(docxml)
|
@@ -90,11 +60,14 @@ module IsoDoc
|
|
90
60
|
end
|
91
61
|
end
|
92
62
|
|
93
|
-
def example1(
|
94
|
-
n = @xrefs.get[
|
95
|
-
lbl =
|
96
|
-
|
97
|
-
|
63
|
+
def example1(elem)
|
64
|
+
n = @xrefs.get[elem["id"]]
|
65
|
+
lbl = if n.nil? || n[:label].nil? || n[:label].empty?
|
66
|
+
@i18n.example
|
67
|
+
else
|
68
|
+
l10n("#{@i18n.example} #{n[:label]}")
|
69
|
+
end
|
70
|
+
prefix_name(elem, " — ", lbl, "name")
|
98
71
|
end
|
99
72
|
|
100
73
|
def note(docxml)
|
@@ -104,13 +77,16 @@ module IsoDoc
|
|
104
77
|
end
|
105
78
|
|
106
79
|
# introduce name element
|
107
|
-
def note1(
|
108
|
-
return if
|
80
|
+
def note1(elem)
|
81
|
+
return if elem.parent.name == "bibitem"
|
109
82
|
|
110
|
-
n = @xrefs.get[
|
111
|
-
lbl =
|
112
|
-
|
113
|
-
|
83
|
+
n = @xrefs.get[elem["id"]]
|
84
|
+
lbl = if n.nil? || n[:label].nil? || n[:label].empty?
|
85
|
+
@i18n.note
|
86
|
+
else
|
87
|
+
l10n("#{@i18n.note} #{n[:label]}")
|
88
|
+
end
|
89
|
+
prefix_name(elem, "", lbl, "name")
|
114
90
|
end
|
115
91
|
|
116
92
|
def termnote(docxml)
|
@@ -120,9 +96,27 @@ module IsoDoc
|
|
120
96
|
end
|
121
97
|
|
122
98
|
# introduce name element
|
123
|
-
def termnote1(
|
124
|
-
lbl = l10n(@xrefs.anchor(
|
125
|
-
prefix_name(
|
99
|
+
def termnote1(elem)
|
100
|
+
lbl = l10n(@xrefs.anchor(elem["id"], :label) || "???")
|
101
|
+
prefix_name(elem, "", lower2cap(lbl), "name")
|
102
|
+
end
|
103
|
+
|
104
|
+
def termdefinition(docxml)
|
105
|
+
docxml.xpath(ns("//term[definition]")).each do |f|
|
106
|
+
termdefinition1(f)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def termdefinition1(elem)
|
111
|
+
return unless elem.xpath(ns("./definition")).size > 1
|
112
|
+
|
113
|
+
d = elem.at(ns("./definition"))
|
114
|
+
d = d.replace("<ol><li>#{d.children.to_xml}</li></ol>").first
|
115
|
+
elem.xpath(ns("./definition")).each do |f|
|
116
|
+
f = f.replace("<li>#{f.children.to_xml}</li>").first
|
117
|
+
d << f
|
118
|
+
end
|
119
|
+
d.wrap("<definition></definition>")
|
126
120
|
end
|
127
121
|
|
128
122
|
def recommendation(docxml)
|
@@ -144,10 +138,10 @@ module IsoDoc
|
|
144
138
|
end
|
145
139
|
|
146
140
|
# introduce name element
|
147
|
-
def recommendation1(
|
148
|
-
n = @xrefs.anchor(
|
141
|
+
def recommendation1(elem, type)
|
142
|
+
n = @xrefs.anchor(elem["id"], :label, false)
|
149
143
|
lbl = (n.nil? ? type : l10n("#{type} #{n}"))
|
150
|
-
prefix_name(
|
144
|
+
prefix_name(elem, "", lbl, "name")
|
151
145
|
end
|
152
146
|
|
153
147
|
def table(docxml)
|
@@ -156,12 +150,13 @@ module IsoDoc
|
|
156
150
|
end
|
157
151
|
end
|
158
152
|
|
159
|
-
def table1(
|
160
|
-
return if labelled_ancestor(
|
161
|
-
return if
|
153
|
+
def table1(elem)
|
154
|
+
return if labelled_ancestor(elem)
|
155
|
+
return if elem["unnumbered"] && !elem.at(ns("./name"))
|
162
156
|
|
163
|
-
n = @xrefs.anchor(
|
164
|
-
prefix_name(
|
157
|
+
n = @xrefs.anchor(elem["id"], :label, false)
|
158
|
+
prefix_name(elem, " — ", l10n("#{lower2cap @i18n.table} #{n}"),
|
159
|
+
"name")
|
165
160
|
end
|
166
161
|
|
167
162
|
# we use this to eliminate the semantic amend blocks from rendering
|
@@ -171,11 +166,11 @@ module IsoDoc
|
|
171
166
|
end
|
172
167
|
end
|
173
168
|
|
174
|
-
def amend1(
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
169
|
+
def amend1(elem)
|
170
|
+
elem.xpath(ns("./autonumber")).each(&:remove)
|
171
|
+
elem.xpath(ns("./newcontent")).each { |a| a.name = "quote" }
|
172
|
+
elem.xpath(ns("./description")).each { |a| a.replace(a.children) }
|
173
|
+
elem.replace(elem.children)
|
179
174
|
end
|
180
175
|
end
|
181
176
|
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module IsoDoc
|
2
|
+
class PresentationXMLConvert < ::IsoDoc::Convert
|
3
|
+
def concept(docxml)
|
4
|
+
docxml.xpath(ns("//concept")).each { |f| concept1(f) }
|
5
|
+
end
|
6
|
+
|
7
|
+
def concept1(node)
|
8
|
+
xref = node&.at(ns("./xref/@target"))&.text or
|
9
|
+
return concept_render(node, ital: node["ital"] || "true",
|
10
|
+
ref: node["ref"] || "true",
|
11
|
+
linkref: node["linkref"] || "true",
|
12
|
+
linkmention: node["linkmention"] || "false")
|
13
|
+
if node.at(ns("//definitions//dt[@id = '#{xref}']"))
|
14
|
+
concept_render(node, ital: node["ital"] || "false",
|
15
|
+
ref: node["ref"] || "false",
|
16
|
+
linkref: node["linkref"] || "true",
|
17
|
+
linkmention: node["linkmention"] || "false")
|
18
|
+
else concept_render(node, ital: node["ital"] || "true",
|
19
|
+
ref: node["ref"] || "true",
|
20
|
+
linkref: node["linkref"] || "true",
|
21
|
+
linkmention: node["linkmention"] || "false")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def concept_render(node, opts)
|
26
|
+
node&.at(ns("./refterm"))&.remove
|
27
|
+
r = node.at(ns("./renderterm"))
|
28
|
+
ref = node.at(ns("./xref | ./eref | ./termref"))
|
29
|
+
ref && opts[:ref] != "false" and r&.next = " "
|
30
|
+
opts[:ital] == "true" and r&.name = "em"
|
31
|
+
if opts[:linkmention] == "true" && !r.nil? && !ref.nil?
|
32
|
+
ref2 = ref.clone
|
33
|
+
r2 = r.clone
|
34
|
+
r.replace(ref2).children = r2
|
35
|
+
end
|
36
|
+
concept1_ref(node, ref, opts)
|
37
|
+
if opts[:ital] == "false"
|
38
|
+
r = node.at(ns(".//renderterm"))
|
39
|
+
r&.replace(r&.children)
|
40
|
+
end
|
41
|
+
node.replace(node.children)
|
42
|
+
end
|
43
|
+
|
44
|
+
def concept1_ref(_node, ref, opts)
|
45
|
+
ref.nil? and return
|
46
|
+
return ref.remove if opts[:ref] == "false"
|
47
|
+
|
48
|
+
r = concept1_ref_content(ref)
|
49
|
+
ref = r.at("./descendant-or-self::xmlns:xref | "\
|
50
|
+
"./descendant-or-self::xmlns:eref | "\
|
51
|
+
"./descendant-or-self::xmlns:termref")
|
52
|
+
%w(xref eref).include? ref&.name and get_linkend(ref)
|
53
|
+
if opts[:linkref] == "false" && %w(xref eref).include?(ref&.name)
|
54
|
+
ref.replace(ref.children)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def concept1_ref_content(ref)
|
59
|
+
if non_locality_elems(ref).select do |c|
|
60
|
+
!c.text? || /\S/.match(c)
|
61
|
+
end.empty?
|
62
|
+
ref.replace(@i18n.term_defined_in.sub(/%/,
|
63
|
+
ref.to_xml))
|
64
|
+
else ref.replace("[#{ref.to_xml}]")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require "base64"
|
2
|
+
require "emf2svg"
|
3
|
+
|
4
|
+
module IsoDoc
|
5
|
+
class PresentationXMLConvert < ::IsoDoc::Convert
|
6
|
+
def figure(docxml)
|
7
|
+
docxml.xpath(ns("//image")).each { |f| svg_extract(f) }
|
8
|
+
docxml.xpath(ns("//figure")).each { |f| figure1(f) }
|
9
|
+
docxml.xpath(ns("//svgmap")).each do |s|
|
10
|
+
if f = s.at(ns("./figure")) then s.replace(f)
|
11
|
+
else s.remove
|
12
|
+
end
|
13
|
+
end
|
14
|
+
docxml.xpath(ns("//image")).each { |f| svg_emf_double(f) }
|
15
|
+
end
|
16
|
+
|
17
|
+
def svg_extract(elem)
|
18
|
+
return unless %r{^data:image/svg\+xml;}.match?(elem["src"])
|
19
|
+
|
20
|
+
svg = Base64.strict_decode64(elem["src"]
|
21
|
+
.sub(%r{^data:image/svg\+xml;(charset=[^;]+;)?base64,}, ""))
|
22
|
+
x = Nokogiri::XML.fragment(svg.sub(/<\?xml[^>]*>/, "")) do |config|
|
23
|
+
config.huge
|
24
|
+
end
|
25
|
+
elem["src"] = ""
|
26
|
+
elem.children = x
|
27
|
+
end
|
28
|
+
|
29
|
+
def figure1(elem)
|
30
|
+
return sourcecode1(elem) if elem["class"] == "pseudocode" ||
|
31
|
+
elem["type"] == "pseudocode"
|
32
|
+
return if labelled_ancestor(elem) && elem.ancestors("figure").empty? ||
|
33
|
+
elem.at(ns("./figure")) && !elem.at(ns("./name"))
|
34
|
+
|
35
|
+
lbl = @xrefs.anchor(elem["id"], :label, false) or return
|
36
|
+
prefix_name(elem, " — ",
|
37
|
+
l10n("#{lower2cap @i18n.figure} #{lbl}"), "name")
|
38
|
+
end
|
39
|
+
|
40
|
+
def svg_emf_double(img)
|
41
|
+
if emf?(img["mimetype"])
|
42
|
+
img = emf_encode(img)
|
43
|
+
img.children.first.previous = emf_to_svg(img)
|
44
|
+
elsif img["mimetype"] == "image/svg+xml"
|
45
|
+
src = svg_to_emf(img) and img << "<emf src='#{src}'/>"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def emf_encode(img)
|
50
|
+
img["mimetype"] = "image/svg+xml"
|
51
|
+
unless %r{^data:image}.match?(img["src"])
|
52
|
+
img["src"] = Metanorma::Utils::datauri(img["src"])
|
53
|
+
end
|
54
|
+
img.children = "<emf src='#{img['src']}'/>"
|
55
|
+
img["src"] = ""
|
56
|
+
img
|
57
|
+
end
|
58
|
+
|
59
|
+
def emf_to_svg(img)
|
60
|
+
emf = Metanorma::Utils::save_dataimage(img.at(ns("./emf/@src")).text)
|
61
|
+
Emf2svg.from_file(emf).sub(/<\?[^>]+>/, "")
|
62
|
+
end
|
63
|
+
|
64
|
+
def svg_to_emf(node)
|
65
|
+
uri = svg_to_emf_uri(node)
|
66
|
+
ret = svg_to_emf_filename(uri)
|
67
|
+
File.exists?(ret) and return ret
|
68
|
+
exe = inkscape_installed? or return nil
|
69
|
+
uri = Metanorma::Utils::external_path uri
|
70
|
+
exe = Metanorma::Utils::external_path exe
|
71
|
+
system(%(#{exe} --export-type="emf" #{uri})) and
|
72
|
+
return Metanorma::Utils::datauri(ret)
|
73
|
+
|
74
|
+
warn %(Fail on #{exe} --export-type="emf" #{uri})
|
75
|
+
|
76
|
+
nil
|
77
|
+
end
|
78
|
+
|
79
|
+
def svg_to_emf_uri(node)
|
80
|
+
uri = if node&.elements&.first&.name == "svg"
|
81
|
+
a = Base64.strict_encode64(node.children.to_xml)
|
82
|
+
"data:image/svg+xml;base64,#{a}"
|
83
|
+
else node["src"]
|
84
|
+
end
|
85
|
+
if %r{^data:}.match?(uri)
|
86
|
+
uri = save_dataimage(uri)
|
87
|
+
@tempfile_cache << uri
|
88
|
+
end
|
89
|
+
uri
|
90
|
+
end
|
91
|
+
|
92
|
+
def svg_to_emf_filename(uri)
|
93
|
+
"#{File.join(File.dirname(uri), File.basename(uri, '.*'))}.emf"
|
94
|
+
end
|
95
|
+
|
96
|
+
def emf_to_svgfilename(uri)
|
97
|
+
"#{File.join(File.dirname(uri), File.basename(uri, '.*'))}.svg"
|
98
|
+
end
|
99
|
+
|
100
|
+
def inkscape_installed?
|
101
|
+
cmd = "inkscape"
|
102
|
+
exts = ENV["PATHEXT"] ? ENV["PATHEXT"].split(";") : [""]
|
103
|
+
ENV["PATH"].split(File::PATH_SEPARATOR).each do |path|
|
104
|
+
exts.each do |ext|
|
105
|
+
exe = File.join(path, "#{cmd}#{ext}")
|
106
|
+
return exe if File.executable?(exe) && !File.directory?(exe)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
nil
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|