isodoc 1.6.3 → 1.6.7.1
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/.github/workflows/rake.yml +2 -12
- data/.hound.yml +3 -1
- data/.rubocop.yml +4 -6
- data/isodoc.gemspec +3 -2
- data/lib/isodoc-yaml/i18n-en.yaml +1 -0
- data/lib/isodoc-yaml/i18n-fr.yaml +1 -0
- data/lib/isodoc-yaml/i18n-zh-Hans.yaml +1 -0
- data/lib/isodoc.rb +0 -2
- data/lib/isodoc/convert.rb +7 -1
- data/lib/isodoc/function/blocks.rb +5 -4
- data/lib/isodoc/function/cleanup.rb +52 -43
- data/lib/isodoc/function/inline.rb +7 -7
- data/lib/isodoc/function/references.rb +33 -52
- data/lib/isodoc/function/section.rb +28 -16
- data/lib/isodoc/function/table.rb +21 -22
- data/lib/isodoc/function/terms.rb +6 -7
- data/lib/isodoc/function/to_word_html.rb +6 -3
- data/lib/isodoc/function/utils.rb +181 -163
- data/lib/isodoc/gem_tasks.rb +8 -9
- data/lib/isodoc/headlesshtml_convert.rb +8 -7
- data/lib/isodoc/html_convert.rb +5 -1
- data/lib/isodoc/html_function/comments.rb +14 -12
- data/lib/isodoc/html_function/footnotes.rb +14 -7
- data/lib/isodoc/html_function/html.rb +30 -26
- data/lib/isodoc/html_function/postprocess.rb +191 -182
- data/lib/isodoc/html_function/sectionsplit.rb +230 -0
- data/lib/isodoc/metadata.rb +22 -20
- data/lib/isodoc/metadata_contributor.rb +31 -28
- data/lib/isodoc/pdf_convert.rb +11 -13
- data/lib/isodoc/presentation_function/bibdata.rb +50 -22
- data/lib/isodoc/presentation_function/inline.rb +20 -15
- data/lib/isodoc/presentation_function/section.rb +38 -1
- data/lib/isodoc/presentation_xml_convert.rb +2 -0
- data/lib/isodoc/version.rb +1 -1
- data/lib/isodoc/word_function/postprocess.rb +50 -36
- data/lib/isodoc/xref.rb +2 -0
- data/lib/isodoc/xref/xref_gen_seq.rb +60 -35
- data/lib/isodoc/xref/xref_sect_gen.rb +4 -4
- data/spec/assets/scripts_override.html +3 -0
- data/spec/isodoc/blocks_spec.rb +373 -685
- data/spec/isodoc/cleanup_spec.rb +40 -42
- data/spec/isodoc/i18n_spec.rb +694 -821
- data/spec/isodoc/inline_spec.rb +482 -328
- data/spec/isodoc/metadata_spec.rb +384 -379
- data/spec/isodoc/postproc_spec.rb +163 -55
- data/spec/isodoc/presentation_xml_spec.rb +355 -278
- data/spec/isodoc/ref_spec.rb +5 -5
- data/spec/isodoc/section_spec.rb +216 -199
- data/spec/isodoc/sectionsplit_spec.rb +190 -0
- data/spec/isodoc/table_spec.rb +41 -42
- data/spec/isodoc/terms_spec.rb +84 -84
- data/spec/isodoc/xref_spec.rb +974 -932
- metadata +22 -5
@@ -8,11 +8,11 @@ module IsoDoc::Function
|
|
8
8
|
insert_tab(out, 1)
|
9
9
|
end
|
10
10
|
|
11
|
-
def inline_header_title(out,
|
11
|
+
def inline_header_title(out, _node, title)
|
12
12
|
out.span **{ class: "zzMoveToFollowing" } do |s|
|
13
13
|
s.b do |b|
|
14
14
|
title&.children&.each { |c2| parse(c2, b) }
|
15
|
-
clausedelimspace(out) if /\S/.match(title&.text)
|
15
|
+
clausedelimspace(out) if /\S/.match?(title&.text)
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
@@ -20,12 +20,14 @@ module IsoDoc::Function
|
|
20
20
|
# used for subclauses
|
21
21
|
def clause_parse_title(node, div, title, out, header_class = {})
|
22
22
|
return if title.nil?
|
23
|
+
|
23
24
|
if node["inline-header"] == "true"
|
24
25
|
inline_header_title(out, node, title)
|
25
26
|
else
|
26
|
-
depth =
|
27
|
-
|
28
|
-
|
27
|
+
depth = if title && title["depth"] then title["depth"]
|
28
|
+
else node.ancestors("clause, annex, terms, references, definitions, "\
|
29
|
+
"acknowledgements, introduction, foreword").size + 1
|
30
|
+
end
|
29
31
|
div.send "h#{depth}", **attr_code(header_class) do |h|
|
30
32
|
title&.children&.each { |c2| parse(c2, h) }
|
31
33
|
end
|
@@ -49,8 +51,11 @@ module IsoDoc::Function
|
|
49
51
|
def clause_name(_num, title, div, header_class)
|
50
52
|
header_class = {} if header_class.nil?
|
51
53
|
div.h1 **attr_code(header_class) do |h1|
|
52
|
-
title.is_a?(String)
|
54
|
+
if title.is_a?(String)
|
55
|
+
h1 << title
|
56
|
+
else
|
53
57
|
title&.children&.each { |c2| parse(c2, h1) }
|
58
|
+
end
|
54
59
|
end
|
55
60
|
div.parent.at(".//h1")
|
56
61
|
end
|
@@ -66,8 +71,9 @@ module IsoDoc::Function
|
|
66
71
|
end
|
67
72
|
end
|
68
73
|
|
69
|
-
def annex_name(
|
74
|
+
def annex_name(_annex, name, div)
|
70
75
|
return if name.nil?
|
76
|
+
|
71
77
|
div.h1 **{ class: "Annex" } do |t|
|
72
78
|
name.children.each { |c2| parse(c2, t) }
|
73
79
|
end
|
@@ -144,7 +150,6 @@ module IsoDoc::Function
|
|
144
150
|
|
145
151
|
def introduction(isoxml, out)
|
146
152
|
f = isoxml.at(ns("//introduction")) || return
|
147
|
-
title_attr = { class: "IntroTitle" }
|
148
153
|
page_break(out)
|
149
154
|
out.div **{ class: "Section3", id: f["id"] } do |div|
|
150
155
|
clause_name(nil, f.at(ns("./title")), div, { class: "IntroTitle" })
|
@@ -160,7 +165,6 @@ module IsoDoc::Function
|
|
160
165
|
out.div **attr_code(id: f["id"]) do |s|
|
161
166
|
clause_name(nil, f.at(ns("./title")) || @i18n.foreword, s,
|
162
167
|
{ class: "ForewordTitle" })
|
163
|
-
#s.h1(**{ class: "ForewordTitle" }) { |h1| h1 << @i18n.foreword }
|
164
168
|
f.elements.each { |e| parse(e, s) unless e.name == "title" }
|
165
169
|
end
|
166
170
|
end
|
@@ -187,12 +191,11 @@ module IsoDoc::Function
|
|
187
191
|
end
|
188
192
|
|
189
193
|
def preface(isoxml, out)
|
190
|
-
title_attr = { class: "IntroTitle" }
|
191
194
|
isoxml.xpath(ns("//preface/clause | //preface/references | "\
|
192
195
|
"//preface/definitions | //preface/terms")).each do |f|
|
193
196
|
page_break(out)
|
194
197
|
out.div **{ class: "Section3", id: f["id"] } do |div|
|
195
|
-
clause_name(nil, f&.at(ns("./title")), div,
|
198
|
+
clause_name(nil, f&.at(ns("./title")), div, { class: "IntroTitle" })
|
196
199
|
f.elements.each do |e|
|
197
200
|
parse(e, div) unless e.name == "title"
|
198
201
|
end
|
@@ -202,37 +205,46 @@ module IsoDoc::Function
|
|
202
205
|
|
203
206
|
def is_clause?(name)
|
204
207
|
%w(clause references definitions terms foreword introduction abstract
|
205
|
-
|
208
|
+
acknowledgements).include? name
|
206
209
|
end
|
207
210
|
|
208
211
|
def preface_block(isoxml, out)
|
209
212
|
p = isoxml.at(ns("//preface")) or return
|
210
213
|
p.elements.each do |e|
|
211
214
|
next if is_clause?(e.name)
|
215
|
+
|
212
216
|
parse(e, out)
|
213
217
|
end
|
214
218
|
end
|
215
219
|
|
216
220
|
def copyright_parse(node, out)
|
217
|
-
|
221
|
+
return if @bare
|
222
|
+
|
223
|
+
out.div **{ class: "boilerplate-copyright" } do |div|
|
218
224
|
node.children.each { |n| parse(n, div) }
|
219
225
|
end
|
220
226
|
end
|
221
227
|
|
222
228
|
def license_parse(node, out)
|
223
|
-
|
229
|
+
return if @bare
|
230
|
+
|
231
|
+
out.div **{ class: "boilerplate-license" } do |div|
|
224
232
|
node.children.each { |n| parse(n, div) }
|
225
233
|
end
|
226
234
|
end
|
227
235
|
|
228
236
|
def legal_parse(node, out)
|
229
|
-
|
237
|
+
return if @bare
|
238
|
+
|
239
|
+
out.div **{ class: "boilerplate-legal" } do |div|
|
230
240
|
node.children.each { |n| parse(n, div) }
|
231
241
|
end
|
232
242
|
end
|
233
243
|
|
234
244
|
def feedback_parse(node, out)
|
235
|
-
|
245
|
+
return if @bare
|
246
|
+
|
247
|
+
out.div **{ class: "boilerplate-feedback" } do |div|
|
236
248
|
node.children.each { |n| parse(n, div) }
|
237
249
|
end
|
238
250
|
end
|
@@ -1,17 +1,16 @@
|
|
1
1
|
module IsoDoc::Function
|
2
2
|
module Table
|
3
|
-
|
4
3
|
def table_title_parse(node, out)
|
5
4
|
name = node.at(ns("./name")) or return
|
6
5
|
out.p **{ class: "TableTitle", style: "text-align:center;" } do |p|
|
7
|
-
name
|
6
|
+
name&.children&.each { |n| parse(n, p) }
|
8
7
|
end
|
9
8
|
end
|
10
9
|
|
11
|
-
def thead_parse(node,
|
10
|
+
def thead_parse(node, table)
|
12
11
|
thead = node.at(ns("./thead"))
|
13
12
|
if thead
|
14
|
-
|
13
|
+
table.thead do |h|
|
15
14
|
thead.element_children.each_with_index do |n, i|
|
16
15
|
tr_parse(n, h, i, thead.element_children.size, true)
|
17
16
|
end
|
@@ -19,19 +18,19 @@ module IsoDoc::Function
|
|
19
18
|
end
|
20
19
|
end
|
21
20
|
|
22
|
-
def tbody_parse(node,
|
21
|
+
def tbody_parse(node, table)
|
23
22
|
tbody = node.at(ns("./tbody")) || return
|
24
|
-
|
23
|
+
table.tbody do |h|
|
25
24
|
tbody.element_children.each_with_index do |n, i|
|
26
25
|
tr_parse(n, h, i, tbody.element_children.size, false)
|
27
26
|
end
|
28
27
|
end
|
29
28
|
end
|
30
29
|
|
31
|
-
def tfoot_parse(node,
|
30
|
+
def tfoot_parse(node, table)
|
32
31
|
tfoot = node.at(ns("./tfoot"))
|
33
32
|
if tfoot
|
34
|
-
|
33
|
+
table.tfoot do |h|
|
35
34
|
tfoot.element_children.each_with_index do |n, i|
|
36
35
|
tr_parse(n, h, i, tfoot.element_children.size, false)
|
37
36
|
end
|
@@ -45,23 +44,23 @@ module IsoDoc::Function
|
|
45
44
|
id: node["id"],
|
46
45
|
class: "MsoISOTable",
|
47
46
|
style: "border-width:1px;border-spacing:0;#{width}#{keep_style(node)}",
|
48
|
-
title: node["alt"]
|
47
|
+
title: node["alt"],
|
49
48
|
)
|
50
49
|
end
|
51
50
|
|
52
|
-
def tcaption(node,
|
51
|
+
def tcaption(node, table)
|
53
52
|
return unless node["summary"]
|
54
53
|
|
55
|
-
|
54
|
+
table.caption do |c|
|
56
55
|
c.span **{ style: "display:none" } do |s|
|
57
56
|
s << node["summary"]
|
58
57
|
end
|
59
58
|
end
|
60
59
|
end
|
61
60
|
|
62
|
-
def colgroup(node,
|
61
|
+
def colgroup(node, table)
|
63
62
|
colgroup = node.at(ns("./colgroup")) or return
|
64
|
-
|
63
|
+
table.colgroup do |cg|
|
65
64
|
colgroup.xpath(ns("./col")).each do |c|
|
66
65
|
cg.col **{ style: "width: #{c['width']};" }
|
67
66
|
end
|
@@ -90,19 +89,19 @@ module IsoDoc::Function
|
|
90
89
|
# border-left:#{col.zero? ? "#{SW} 1.5pt;" : "none;"}
|
91
90
|
# border-right:#{SW} #{col == totalcols && !header ? "1.5" : "1.0"}pt;
|
92
91
|
|
93
|
-
def make_tr_attr(
|
94
|
-
style =
|
95
|
-
|
96
|
-
|
97
|
-
rowmax =
|
92
|
+
def make_tr_attr(cell, row, totalrows, header)
|
93
|
+
style = cell.name == "th" ? "font-weight:bold;" : ""
|
94
|
+
cell["align"] and style += "text-align:#{cell['align']};"
|
95
|
+
cell["valign"] and style += "vertical-align:#{cell['valign']};"
|
96
|
+
rowmax = cell["rowspan"] ? row + cell["rowspan"].to_i - 1 : row
|
98
97
|
style += <<~STYLE
|
99
98
|
border-top:#{row.zero? ? "#{SW} 1.5pt;" : 'none;'}
|
100
99
|
border-bottom:#{SW} #{rowmax == totalrows ? '1.5' : '1.0'}pt;
|
101
100
|
STYLE
|
102
|
-
header and scope = (
|
103
|
-
!header and
|
104
|
-
|
105
|
-
{ rowspan:
|
101
|
+
header and scope = (cell["colspan"] ? "colgroup" : "col")
|
102
|
+
!header and cell.name == "th" and scope =
|
103
|
+
(cell["rowspan"] ? "rowgroup" : "row")
|
104
|
+
{ rowspan: cell["rowspan"], colspan: cell["colspan"],
|
106
105
|
style: style.gsub(/\n/, ""), scope: scope }
|
107
106
|
end
|
108
107
|
|
@@ -11,27 +11,27 @@ module IsoDoc::Function
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def deprecated_term_parse(node, out)
|
14
|
-
out.p **{ class: "DeprecatedTerms", style:"text-align:left;" } do |p|
|
14
|
+
out.p **{ class: "DeprecatedTerms", style: "text-align:left;" } do |p|
|
15
15
|
p << l10n("#{@i18n.deprecated}: ")
|
16
16
|
node.children.each { |c| parse(c, p) }
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
20
|
def admitted_term_parse(node, out)
|
21
|
-
out.p **{ class: "AltTerms", style:"text-align:left;" } do |p|
|
21
|
+
out.p **{ class: "AltTerms", style: "text-align:left;" } do |p|
|
22
22
|
node.children.each { |c| parse(c, p) }
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
26
|
def term_parse(node, out)
|
27
|
-
out.p **{ class: "Terms", style:"text-align:left;" } do |p|
|
27
|
+
out.p **{ class: "Terms", style: "text-align:left;" } do |p|
|
28
28
|
node.children.each { |c| parse(c, p) }
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
-
def para_then_remainder(first, node,
|
32
|
+
def para_then_remainder(first, node, para, div)
|
33
33
|
if first.name == "p"
|
34
|
-
first.children.each { |n| parse(n,
|
34
|
+
first.children.each { |n| parse(n, para) }
|
35
35
|
node.elements.drop(1).each { |n| parse(n, div) }
|
36
36
|
else
|
37
37
|
node.elements.each { |n| parse(n, div) }
|
@@ -72,7 +72,6 @@ module IsoDoc::Function
|
|
72
72
|
node.children.each { |n| parse(n, out) }
|
73
73
|
end
|
74
74
|
|
75
|
-
def termdocsource_parse(_node, _out)
|
76
|
-
end
|
75
|
+
def termdocsource_parse(_node, _out); end
|
77
76
|
end
|
78
77
|
end
|
@@ -21,9 +21,10 @@ module IsoDoc::Function
|
|
21
21
|
filename = filepath.sub_ext("").sub(/\.presentation$/, "").to_s
|
22
22
|
dir = init_dir(filename, debug)
|
23
23
|
@filename = filename
|
24
|
-
@localdir = filepath.parent
|
24
|
+
@localdir = "#{filepath.parent}/"
|
25
25
|
@sourcedir = @localdir
|
26
|
-
@sourcefilename and
|
26
|
+
@sourcefilename and
|
27
|
+
@sourcedir = "#{Pathname.new(@sourcefilename).parent}/"
|
27
28
|
[filename, dir]
|
28
29
|
end
|
29
30
|
|
@@ -47,7 +48,7 @@ module IsoDoc::Function
|
|
47
48
|
|
48
49
|
# isodoc.css overrides any CSS injected by Html2Doc, which
|
49
50
|
# is inserted before this CSS.
|
50
|
-
def define_head(head,
|
51
|
+
def define_head(head, _filename, _dir)
|
51
52
|
if @standardstylesheet
|
52
53
|
head.style do |style|
|
53
54
|
@standardstylesheet.open
|
@@ -128,6 +129,8 @@ module IsoDoc::Function
|
|
128
129
|
end
|
129
130
|
|
130
131
|
def boilerplate(node, out)
|
132
|
+
return if @bare
|
133
|
+
|
131
134
|
boilerplate = node.at(ns("//boilerplate")) or return
|
132
135
|
out.div **{ class: "authority" } do |s|
|
133
136
|
boilerplate.children.each do |n|
|
@@ -1,193 +1,211 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module IsoDoc
|
4
|
-
module
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
module IsoDoc
|
4
|
+
module Function
|
5
|
+
module Utils
|
6
|
+
def date_range(date)
|
7
|
+
self.class.date_range(date)
|
8
|
+
end
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
10
|
+
def ns(xpath)
|
11
|
+
self.class.ns(xpath)
|
12
|
+
end
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
def insert_tab(out, count)
|
15
|
+
tab = %w(Hans Hant).include?(@script) ? " " : " "
|
16
|
+
[1..count].each { out << tab }
|
17
|
+
end
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
19
|
+
# add namespaces for Word fragments
|
20
|
+
NOKOHEAD = <<~HERE
|
21
|
+
<!DOCTYPE html SYSTEM
|
22
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
23
|
+
<html xmlns="http://www.w3.org/1999/xhtml">
|
24
|
+
<head> <title></title> <meta charset="UTF-8" /> </head>
|
25
|
+
<body> </body> </html>
|
26
|
+
HERE
|
27
|
+
|
28
|
+
# block for processing XML document fragments as XHTML,
|
29
|
+
# to allow for HTMLentities
|
30
|
+
def noko(&block)
|
31
|
+
doc = ::Nokogiri::XML.parse(NOKOHEAD)
|
32
|
+
fragment = doc.fragment("")
|
33
|
+
::Nokogiri::XML::Builder.with fragment, &block
|
34
|
+
fragment.to_xml(encoding: "US-ASCII").lines.map do |l|
|
35
|
+
l.gsub(/\s*\n/, "")
|
36
|
+
end
|
35
37
|
end
|
36
|
-
end
|
37
38
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
39
|
+
def attr_code(attributes)
|
40
|
+
attributes = attributes.reject { |_, val| val.nil? }.map
|
41
|
+
attributes.map do |k, v|
|
42
|
+
[k, v.is_a?(String) ? HTMLEntities.new.decode(v) : v]
|
43
|
+
end.to_h
|
44
|
+
end
|
44
45
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
abort "Malformed Output XML for #{@format}: #{e} "\
|
60
|
-
"(see #{@filename}.#{@format}.err)"
|
46
|
+
DOCTYPE_HDR = "<!DOCTYPE html SYSTEM "\
|
47
|
+
'"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
|
48
|
+
|
49
|
+
def to_xhtml(xml)
|
50
|
+
xml = to_xhtml_prep(xml)
|
51
|
+
begin
|
52
|
+
Nokogiri::XML.parse(xml, &:strict)
|
53
|
+
rescue Nokogiri::XML::SyntaxError => e
|
54
|
+
File.open("#{@filename}.#{@format}.err", "w:UTF-8") do |f|
|
55
|
+
f.write xml
|
56
|
+
end
|
57
|
+
abort "Malformed Output XML for #{@format}: #{e} "\
|
58
|
+
"(see #{@filename}.#{@format}.err)"
|
59
|
+
end
|
61
60
|
end
|
62
|
-
end
|
63
61
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
62
|
+
def to_xhtml_prep(xml)
|
63
|
+
xml.gsub!(/<\?xml[^>]*>/, "")
|
64
|
+
/<!DOCTYPE /.match(xml) || (xml = DOCTYPE_HDR + xml)
|
65
|
+
xml.split(/(&[^ \r\n\t#;]+;)/).map do |t|
|
66
|
+
if /^(&[^ \t\r\n#;]+;)/.match?(t)
|
67
|
+
HTMLEntities.new.encode(HTMLEntities.new.decode(t), :hexadecimal)
|
68
|
+
else t
|
69
|
+
end
|
70
|
+
end.join("")
|
71
|
+
end
|
69
72
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
+
def to_xhtml_fragment(xml)
|
74
|
+
doc = ::Nokogiri::XML.parse(NOKOHEAD)
|
75
|
+
doc.fragment(xml)
|
76
|
+
end
|
73
77
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
"local-name() = 'acknowledgements' or local-name() = 'term' or "\
|
78
|
-
"local-name() = 'appendix' or local-name() = 'foreword' or "\
|
79
|
-
"local-name() = 'introduction' or local-name() = 'terms' or "\
|
80
|
-
"local-name() = 'clause' or local-name() = 'references']/@id"
|
81
|
-
|
82
|
-
def get_clause_id(node)
|
83
|
-
clause = node.xpath(CLAUSE_ANCESTOR)
|
84
|
-
clause&.last&.text || nil
|
85
|
-
end
|
78
|
+
def from_xhtml(xml)
|
79
|
+
xml.to_xml.sub(%r{ xmlns="http://www.w3.org/1999/xhtml"}, "")
|
80
|
+
end
|
86
81
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
end
|
82
|
+
CLAUSE_ANCESTOR =
|
83
|
+
".//ancestor::*[local-name() = 'annex' or "\
|
84
|
+
"local-name() = 'definitions' or "\
|
85
|
+
"local-name() = 'acknowledgements' or local-name() = 'term' or "\
|
86
|
+
"local-name() = 'appendix' or local-name() = 'foreword' or "\
|
87
|
+
"local-name() = 'introduction' or local-name() = 'terms' or "\
|
88
|
+
"local-name() = 'clause' or local-name() = 'references']/@id"
|
89
|
+
|
90
|
+
def get_clause_id(node)
|
91
|
+
clause = node.xpath(CLAUSE_ANCESTOR)
|
92
|
+
clause&.last&.text || nil
|
93
|
+
end
|
100
94
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
95
|
+
NOTE_CONTAINER_ANCESTOR =
|
96
|
+
".//ancestor::*[local-name() = 'annex' or "\
|
97
|
+
"local-name() = 'foreword' or local-name() = 'appendix' or "\
|
98
|
+
"local-name() = 'introduction' or local-name() = 'terms' or "\
|
99
|
+
"local-name() = 'acknowledgements' or local-name() = 'term' or "\
|
100
|
+
"local-name() = 'clause' or local-name() = 'references' or "\
|
101
|
+
"local-name() = 'figure' or local-name() = 'formula' or "\
|
102
|
+
"local-name() = 'table' or local-name() = 'example']/@id"
|
103
|
+
|
104
|
+
def get_note_container_id(node)
|
105
|
+
container = node.xpath(NOTE_CONTAINER_ANCESTOR)
|
106
|
+
container&.last&.text || nil
|
108
107
|
end
|
109
|
-
end
|
110
108
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
109
|
+
def sentence_join(array)
|
110
|
+
return "" if array.nil? || array.empty?
|
111
|
+
|
112
|
+
if array.length == 1 then array[0]
|
113
|
+
else
|
114
|
+
@i18n.l10n("#{array[0..-2].join(', ')} "\
|
115
|
+
"#{@i18n.and} #{array.last}",
|
116
|
+
@lang, @script)
|
117
|
+
end
|
118
118
|
end
|
119
|
-
[@openmathdelim, @closemathdelim]
|
120
|
-
end
|
121
119
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
x.replace(x.children) if x.name == "a"
|
133
|
-
end
|
134
|
-
from_xhtml(h1)
|
135
|
-
end
|
120
|
+
# avoid `; avoid {{ (Liquid Templates); avoid [[ (Javascript)
|
121
|
+
def extract_delims(text)
|
122
|
+
@openmathdelim = "(#("
|
123
|
+
@closemathdelim = ")#)"
|
124
|
+
while text.include?(@openmathdelim) || text.include?(@closemathdelim)
|
125
|
+
@openmathdelim += "("
|
126
|
+
@closemathdelim += ")"
|
127
|
+
end
|
128
|
+
[@openmathdelim, @closemathdelim]
|
129
|
+
end
|
136
130
|
|
137
|
-
|
138
|
-
|
139
|
-
|
131
|
+
def header_strip(hdr)
|
132
|
+
h1 = to_xhtml_fragment(hdr.to_s.gsub(%r{<br\s*/>}, " ")
|
133
|
+
.gsub(/<\/?h[123456][^>]*>/, "").gsub(/<\/?b[^>]*>/, "").dup)
|
134
|
+
h1.traverse do |x|
|
135
|
+
if x.name == "span" && /mso-tab-count/.match(x["style"])
|
136
|
+
x.replace(" ")
|
137
|
+
elsif header_strip_elem?(x) then x.remove
|
138
|
+
elsif x.name == "a" then x.replace(x.children)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
from_xhtml(h1)
|
142
|
+
end
|
140
143
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
end
|
147
|
-
Liquid::Template.parse(doc)
|
148
|
-
end
|
144
|
+
def header_strip_elem?(elem)
|
145
|
+
elem.name == "img" ||
|
146
|
+
elem.name == "span" && elem["class"] == "MsoCommentReference" ||
|
147
|
+
elem.name == "a" && elem["class"] == "FootnoteRef" ||
|
148
|
+
elem.name == "span" && /mso-bookmark/.match(elem["style"])
|
149
|
+
end
|
149
150
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
151
|
+
=begin
|
152
|
+
def liquid(doc)
|
153
|
+
self.class.liquid(doc)
|
154
|
+
end
|
155
|
+
=end
|
156
|
+
|
157
|
+
def liquid(doc)
|
158
|
+
# unescape HTML escapes in doc
|
159
|
+
doc = doc.split(%r<(\{%|%\})>).each_slice(4).map do |a|
|
160
|
+
a[2] = a[2].gsub(/</, "<").gsub(/>/, ">") if a.size > 2
|
161
|
+
a.join("")
|
162
|
+
end.join("")
|
163
|
+
Liquid::Template.parse(doc)
|
164
|
+
end
|
154
165
|
|
155
|
-
|
156
|
-
|
157
|
-
.get
|
158
|
-
.merge(@labels ? {labels: @labels} : {})
|
159
|
-
.merge(@meta.labels ? {labels: @meta.labels} : {})
|
160
|
-
.merge(fonts_options || {})
|
161
|
-
template = liquid(docxml)
|
162
|
-
template.render(meta.map { |k, v| [k.to_s, empty2nil(v)] }.to_h)
|
163
|
-
.gsub("<", "<").gsub(">", ">").gsub("&", "&")
|
164
|
-
end
|
166
|
+
def empty2nil(str)
|
167
|
+
return nil if !str.nil? && str.is_a?(String) && str.empty?
|
165
168
|
|
166
|
-
|
167
|
-
%r{^data:(image|application)/(?<imgtype>[^;]+);base64,(?<imgdata>.+)$} =~ uri
|
168
|
-
imgtype.sub!(/\+[a-z0-9]+$/, "") # svg+xml
|
169
|
-
imgtype = "png" unless /^[a-z0-9]+$/.match imgtype
|
170
|
-
Tempfile.open(["image", ".#{imgtype}"]) do |f|
|
171
|
-
f.binmode
|
172
|
-
f.write(Base64.strict_decode64(imgdata))
|
173
|
-
@tempfile_cache << f # persist to the end
|
174
|
-
f.path
|
169
|
+
str
|
175
170
|
end
|
176
|
-
end
|
177
171
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
172
|
+
def populate_template(docxml, _format = nil)
|
173
|
+
meta = @meta
|
174
|
+
.get
|
175
|
+
.merge(@labels ? { labels: @labels } : {})
|
176
|
+
.merge(@meta.labels ? { labels: @meta.labels } : {})
|
177
|
+
.merge(fonts_options || {})
|
178
|
+
template = liquid(docxml)
|
179
|
+
template.render(meta.map { |k, v| [k.to_s, empty2nil(v)] }.to_h)
|
180
|
+
.gsub("<", "<").gsub(">", ">").gsub("&", "&")
|
185
181
|
end
|
186
|
-
end
|
187
182
|
|
188
|
-
|
189
|
-
|
190
|
-
|
183
|
+
def save_dataimage(uri, _relative_dir = true)
|
184
|
+
%r{^data:(image|application)/(?<imgtype>[^;]+);base64,(?<imgdata>.+)$} =~ uri
|
185
|
+
imgtype.sub!(/\+[a-z0-9]+$/, "") # svg+xml
|
186
|
+
imgtype = "png" unless /^[a-z0-9]+$/.match? imgtype
|
187
|
+
Tempfile.open(["image", ".#{imgtype}"]) do |f|
|
188
|
+
f.binmode
|
189
|
+
f.write(Base64.strict_decode64(imgdata))
|
190
|
+
@tempfile_cache << f # persist to the end
|
191
|
+
f.path
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def image_localfile(img)
|
196
|
+
if /^data:/.match? img["src"]
|
197
|
+
save_dataimage(img["src"], false)
|
198
|
+
elsif %r{^([A-Z]:)?/}.match? img["src"]
|
199
|
+
img["src"]
|
200
|
+
else
|
201
|
+
File.join(@localdir, img["src"])
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def labelled_ancestor(node)
|
206
|
+
!node.ancestors("example, requirement, recommendation, permission, "\
|
207
|
+
"note, table, figure, sourcecode").empty?
|
208
|
+
end
|
191
209
|
end
|
192
210
|
end
|
193
211
|
end
|