html2doc 1.0.5 → 1.1.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 +42 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +6 -4
- data/Gemfile +2 -2
- data/README.adoc +1 -3
- data/Rakefile +1 -1
- data/bin/html2doc +2 -3
- data/html2doc.gemspec +4 -3
- data/lib/html2doc/base.rb +55 -45
- data/lib/html2doc/lists.rb +33 -25
- data/lib/html2doc/math.rb +97 -38
- data/lib/html2doc/mime.rb +42 -25
- data/lib/html2doc/mml2omml.xsl +9 -1
- data/lib/html2doc/notes.rb +34 -31
- data/lib/html2doc/version.rb +1 -1
- data/spec/html2doc_spec.rb +511 -484
- metadata +26 -16
- data/.github/workflows/macos.yml +0 -38
- data/.github/workflows/ubuntu.yml +0 -56
- data/.github/workflows/windows.yml +0 -40
- data/.rubocop.ribose.yml +0 -65
- data/.rubocop.tb.yml +0 -650
data/lib/html2doc/mime.rb
CHANGED
@@ -7,19 +7,20 @@ require "fileutils"
|
|
7
7
|
module Html2Doc
|
8
8
|
def self.mime_preamble(boundary, filename, result)
|
9
9
|
<<~"PREAMBLE"
|
10
|
-
|
11
|
-
|
10
|
+
MIME-Version: 1.0
|
11
|
+
Content-Type: multipart/related; boundary="#{boundary}"
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
--#{boundary}
|
14
|
+
Content-ID: <#{File.basename(filename)}>
|
15
|
+
Content-Disposition: inline; filename="#{File.basename(filename)}"
|
16
|
+
Content-Type: text/html; charset="utf-8"
|
16
17
|
|
17
|
-
|
18
|
+
#{result}
|
18
19
|
|
19
20
|
PREAMBLE
|
20
21
|
end
|
21
22
|
|
22
|
-
def self.mime_attachment(boundary,
|
23
|
+
def self.mime_attachment(boundary, _filename, item, dir)
|
23
24
|
content_type = mime_type(item)
|
24
25
|
text_mode = %w[text application].any? { |p| content_type.start_with? p }
|
25
26
|
|
@@ -28,12 +29,13 @@ module Html2Doc
|
|
28
29
|
|
29
30
|
encoded_file = Base64.strict_encode64(content).gsub(/(.{76})/, "\\1\n")
|
30
31
|
<<~"FILE"
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
32
|
+
--#{boundary}
|
33
|
+
Content-ID: <#{File.basename(item)}>
|
34
|
+
Content-Disposition: inline; filename="#{File.basename(item)}"
|
35
|
+
Content-Transfer-Encoding: base64
|
36
|
+
Content-Type: #{content_type}
|
35
37
|
|
36
|
-
|
38
|
+
#{encoded_file}
|
37
39
|
|
38
40
|
FILE
|
39
41
|
end
|
@@ -52,15 +54,26 @@ module Html2Doc
|
|
52
54
|
|
53
55
|
def self.mime_package(result, filename, dir)
|
54
56
|
boundary = mime_boundary
|
55
|
-
mhtml = mime_preamble(boundary, filename, result)
|
56
|
-
mhtml += mime_attachment(boundary, filename, "filelist.xml", dir)
|
57
|
+
mhtml = mime_preamble(boundary, "#{filename}.htm", result)
|
58
|
+
mhtml += mime_attachment(boundary, "#{filename}.htm", "filelist.xml", dir)
|
57
59
|
Dir.foreach(dir) do |item|
|
58
60
|
next if item == "." || item == ".." || /^\./.match(item) ||
|
59
61
|
item == "filelist.xml"
|
60
|
-
|
62
|
+
|
63
|
+
mhtml += mime_attachment(boundary, "#{filename}.htm", item, dir)
|
61
64
|
end
|
62
65
|
mhtml += "--#{boundary}--"
|
63
|
-
File.open("#{filename}.doc", "w:UTF-8") { |f| f.write mhtml }
|
66
|
+
File.open("#{filename}.doc", "w:UTF-8") { |f| f.write contentid(mhtml) }
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.contentid(mhtml)
|
70
|
+
mhtml.gsub %r{(<img[^>]*?src=")([^\"']+)(['"])}m do |m|
|
71
|
+
repl = "#{$1}cid:#{File.basename($2)}#{$3}"
|
72
|
+
/^data:|^https?:/.match($2) ? m : repl
|
73
|
+
end.gsub %r{(<v:imagedata[^>]*?src=")([^\"']+)(['"])}m do |m|
|
74
|
+
repl = "#{$1}cid:#{File.basename($2)}#{$3}"
|
75
|
+
/^data:|^https?:/.match($2) ? m : repl
|
76
|
+
end
|
64
77
|
end
|
65
78
|
|
66
79
|
# max width for Word document is 400, max height is 680
|
@@ -68,7 +81,8 @@ module Html2Doc
|
|
68
81
|
realSize = ImageSize.path(path).size
|
69
82
|
s = [i["width"].to_i, i["height"].to_i]
|
70
83
|
s = realSize if s[0].zero? && s[1].zero?
|
71
|
-
return [nil, nil] if realSize[0].nil? || realSize[1].nil?
|
84
|
+
return [nil, nil] if realSize.nil? || realSize[0].nil? || realSize[1].nil?
|
85
|
+
|
72
86
|
s[1] = s[0] * realSize[1] / realSize[0] if s[1].zero? && !s[0].zero?
|
73
87
|
s[0] = s[1] * realSize[0] / realSize[1] if s[0].zero? && !s[1].zero?
|
74
88
|
s = [(s[0] * maxheight / s[1]).ceil, maxheight] if s[1] > maxheight
|
@@ -83,7 +97,7 @@ module Html2Doc
|
|
83
97
|
end
|
84
98
|
|
85
99
|
def self.warnsvg(src)
|
86
|
-
warn "#{src}: SVG not supported" if /\.svg$/i.match(src)
|
100
|
+
warn "#{src}: SVG not supported" if /\.svg$/i.match?(src)
|
87
101
|
end
|
88
102
|
|
89
103
|
# only processes locally stored images
|
@@ -92,10 +106,11 @@ module Html2Doc
|
|
92
106
|
next unless i.element? && %w(img v:imagedata).include?(i.name)
|
93
107
|
#warnsvg(i["src"])
|
94
108
|
next if /^http/.match i["src"]
|
95
|
-
next if %r{^data:image/[^;]+;base64}.match i["src"]
|
109
|
+
next if %r{^data:(image|application)/[^;]+;base64}.match? i["src"]
|
110
|
+
|
96
111
|
local_filename = %r{^([A-Z]:)?/}.match(i["src"]) ? i["src"] :
|
97
112
|
File.join(localdir, i["src"])
|
98
|
-
new_filename = "#{mkuuid}#{File.extname(i[
|
113
|
+
new_filename = "#{mkuuid}#{File.extname(i['src'])}"
|
99
114
|
FileUtils.cp local_filename, File.join(dir, new_filename)
|
100
115
|
i["width"], i["height"] = image_resize(i, local_filename, 680, 400)
|
101
116
|
i["src"] = File.join(File.basename(dir), new_filename)
|
@@ -103,7 +118,7 @@ module Html2Doc
|
|
103
118
|
docxml
|
104
119
|
end
|
105
120
|
|
106
|
-
# do not parse the header through Nokogiri, since it will contain
|
121
|
+
# do not parse the header through Nokogiri, since it will contain
|
107
122
|
# non-XML like <![if !supportFootnotes]>
|
108
123
|
def self.header_image_cleanup(doc, dir, filename, localdir)
|
109
124
|
doc.split(%r{(<img [^>]*>|<v:imagedata [^>]*>)}).each_slice(2).map do |a|
|
@@ -111,16 +126,17 @@ module Html2Doc
|
|
111
126
|
end.join
|
112
127
|
end
|
113
128
|
|
114
|
-
def self.header_image_cleanup1(a, dir,
|
129
|
+
def self.header_image_cleanup1(a, dir, _filename, localdir)
|
115
130
|
if a.size == 2 && !(/ src="https?:/.match a[1]) &&
|
116
|
-
!(%r{ src="data:image/[^;]+;base64}.match a[1])
|
131
|
+
!(%r{ src="data:(image|application)/[^;]+;base64}.match a[1])
|
117
132
|
m = / src=['"](?<src>[^"']+)['"]/.match a[1]
|
118
133
|
#warnsvg(m[:src])
|
119
134
|
m2 = /\.(?<suffix>[a-zA-Z_0-9]+)$/.match m[:src]
|
120
135
|
new_filename = "#{mkuuid}.#{m2[:suffix]}"
|
121
|
-
old_filename = %r{^([A-Z]:)?/}.match(m[:src]) ? m[:src] :
|
136
|
+
old_filename = %r{^([A-Z]:)?/}.match?(m[:src]) ? m[:src] :
|
137
|
+
File.join(localdir, m[:src])
|
122
138
|
FileUtils.cp old_filename, File.join(dir, new_filename)
|
123
|
-
a[1].sub!(%r{ src=['"](?<src>[^"']+)['"]}, " src='
|
139
|
+
a[1].sub!(%r{ src=['"](?<src>[^"']+)['"]}, " src='cid:#{new_filename}'")
|
124
140
|
end
|
125
141
|
a.join
|
126
142
|
end
|
@@ -131,6 +147,7 @@ module Html2Doc
|
|
131
147
|
<o:MainFile HRef="../#{filename}.htm"/>}
|
132
148
|
Dir.entries(dir).sort.each do |item|
|
133
149
|
next if item == "." || item == ".." || /^\./.match(item)
|
150
|
+
|
134
151
|
f.write %{ <o:File HRef="#{item}"/>\n}
|
135
152
|
end
|
136
153
|
f.write("</xml>\n")
|
data/lib/html2doc/mml2omml.xsl
CHANGED
@@ -1087,8 +1087,16 @@
|
|
1087
1087
|
<xsl:attribute name="m:val">bi</xsl:attribute>
|
1088
1088
|
</sty>
|
1089
1089
|
</xsl:when>
|
1090
|
-
<xsl:when test="$font='monospace'"
|
1090
|
+
<xsl:when test="$font='monospace'">
|
1091
1091
|
<!-- We can't do monospace, so leave empty -->
|
1092
|
+
<!-- NN 2020 https://github.com/metanorma/html2doc/issues/47 no, we will -->
|
1093
|
+
<scr>
|
1094
|
+
<xsl:attribute name="m:val">monospace</xsl:attribute>
|
1095
|
+
</scr>
|
1096
|
+
<sty>
|
1097
|
+
<xsl:attribute name="m:val">p</xsl:attribute>
|
1098
|
+
</sty>
|
1099
|
+
</xsl:when>
|
1092
1100
|
<xsl:when test="$font='bold'">
|
1093
1101
|
<sty>
|
1094
1102
|
<xsl:attribute name="m:val">b</xsl:attribute>
|
data/lib/html2doc/notes.rb
CHANGED
@@ -6,6 +6,7 @@ module Html2Doc
|
|
6
6
|
fn = []
|
7
7
|
docxml.xpath("//a").each do |a|
|
8
8
|
next unless process_footnote_link(docxml, a, i, fn)
|
9
|
+
|
9
10
|
i += 1
|
10
11
|
end
|
11
12
|
process_footnote_texts(docxml, fn)
|
@@ -22,13 +23,13 @@ module Html2Doc
|
|
22
23
|
footnote_cleanup(docxml)
|
23
24
|
end
|
24
25
|
|
25
|
-
def self.footnote_div_to_p(
|
26
|
-
if %w{div aside}.include?
|
27
|
-
if
|
28
|
-
|
26
|
+
def self.footnote_div_to_p(elem)
|
27
|
+
if %w{div aside}.include? elem.name
|
28
|
+
if elem.at(".//p")
|
29
|
+
elem.replace(elem.children)
|
29
30
|
else
|
30
|
-
|
31
|
-
|
31
|
+
elem.name = "p"
|
32
|
+
elem["class"] = "MsoFootnoteText"
|
32
33
|
end
|
33
34
|
end
|
34
35
|
end
|
@@ -36,34 +37,36 @@ module Html2Doc
|
|
36
37
|
FN = "<span class='MsoFootnoteReference'>"\
|
37
38
|
"<span style='mso-special-character:footnote'/></span>".freeze
|
38
39
|
|
39
|
-
def self.footnote_container(docxml,
|
40
|
-
ref = docxml&.at("//a[@href='#_ftn#{
|
41
|
-
gsub(/>\n</, "><") || FN
|
40
|
+
def self.footnote_container(docxml, idx)
|
41
|
+
ref = docxml&.at("//a[@href='#_ftn#{idx}']")&.children&.to_xml(indent: 0)
|
42
|
+
&.gsub(/>\n</, "><") || FN
|
42
43
|
<<~DIV
|
43
|
-
<div style='mso-element:footnote' id='ftn#{
|
44
|
-
<a style='mso-footnote-id:ftn#{
|
45
|
-
name='_ftnref#{
|
44
|
+
<div style='mso-element:footnote' id='ftn#{idx}'>
|
45
|
+
<a style='mso-footnote-id:ftn#{idx}' href='#_ftn#{idx}'
|
46
|
+
name='_ftnref#{idx}' title='' id='_ftnref#{idx}'>#{ref.strip}</a></div>
|
46
47
|
DIV
|
47
48
|
end
|
48
49
|
|
49
|
-
def self.process_footnote_link(docxml,
|
50
|
-
return false unless footnote?(
|
51
|
-
|
50
|
+
def self.process_footnote_link(docxml, elem, idx, footnote)
|
51
|
+
return false unless footnote?(elem)
|
52
|
+
|
53
|
+
href = elem["href"].gsub(/^#/, "")
|
52
54
|
note = docxml.at("//*[@name = '#{href}' or @id = '#{href}']")
|
53
55
|
return false if note.nil?
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
56
|
+
|
57
|
+
set_footnote_link_attrs(elem, idx)
|
58
|
+
if elem.at("./span[@class = 'MsoFootnoteReference']")
|
59
|
+
elem.children.each do |c|
|
60
|
+
if c.name == "span" && c["class"] == "MsoFootnoteReference"
|
58
61
|
c.replace(FN)
|
59
62
|
else
|
60
63
|
c.wrap("<span class='MsoFootnoteReference'></span>")
|
61
64
|
end
|
62
65
|
end
|
63
66
|
else
|
64
|
-
|
67
|
+
elem.children = FN
|
65
68
|
end
|
66
|
-
|
69
|
+
footnote << transform_footnote_text(note)
|
67
70
|
end
|
68
71
|
|
69
72
|
def self.transform_footnote_text(note)
|
@@ -76,16 +79,16 @@ module Html2Doc
|
|
76
79
|
note.remove
|
77
80
|
end
|
78
81
|
|
79
|
-
def self.footnote?(
|
80
|
-
|
81
|
-
|
82
|
+
def self.footnote?(elem)
|
83
|
+
elem["epub:type"]&.casecmp("footnote")&.zero? ||
|
84
|
+
elem["class"]&.casecmp("footnote")&.zero?
|
82
85
|
end
|
83
86
|
|
84
|
-
def self.set_footnote_link_attrs(
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
87
|
+
def self.set_footnote_link_attrs(elem, idx)
|
88
|
+
elem["style"] = "mso-footnote-id:ftn#{idx}"
|
89
|
+
elem["href"] = "#_ftn#{idx}"
|
90
|
+
elem["name"] = "_ftnref#{idx}"
|
91
|
+
elem["title"] = ""
|
89
92
|
end
|
90
93
|
|
91
94
|
# We expect that the content of the footnote text received is one or
|
@@ -94,8 +97,8 @@ module Html2Doc
|
|
94
97
|
# are present in the HTML, they need to have been cleaned out before
|
95
98
|
# passing to this gem
|
96
99
|
def self.footnote_cleanup(docxml)
|
97
|
-
docxml.xpath('//div[@style="mso-element:footnote"]/a')
|
98
|
-
each do |x|
|
100
|
+
docxml.xpath('//div[@style="mso-element:footnote"]/a')
|
101
|
+
.each do |x|
|
99
102
|
n = x.next_element
|
100
103
|
n&.children&.first&.add_previous_sibling(x.remove)
|
101
104
|
end
|
data/lib/html2doc/version.rb
CHANGED
data/spec/html2doc_spec.rb
CHANGED
@@ -1,270 +1,276 @@
|
|
1
1
|
require "base64"
|
2
2
|
|
3
|
-
def html_input(
|
3
|
+
def html_input(xml)
|
4
4
|
<<~HTML
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
<html><head><title>blank</title>
|
6
|
+
<meta name="Originator" content="Me"/>
|
7
|
+
</head>
|
8
|
+
<body>
|
9
|
+
#{xml}
|
10
|
+
</body></html>
|
11
11
|
HTML
|
12
12
|
end
|
13
13
|
|
14
|
-
def html_input_no_title(
|
14
|
+
def html_input_no_title(xml)
|
15
15
|
<<~HTML
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
16
|
+
<html><head>
|
17
|
+
<meta name="Originator" content="Me"/>
|
18
|
+
</head>
|
19
|
+
<body>
|
20
|
+
#{xml}
|
21
|
+
</body></html>
|
22
22
|
HTML
|
23
23
|
end
|
24
24
|
|
25
|
-
def html_input_empty_head(
|
25
|
+
def html_input_empty_head(xml)
|
26
26
|
<<~HTML
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
27
|
+
<html><head></head>
|
28
|
+
<body>
|
29
|
+
#{xml}
|
30
|
+
</body></html>
|
31
31
|
HTML
|
32
32
|
end
|
33
33
|
|
34
|
-
WORD_HDR = <<~HDR
|
35
|
-
MIME-Version: 1.0
|
36
|
-
Content-Type: multipart/related; boundary="----=_NextPart_"
|
37
|
-
|
38
|
-
------=_NextPart_
|
39
|
-
Content-
|
40
|
-
Content-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
<
|
45
|
-
<
|
46
|
-
<w:
|
47
|
-
<w:
|
48
|
-
<w:
|
49
|
-
|
50
|
-
</
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
<
|
56
|
-
|
34
|
+
WORD_HDR = <<~HDR.freeze
|
35
|
+
MIME-Version: 1.0
|
36
|
+
Content-Type: multipart/related; boundary="----=_NextPart_"
|
37
|
+
|
38
|
+
------=_NextPart_
|
39
|
+
Content-ID: <test.htm>
|
40
|
+
Content-Disposition: inline; filename="test.htm"
|
41
|
+
Content-Type: text/html; charset="utf-8"
|
42
|
+
|
43
|
+
<?xml version="1.0"?>
|
44
|
+
<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40"><head><!--[if gte mso 9]>
|
45
|
+
<xml>
|
46
|
+
<w:WordDocument>
|
47
|
+
<w:View>Print</w:View>
|
48
|
+
<w:Zoom>100</w:Zoom>
|
49
|
+
<w:DoNotOptimizeForBrowser/>
|
50
|
+
</w:WordDocument>
|
51
|
+
</xml>
|
52
|
+
<![endif]-->
|
53
|
+
<meta http-equiv=Content-Type content="text/html; charset=utf-8"/>
|
54
|
+
|
55
|
+
<link rel=File-List href="cid:filelist.xml"/>
|
56
|
+
<title>blank</title><style><![CDATA[
|
57
|
+
<!--
|
57
58
|
HDR
|
58
59
|
|
59
|
-
WORD_HDR_END = <<~HDR
|
60
|
-
-->
|
61
|
-
]]></style>
|
62
|
-
<meta name="Originator" content="Me"/>
|
63
|
-
</head>
|
60
|
+
WORD_HDR_END = <<~HDR.freeze
|
61
|
+
-->
|
62
|
+
]]></style>
|
63
|
+
<meta name="Originator" content="Me"/>
|
64
|
+
</head>
|
64
65
|
HDR
|
65
66
|
|
66
67
|
def word_body(x, fn)
|
67
68
|
<<~BODY
|
68
|
-
<body>
|
69
|
-
|
70
|
-
|
69
|
+
<body>
|
70
|
+
#{x}
|
71
|
+
#{fn}</body></html>
|
71
72
|
BODY
|
72
73
|
end
|
73
74
|
|
74
|
-
WORD_FTR1 = <<~FTR
|
75
|
+
WORD_FTR1 = <<~FTR.freeze
|
75
76
|
------=_NextPart_
|
76
|
-
Content-
|
77
|
-
Content-
|
78
|
-
Content-
|
77
|
+
Content-ID: <filelist.xml>
|
78
|
+
Content-Disposition: inline; filename="filelist.xml"
|
79
|
+
Content-Transfer-Encoding: base64
|
80
|
+
Content-Type: #{Html2Doc::mime_type('filelist.xml')}
|
79
81
|
|
80
|
-
PHhtbCB4bWxuczpvPSJ1cm46c2NoZW1hcy1taWNyb3NvZnQtY29tOm9mZmljZTpvZmZpY2UiPgog
|
81
|
-
ICAgICAgIDxvOk1haW5GaWxlIEhSZWY9Ii4uL3Rlc3QuaHRtIi8+ICA8bzpGaWxlIEhSZWY9ImZp
|
82
|
-
bGVsaXN0LnhtbCIvPgo8L3htbD4K
|
82
|
+
PHhtbCB4bWxuczpvPSJ1cm46c2NoZW1hcy1taWNyb3NvZnQtY29tOm9mZmljZTpvZmZpY2UiPgog
|
83
|
+
ICAgICAgIDxvOk1haW5GaWxlIEhSZWY9Ii4uL3Rlc3QuaHRtIi8+ICA8bzpGaWxlIEhSZWY9ImZp
|
84
|
+
bGVsaXN0LnhtbCIvPgo8L3htbD4K
|
83
85
|
|
84
|
-
------=_NextPart_--
|
86
|
+
------=_NextPart_--
|
85
87
|
FTR
|
86
88
|
|
87
|
-
WORD_FTR2 = <<~FTR
|
89
|
+
WORD_FTR2 = <<~FTR.freeze
|
90
|
+
------=_NextPart_
|
91
|
+
Content-ID: <filelist.xml>
|
92
|
+
Content-Disposition: inline; filename="filelist.xml"
|
93
|
+
Content-Transfer-Encoding: base64
|
94
|
+
Content-Type: #{Html2Doc::mime_type('filelist.xml')}
|
95
|
+
PHhtbCB4bWxuczpvPSJ1cm46c2NoZW1hcy1taWNyb3NvZnQtY29tOm9mZmljZTpvZmZpY2UiPgog
|
96
|
+
ICAgICAgIDxvOk1haW5GaWxlIEhSZWY9Ii4uL3Rlc3QuaHRtIi8+ICA8bzpGaWxlIEhSZWY9ImZp
|
97
|
+
bGVsaXN0LnhtbCIvPgogIDxvOkZpbGUgSFJlZj0iaGVhZGVyLmh0bWwiLz4KPC94bWw+Cg==
|
88
98
|
------=_NextPart_
|
89
|
-
Content-Location: file:///C:/Doc/test_files/filelist.xml
|
90
|
-
Content-Transfer-Encoding: base64
|
91
|
-
Content-Type: #{Html2Doc::mime_type('filelist.xml')}
|
92
|
-
PHhtbCB4bWxuczpvPSJ1cm46c2NoZW1hcy1taWNyb3NvZnQtY29tOm9mZmljZTpvZmZpY2UiPgog
|
93
|
-
ICAgICAgIDxvOk1haW5GaWxlIEhSZWY9Ii4uL3Rlc3QuaHRtIi8+ICA8bzpGaWxlIEhSZWY9ImZp
|
94
|
-
bGVsaXN0LnhtbCIvPgogIDxvOkZpbGUgSFJlZj0iaGVhZGVyLmh0bWwiLz4KPC94bWw+Cg==
|
95
|
-
------=_NextPart_
|
96
99
|
FTR
|
97
100
|
|
98
|
-
WORD_FTR3 = <<~FTR
|
99
|
-
------=_NextPart_
|
100
|
-
Content-
|
101
|
-
Content-
|
102
|
-
Content-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
Content-
|
111
|
-
Content-
|
112
|
-
|
101
|
+
WORD_FTR3 = <<~FTR.freeze
|
102
|
+
------=_NextPart_
|
103
|
+
Content-ID: <filelist.xml>
|
104
|
+
Content-Disposition: inline; filename="filelist.xml"
|
105
|
+
Content-Transfer-Encoding: base64
|
106
|
+
Content-Type: #{Html2Doc::mime_type('filelist.xml')}
|
107
|
+
|
108
|
+
PHhtbCB4bWxuczpvPSJ1cm46c2NoZW1hcy1taWNyb3NvZnQtY29tOm9mZmljZTpvZmZpY2UiPgog
|
109
|
+
ICAgICAgIDxvOk1haW5GaWxlIEhSZWY9Ii4uL3Rlc3QuaHRtIi8+ICA8bzpGaWxlIEhSZWY9IjFh
|
110
|
+
YzIwNjVmLTAzZjAtNGM3YS1iOWE2LTkyZTgyMDU5MWJmMC5wbmciLz4KICA8bzpGaWxlIEhSZWY9
|
111
|
+
ImZpbGVsaXN0LnhtbCIvPgo8L3htbD4K
|
112
|
+
------=_NextPart_
|
113
|
+
Content-ID: <cb7b0d19-891e-4634-815a-570d019d454c.png>
|
114
|
+
Content-Disposition: inline; filename="cb7b0d19-891e-4634-815a-570d019d454c.png"
|
115
|
+
Content-Transfer-Encoding: base64
|
116
|
+
Content-Type: image/png
|
117
|
+
------=_NextPart_--
|
113
118
|
FTR
|
114
119
|
|
115
|
-
HEADERHTML
|
116
|
-
<html xmlns:v="urn:schemas-microsoft-com:vml"
|
117
|
-
xmlns:o="urn:schemas-microsoft-com:office:office"
|
118
|
-
xmlns:w="urn:schemas-microsoft-com:office:word"
|
119
|
-
xmlns:m="http://schemas.microsoft.com/office/2004/12/omml"
|
120
|
-
xmlns:mv="http://macVmlSchemaUri" xmlns="http://www.w3.org/TR/REC-html40">
|
121
|
-
<head>
|
122
|
-
<meta name=Title content="">
|
123
|
-
<meta name=Keywords content="">
|
124
|
-
<meta http-equiv=Content-Type content="text/html; charset=utf-8">
|
125
|
-
<meta name=ProgId content=Word.Document>
|
126
|
-
<meta name=Generator content="Microsoft Word 15">
|
127
|
-
<meta name=Originator content="Microsoft Word 15">
|
128
|
-
<link id=Main-File rel=Main-File href="FILENAME.html">
|
129
|
-
<!--[if gte mso 9]><xml>
|
130
|
-
<o:shapedefaults v:ext="edit" spidmax="2049"/>
|
131
|
-
</xml><![endif]-->
|
132
|
-
</head>
|
133
|
-
<body lang=EN link=blue vlink="#954F72">
|
134
|
-
<div style='mso-element:footnote-separator' id=fs>
|
135
|
-
<p class=MsoNormal style='margin-bottom:0cm;margin-bottom:.0001pt;line-height:
|
136
|
-
normal'><span lang=EN-GB><span style='mso-special-character:footnote-separator'><![if !supportFootnotes]>
|
137
|
-
<hr align=left size=1 width="33%">
|
138
|
-
<![endif]></span></span></p>
|
139
|
-
</div>
|
140
|
-
<div style='mso-element:footnote-continuation-separator' id=fcs>
|
141
|
-
<p class=MsoNormal style='margin-bottom:0cm;margin-bottom:.0001pt;line-height:
|
142
|
-
normal'><span lang=EN-GB><span style='mso-special-character:footnote-continuation-separator'><![if !supportFootnotes]>
|
143
|
-
<hr align=left size=1>
|
144
|
-
<![endif]></span></span></p>
|
145
|
-
</div>
|
146
|
-
<div style='mso-element:endnote-separator' id=es>
|
147
|
-
<p class=MsoNormal style='margin-bottom:0cm;margin-bottom:.0001pt;line-height:
|
148
|
-
normal'><span lang=EN-GB><span style='mso-special-character:footnote-separator'><![if !supportFootnotes]>
|
149
|
-
<hr align=left size=1 width="33%">
|
150
|
-
<![endif]></span></span></p>
|
151
|
-
</div>
|
152
|
-
<div style='mso-element:endnote-continuation-separator' id=ecs>
|
153
|
-
<p class=MsoNormal style='margin-bottom:0cm;margin-bottom:.0001pt;line-height:
|
154
|
-
normal'><span lang=EN-GB><span style='mso-special-character:footnote-continuation-separator'><![if !supportFootnotes]>
|
155
|
-
<hr align=left size=1>
|
156
|
-
<![endif]></span></span></p>
|
157
|
-
</div>
|
158
|
-
<div style='mso-element:header' id=eh1>
|
159
|
-
<p class=MsoHeader align=left style='text-align:left;line-height:12.0pt;
|
160
|
-
mso-line-height-rule:exactly'><span lang=EN-GB>ISO/IEC&nbsp;CD 17301-1:2016(E)</span></p>
|
161
|
-
</div>
|
162
|
-
<div style='mso-element:header' id=h1>
|
163
|
-
<p class=MsoHeader style='margin-bottom:18.0pt'><span lang=EN-GB
|
164
|
-
style='font-size:10.0pt;mso-bidi-font-size:11.0pt;font-weight:normal'>©
|
165
|
-
ISO/IEC&nbsp;2016&nbsp;– All rights reserved</span><span lang=EN-GB
|
166
|
-
style='font-weight:normal'><o:p></o:p></span></p>
|
167
|
-
</div>
|
168
|
-
<div style='mso-element:footer' id=ef1>
|
169
|
-
<p class=MsoFooter style='margin-top:12.0pt;line-height:12.0pt;mso-line-height-rule:
|
170
|
-
exactly'><!--[if supportFields]><b style='mso-bidi-font-weight:normal'><span
|
171
|
-
lang=EN-GB style='font-size:10.0pt;mso-bidi-font-size:11.0pt'><span
|
172
|
-
style='mso-element:field-begin'></span><span
|
173
|
-
style='mso-spacerun:yes'> </span>PAGE<span style='mso-spacerun:yes'>  
|
174
|
-
</span>\\* MERGEFORMAT <span style='mso-element:field-separator'></span></span></b><![endif]--><b
|
175
|
-
style='mso-bidi-font-weight:normal'><span lang=EN-GB style='font-size:10.0pt;
|
176
|
-
mso-bidi-font-size:11.0pt'><span style='mso-no-proof:yes'>2</span></span></b><!--[if supportFields]><b
|
177
|
-
style='mso-bidi-font-weight:normal'><span lang=EN-GB style='font-size:10.0pt;
|
178
|
-
mso-bidi-font-size:11.0pt'><span style='mso-element:field-end'></span></span></b><![endif]--><span
|
179
|
-
lang=EN-GB style='font-size:10.0pt;mso-bidi-font-size:11.0pt'><span
|
180
|
-
style='mso-tab-count:1'>                                                                                                                                                                           </span>©
|
181
|
-
ISO/IEC&nbsp;2016&nbsp;– All rights reserved<o:p></o:p></span></p>
|
182
|
-
</div>
|
183
|
-
<div style='mso-element:header' id=eh2>
|
184
|
-
<p class=MsoHeader align=left style='text-align:left;line-height:12.0pt;
|
185
|
-
mso-line-height-rule:exactly'><span lang=EN-GB>ISO/IEC&nbsp;CD 17301-1:2016(E)</span></p>
|
186
|
-
</div>
|
187
|
-
<div style='mso-element:header' id=h2>
|
188
|
-
<p class=MsoHeader align=right style='text-align:right;line-height:12.0pt;
|
189
|
-
mso-line-height-rule:exactly'><span lang=EN-GB>ISO/IEC&nbsp;CD 17301-1:2016(E)</span></p>
|
190
|
-
</div>
|
191
|
-
<div style='mso-element:footer' id=ef2>
|
192
|
-
<p class=MsoFooter style='line-height:12.0pt;mso-line-height-rule:exactly'><!--[if supportFields]><span
|
193
|
-
lang=EN-GB style='font-size:10.0pt;mso-bidi-font-size:11.0pt'><span
|
194
|
-
style='mso-element:field-begin'></span><span
|
195
|
-
style='mso-spacerun:yes'> </span>PAGE<span style='mso-spacerun:yes'>  
|
196
|
-
</span>\\* MERGEFORMAT <span style='mso-element:field-separator'></span></span><![endif]--><span
|
197
|
-
lang=EN-GB style='font-size:10.0pt;mso-bidi-font-size:11.0pt'><span
|
198
|
-
style='mso-no-proof:yes'>ii</span></span><!--[if supportFields]><span
|
199
|
-
lang=EN-GB style='font-size:10.0pt;mso-bidi-font-size:11.0pt'><span
|
200
|
-
style='mso-element:field-end'></span></span><![endif]--><span lang=EN-GB
|
201
|
-
style='font-size:10.0pt;mso-bidi-font-size:11.0pt'><span style='mso-tab-count:
|
202
|
-
1'>                                                                                                                                                                           </span>©
|
203
|
-
ISO/IEC&nbsp;2016&nbsp;– All rights reserved<o:p></o:p></span></p>
|
204
|
-
</div>
|
205
|
-
<div style='mso-element:footer' id=f2>
|
206
|
-
<p class=MsoFooter style='line-height:12.0pt'><span lang=EN-GB
|
207
|
-
style='font-size:10.0pt;mso-bidi-font-size:11.0pt'>© ISO/IEC&nbsp;2016&nbsp;– All
|
208
|
-
rights reserved<span style='mso-tab-count:1'>                                                                                                                                                                          </span></span><!--[if supportFields]><span
|
209
|
-
lang=EN-GB style='font-size:10.0pt;mso-bidi-font-size:11.0pt'><span
|
210
|
-
style='mso-element:field-begin'></span> PAGE<span style='mso-spacerun:yes'>  
|
211
|
-
</span>\\* MERGEFORMAT <span style='mso-element:field-separator'></span></span><![endif]--><span
|
212
|
-
lang=EN-GB style='font-size:10.0pt;mso-bidi-font-size:11.0pt'><span
|
213
|
-
style='mso-no-proof:yes'>iii</span></span><!--[if supportFields]><span
|
214
|
-
lang=EN-GB style='font-size:10.0pt;mso-bidi-font-size:11.0pt'><span
|
215
|
-
style='mso-element:field-end'></span></span><![endif]--><span lang=EN-GB
|
216
|
-
style='font-size:10.0pt;mso-bidi-font-size:11.0pt'><o:p></o:p></span></p>
|
217
|
-
</div>
|
218
|
-
<div style='mso-element:footer' id=ef3>
|
219
|
-
<p class=MsoFooter style='margin-top:12.0pt;line-height:12.0pt;mso-line-height-rule:
|
220
|
-
exactly'><!--[if supportFields]><b style='mso-bidi-font-weight:normal'><span
|
221
|
-
lang=EN-GB style='font-size:10.0pt;mso-bidi-font-size:11.0pt'><span
|
222
|
-
style='mso-element:field-begin'></span><span
|
223
|
-
style='mso-spacerun:yes'> </span>PAGE<span style='mso-spacerun:yes'>  
|
224
|
-
</span>\\* MERGEFORMAT <span style='mso-element:field-separator'></span></span></b><![endif]--><b
|
225
|
-
style='mso-bidi-font-weight:normal'><span lang=EN-GB style='font-size:10.0pt;
|
226
|
-
mso-bidi-font-size:11.0pt'><span style='mso-no-proof:yes'>2</span></span></b><!--[if supportFields]><b
|
227
|
-
style='mso-bidi-font-weight:normal'><span lang=EN-GB style='font-size:10.0pt;
|
228
|
-
mso-bidi-font-size:11.0pt'><span style='mso-element:field-end'></span></span></b><![endif]--><span
|
229
|
-
lang=EN-GB style='font-size:10.0pt;mso-bidi-font-size:11.0pt'><span
|
230
|
-
style='mso-tab-count:1'>                                                                                                                                                                           </span>©
|
231
|
-
ISO/IEC&nbsp;2016&nbsp;– All rights reserved<o:p></o:p></span></p>
|
232
|
-
</div>
|
233
|
-
<div style='mso-element:footer' id=f3>
|
234
|
-
<p class=MsoFooter style='line-height:12.0pt'><span lang=EN-GB
|
235
|
-
style='font-size:10.0pt;mso-bidi-font-size:11.0pt'>© ISO/IEC&nbsp;2016&nbsp;– All
|
236
|
-
rights reserved<span style='mso-tab-count:1'>                                                                                                                                                                           </span></span><!--[if supportFields]><b
|
237
|
-
style='mso-bidi-font-weight:normal'><span lang=EN-GB style='font-size:10.0pt;
|
238
|
-
mso-bidi-font-size:11.0pt'><span style='mso-element:field-begin'></span>
|
239
|
-
PAGE<span style='mso-spacerun:yes'>   </span>\\* MERGEFORMAT <span
|
240
|
-
style='mso-element:field-separator'></span></span></b><![endif]--><b
|
241
|
-
style='mso-bidi-font-weight:normal'><span lang=EN-GB style='font-size:10.0pt;
|
242
|
-
mso-bidi-font-size:11.0pt'><span style='mso-no-proof:yes'>3</span></span></b><!--[if supportFields]><b
|
243
|
-
style='mso-bidi-font-weight:normal'><span lang=EN-GB style='font-size:10.0pt;
|
244
|
-
mso-bidi-font-size:11.0pt'><span style='mso-element:field-end'></span></span></b><![endif]--><span
|
245
|
-
lang=EN-GB style='font-size:10.0pt;mso-bidi-font-size:11.0pt'><o:p></o:p></span></p>
|
246
|
-
</div>
|
247
|
-
</body>
|
248
|
-
</html>
|
120
|
+
HEADERHTML = <<~FTR.freeze
|
121
|
+
<html xmlns:v="urn:schemas-microsoft-com:vml"
|
122
|
+
xmlns:o="urn:schemas-microsoft-com:office:office"
|
123
|
+
xmlns:w="urn:schemas-microsoft-com:office:word"
|
124
|
+
xmlns:m="http://schemas.microsoft.com/office/2004/12/omml"
|
125
|
+
xmlns:mv="http://macVmlSchemaUri" xmlns="http://www.w3.org/TR/REC-html40">
|
126
|
+
<head>
|
127
|
+
<meta name=Title content="">
|
128
|
+
<meta name=Keywords content="">
|
129
|
+
<meta http-equiv=Content-Type content="text/html; charset=utf-8">
|
130
|
+
<meta name=ProgId content=Word.Document>
|
131
|
+
<meta name=Generator content="Microsoft Word 15">
|
132
|
+
<meta name=Originator content="Microsoft Word 15">
|
133
|
+
<link id=Main-File rel=Main-File href="FILENAME.html">
|
134
|
+
<!--[if gte mso 9]><xml>
|
135
|
+
<o:shapedefaults v:ext="edit" spidmax="2049"/>
|
136
|
+
</xml><![endif]-->
|
137
|
+
</head>
|
138
|
+
<body lang=EN link=blue vlink="#954F72">
|
139
|
+
<div style='mso-element:footnote-separator' id=fs>
|
140
|
+
<p class=MsoNormal style='margin-bottom:0cm;margin-bottom:.0001pt;line-height:
|
141
|
+
normal'><span lang=EN-GB><span style='mso-special-character:footnote-separator'><![if !supportFootnotes]>
|
142
|
+
<hr align=left size=1 width="33%">
|
143
|
+
<![endif]></span></span></p>
|
144
|
+
</div>
|
145
|
+
<div style='mso-element:footnote-continuation-separator' id=fcs>
|
146
|
+
<p class=MsoNormal style='margin-bottom:0cm;margin-bottom:.0001pt;line-height:
|
147
|
+
normal'><span lang=EN-GB><span style='mso-special-character:footnote-continuation-separator'><![if !supportFootnotes]>
|
148
|
+
<hr align=left size=1>
|
149
|
+
<![endif]></span></span></p>
|
150
|
+
</div>
|
151
|
+
<div style='mso-element:endnote-separator' id=es>
|
152
|
+
<p class=MsoNormal style='margin-bottom:0cm;margin-bottom:.0001pt;line-height:
|
153
|
+
normal'><span lang=EN-GB><span style='mso-special-character:footnote-separator'><![if !supportFootnotes]>
|
154
|
+
<hr align=left size=1 width="33%">
|
155
|
+
<![endif]></span></span></p>
|
156
|
+
</div>
|
157
|
+
<div style='mso-element:endnote-continuation-separator' id=ecs>
|
158
|
+
<p class=MsoNormal style='margin-bottom:0cm;margin-bottom:.0001pt;line-height:
|
159
|
+
normal'><span lang=EN-GB><span style='mso-special-character:footnote-continuation-separator'><![if !supportFootnotes]>
|
160
|
+
<hr align=left size=1>
|
161
|
+
<![endif]></span></span></p>
|
162
|
+
</div>
|
163
|
+
<div style='mso-element:header' id=eh1>
|
164
|
+
<p class=MsoHeader align=left style='text-align:left;line-height:12.0pt;
|
165
|
+
mso-line-height-rule:exactly'><span lang=EN-GB>ISO/IEC&nbsp;CD 17301-1:2016(E)</span></p>
|
166
|
+
</div>
|
167
|
+
<div style='mso-element:header' id=h1>
|
168
|
+
<p class=MsoHeader style='margin-bottom:18.0pt'><span lang=EN-GB
|
169
|
+
style='font-size:10.0pt;mso-bidi-font-size:11.0pt;font-weight:normal'>©
|
170
|
+
ISO/IEC&nbsp;2016&nbsp;– All rights reserved</span><span lang=EN-GB
|
171
|
+
style='font-weight:normal'><o:p></o:p></span></p>
|
172
|
+
</div>
|
173
|
+
<div style='mso-element:footer' id=ef1>
|
174
|
+
<p class=MsoFooter style='margin-top:12.0pt;line-height:12.0pt;mso-line-height-rule:
|
175
|
+
exactly'><!--[if supportFields]><b style='mso-bidi-font-weight:normal'><span
|
176
|
+
lang=EN-GB style='font-size:10.0pt;mso-bidi-font-size:11.0pt'><span
|
177
|
+
style='mso-element:field-begin'></span><span
|
178
|
+
style='mso-spacerun:yes'> </span>PAGE<span style='mso-spacerun:yes'>  
|
179
|
+
</span>\\* MERGEFORMAT <span style='mso-element:field-separator'></span></span></b><![endif]--><b
|
180
|
+
style='mso-bidi-font-weight:normal'><span lang=EN-GB style='font-size:10.0pt;
|
181
|
+
mso-bidi-font-size:11.0pt'><span style='mso-no-proof:yes'>2</span></span></b><!--[if supportFields]><b
|
182
|
+
style='mso-bidi-font-weight:normal'><span lang=EN-GB style='font-size:10.0pt;
|
183
|
+
mso-bidi-font-size:11.0pt'><span style='mso-element:field-end'></span></span></b><![endif]--><span
|
184
|
+
lang=EN-GB style='font-size:10.0pt;mso-bidi-font-size:11.0pt'><span
|
185
|
+
style='mso-tab-count:1'>                                                                                                                                                                           </span>©
|
186
|
+
ISO/IEC&nbsp;2016&nbsp;– All rights reserved<o:p></o:p></span></p>
|
187
|
+
</div>
|
188
|
+
<div style='mso-element:header' id=eh2>
|
189
|
+
<p class=MsoHeader align=left style='text-align:left;line-height:12.0pt;
|
190
|
+
mso-line-height-rule:exactly'><span lang=EN-GB>ISO/IEC&nbsp;CD 17301-1:2016(E)</span></p>
|
191
|
+
</div>
|
192
|
+
<div style='mso-element:header' id=h2>
|
193
|
+
<p class=MsoHeader align=right style='text-align:right;line-height:12.0pt;
|
194
|
+
mso-line-height-rule:exactly'><span lang=EN-GB>ISO/IEC&nbsp;CD 17301-1:2016(E)</span></p>
|
195
|
+
</div>
|
196
|
+
<div style='mso-element:footer' id=ef2>
|
197
|
+
<p class=MsoFooter style='line-height:12.0pt;mso-line-height-rule:exactly'><!--[if supportFields]><span
|
198
|
+
lang=EN-GB style='font-size:10.0pt;mso-bidi-font-size:11.0pt'><span
|
199
|
+
style='mso-element:field-begin'></span><span
|
200
|
+
style='mso-spacerun:yes'> </span>PAGE<span style='mso-spacerun:yes'>  
|
201
|
+
</span>\\* MERGEFORMAT <span style='mso-element:field-separator'></span></span><![endif]--><span
|
202
|
+
lang=EN-GB style='font-size:10.0pt;mso-bidi-font-size:11.0pt'><span
|
203
|
+
style='mso-no-proof:yes'>ii</span></span><!--[if supportFields]><span
|
204
|
+
lang=EN-GB style='font-size:10.0pt;mso-bidi-font-size:11.0pt'><span
|
205
|
+
style='mso-element:field-end'></span></span><![endif]--><span lang=EN-GB
|
206
|
+
style='font-size:10.0pt;mso-bidi-font-size:11.0pt'><span style='mso-tab-count:
|
207
|
+
1'>                                                                                                                                                                           </span>©
|
208
|
+
ISO/IEC&nbsp;2016&nbsp;– All rights reserved<o:p></o:p></span></p>
|
209
|
+
</div>
|
210
|
+
<div style='mso-element:footer' id=f2>
|
211
|
+
<p class=MsoFooter style='line-height:12.0pt'><span lang=EN-GB
|
212
|
+
style='font-size:10.0pt;mso-bidi-font-size:11.0pt'>© ISO/IEC&nbsp;2016&nbsp;– All
|
213
|
+
rights reserved<span style='mso-tab-count:1'>                                                                                                                                                                          </span></span><!--[if supportFields]><span
|
214
|
+
lang=EN-GB style='font-size:10.0pt;mso-bidi-font-size:11.0pt'><span
|
215
|
+
style='mso-element:field-begin'></span> PAGE<span style='mso-spacerun:yes'>  
|
216
|
+
</span>\\* MERGEFORMAT <span style='mso-element:field-separator'></span></span><![endif]--><span
|
217
|
+
lang=EN-GB style='font-size:10.0pt;mso-bidi-font-size:11.0pt'><span
|
218
|
+
style='mso-no-proof:yes'>iii</span></span><!--[if supportFields]><span
|
219
|
+
lang=EN-GB style='font-size:10.0pt;mso-bidi-font-size:11.0pt'><span
|
220
|
+
style='mso-element:field-end'></span></span><![endif]--><span lang=EN-GB
|
221
|
+
style='font-size:10.0pt;mso-bidi-font-size:11.0pt'><o:p></o:p></span></p>
|
222
|
+
</div>
|
223
|
+
<div style='mso-element:footer' id=ef3>
|
224
|
+
<p class=MsoFooter style='margin-top:12.0pt;line-height:12.0pt;mso-line-height-rule:
|
225
|
+
exactly'><!--[if supportFields]><b style='mso-bidi-font-weight:normal'><span
|
226
|
+
lang=EN-GB style='font-size:10.0pt;mso-bidi-font-size:11.0pt'><span
|
227
|
+
style='mso-element:field-begin'></span><span
|
228
|
+
style='mso-spacerun:yes'> </span>PAGE<span style='mso-spacerun:yes'>  
|
229
|
+
</span>\\* MERGEFORMAT <span style='mso-element:field-separator'></span></span></b><![endif]--><b
|
230
|
+
style='mso-bidi-font-weight:normal'><span lang=EN-GB style='font-size:10.0pt;
|
231
|
+
mso-bidi-font-size:11.0pt'><span style='mso-no-proof:yes'>2</span></span></b><!--[if supportFields]><b
|
232
|
+
style='mso-bidi-font-weight:normal'><span lang=EN-GB style='font-size:10.0pt;
|
233
|
+
mso-bidi-font-size:11.0pt'><span style='mso-element:field-end'></span></span></b><![endif]--><span
|
234
|
+
lang=EN-GB style='font-size:10.0pt;mso-bidi-font-size:11.0pt'><span
|
235
|
+
style='mso-tab-count:1'>                                                                                                                                                                           </span>©
|
236
|
+
ISO/IEC&nbsp;2016&nbsp;– All rights reserved<o:p></o:p></span></p>
|
237
|
+
</div>
|
238
|
+
<div style='mso-element:footer' id=f3>
|
239
|
+
<p class=MsoFooter style='line-height:12.0pt'><span lang=EN-GB
|
240
|
+
style='font-size:10.0pt;mso-bidi-font-size:11.0pt'>© ISO/IEC&nbsp;2016&nbsp;– All
|
241
|
+
rights reserved<span style='mso-tab-count:1'>                                                                                                                                                                           </span></span><!--[if supportFields]><b
|
242
|
+
style='mso-bidi-font-weight:normal'><span lang=EN-GB style='font-size:10.0pt;
|
243
|
+
mso-bidi-font-size:11.0pt'><span style='mso-element:field-begin'></span>
|
244
|
+
PAGE<span style='mso-spacerun:yes'>   </span>\\* MERGEFORMAT <span
|
245
|
+
style='mso-element:field-separator'></span></span></b><![endif]--><b
|
246
|
+
style='mso-bidi-font-weight:normal'><span lang=EN-GB style='font-size:10.0pt;
|
247
|
+
mso-bidi-font-size:11.0pt'><span style='mso-no-proof:yes'>3</span></span></b><!--[if supportFields]><b
|
248
|
+
style='mso-bidi-font-weight:normal'><span lang=EN-GB style='font-size:10.0pt;
|
249
|
+
mso-bidi-font-size:11.0pt'><span style='mso-element:field-end'></span></span></b><![endif]--><span
|
250
|
+
lang=EN-GB style='font-size:10.0pt;mso-bidi-font-size:11.0pt'><o:p></o:p></span></p>
|
251
|
+
</div>
|
252
|
+
</body>
|
253
|
+
</html>
|
249
254
|
FTR
|
250
255
|
|
251
|
-
ASCII_MATH='<m:nary><m:naryPr><m:chr m:val="∑"></m:chr><m:limLoc m:val="undOvr"></m:limLoc><m:grow m:val="on"></m:grow><m:subHide m:val="off"></m:subHide><m:supHide m:val="off"></m:supHide></m:naryPr><m:sub><m:r><m:t>i=1</m:t></m:r></m:sub><m:sup><m:r><m:t>n</m:t></m:r></m:sup><m:e><m:sSup><m:e><m:r><m:t>i</m:t></m:r></m:e><m:sup><m:r><m:t>3</m:t></m:r></m:sup></m:sSup></m:e></m:nary><m:r><m:t>=</m:t></m:r><m:sSup><m:e><m:d><m:dPr><m:sepChr m:val=","></m:sepChr></m:dPr><m:e><m:f><m:fPr><m:type m:val="bar"></m:type></m:fPr><m:num><m:r><m:t>n</m:t></m:r><m:d><m:dPr><m:sepChr m:val=","></m:sepChr></m:dPr><m:e><m:r><m:t>n+1</m:t></m:r></m:e></m:d></m:num><m:den><m:r><m:t>2</m:t></m:r></m:den></m:f></m:e></m:d></m:e><m:sup><m:r><m:t>2</m:t></m:r></m:sup></m:sSup>'
|
256
|
+
ASCII_MATH = '<m:nary><m:naryPr><m:chr m:val="∑"></m:chr><m:limLoc m:val="undOvr"></m:limLoc><m:grow m:val="on"></m:grow><m:subHide m:val="off"></m:subHide><m:supHide m:val="off"></m:supHide></m:naryPr><m:sub><m:r><m:t>i=1</m:t></m:r></m:sub><m:sup><m:r><m:t>n</m:t></m:r></m:sup><m:e><m:sSup><m:e><m:r><m:t>i</m:t></m:r></m:e><m:sup><m:r><m:t>3</m:t></m:r></m:sup></m:sSup></m:e></m:nary><m:r><m:t>=</m:t></m:r><m:sSup><m:e><m:d><m:dPr><m:sepChr m:val=","></m:sepChr></m:dPr><m:e><m:f><m:fPr><m:type m:val="bar"></m:type></m:fPr><m:num><m:r><m:t>n</m:t></m:r><m:d><m:dPr><m:sepChr m:val=","></m:sepChr></m:dPr><m:e><m:r><m:t>n+1</m:t></m:r></m:e></m:d></m:num><m:den><m:r><m:t>2</m:t></m:r></m:den></m:f></m:e></m:d></m:e><m:sup><m:r><m:t>2</m:t></m:r></m:sup></m:sSup>'.freeze
|
252
257
|
|
253
|
-
DEFAULT_STYLESHEET = File.read("lib/html2doc/wordstyle.css",
|
258
|
+
DEFAULT_STYLESHEET = File.read("lib/html2doc/wordstyle.css",
|
259
|
+
encoding: "utf-8").freeze
|
254
260
|
|
255
|
-
def guid_clean(
|
256
|
-
|
261
|
+
def guid_clean(xml)
|
262
|
+
xml.gsub(/NextPart_[0-9a-f.]+/, "NextPart_")
|
257
263
|
end
|
258
264
|
|
259
|
-
def image_clean(
|
260
|
-
|
261
|
-
gsub(%r{[0-9a-f-]+\.gif}, "image.gif")
|
262
|
-
gsub(%r{[0-9a-f-]+\.(jpeg|jpg)}, "image.jpg")
|
263
|
-
gsub(%r{------=_NextPart_\s+Content-Location: file:///C:/Doc/test_files/image\.(png|gif).*?\s-----=_NextPart_}m, "------=_NextPart_")
|
264
|
-
gsub(%r{Content-Type: image/(png|gif|jpeg)[^-]*------=_NextPart_-?-?}m, "")
|
265
|
-
gsub(%r{ICAgICAg[^-]*-----}m, "-----")
|
266
|
-
gsub(%r{\s*</img>\s*}m, "</img>")
|
267
|
-
gsub(%r{</body>\s*</html>}m, "</body></html>")
|
265
|
+
def image_clean(xml)
|
266
|
+
xml.gsub(%r{[0-9a-f-]+\.png}, "image.png")
|
267
|
+
.gsub(%r{[0-9a-f-]+\.gif}, "image.gif")
|
268
|
+
.gsub(%r{[0-9a-f-]+\.(jpeg|jpg)}, "image.jpg")
|
269
|
+
.gsub(%r{------=_NextPart_\s+Content-Location: file:///C:/Doc/test_files/image\.(png|gif).*?\s-----=_NextPart_}m, "------=_NextPart_")
|
270
|
+
.gsub(%r{Content-Type: image/(png|gif|jpeg)[^-]*------=_NextPart_-?-?}m, "")
|
271
|
+
.gsub(%r{ICAgICAg[^-]*-----}m, "-----")
|
272
|
+
.gsub(%r{\s*</img>\s*}m, "</img>")
|
273
|
+
.gsub(%r{</body>\s*</html>}m, "</body></html>")
|
268
274
|
end
|
269
275
|
|
270
276
|
RSpec.describe Html2Doc do
|
@@ -274,11 +280,11 @@ RSpec.describe Html2Doc do
|
|
274
280
|
|
275
281
|
it "processes a blank document" do
|
276
282
|
Html2Doc.process(html_input(""), filename: "test")
|
277
|
-
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
278
|
-
to match_fuzzy(<<~OUTPUT)
|
279
|
-
|
280
|
-
|
281
|
-
|
283
|
+
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
284
|
+
.to match_fuzzy(<<~OUTPUT)
|
285
|
+
#{WORD_HDR} #{DEFAULT_STYLESHEET} #{WORD_HDR_END}
|
286
|
+
#{word_body('', '<div style="mso-element:footnote-list"/>')} #{WORD_FTR1}
|
287
|
+
OUTPUT
|
282
288
|
end
|
283
289
|
|
284
290
|
it "removes any temp files" do
|
@@ -290,57 +296,59 @@ RSpec.describe Html2Doc do
|
|
290
296
|
end
|
291
297
|
|
292
298
|
it "processes a stylesheet in an HTML document with a title" do
|
293
|
-
Html2Doc.process(html_input(""),
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
+
Html2Doc.process(html_input(""),
|
300
|
+
filename: "test", stylesheet: "lib/html2doc/wordstyle.css")
|
301
|
+
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
302
|
+
.to match_fuzzy(<<~OUTPUT)
|
303
|
+
#{WORD_HDR} #{DEFAULT_STYLESHEET} #{WORD_HDR_END}
|
304
|
+
#{word_body('', '<div style="mso-element:footnote-list"/>')} #{WORD_FTR1}
|
305
|
+
OUTPUT
|
299
306
|
end
|
300
307
|
|
301
308
|
it "processes a stylesheet in an HTML document without a title" do
|
302
|
-
Html2Doc.process(html_input_no_title(""),
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
+
Html2Doc.process(html_input_no_title(""),
|
310
|
+
filename: "test", stylesheet: "lib/html2doc/wordstyle.css")
|
311
|
+
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
312
|
+
.to match_fuzzy(<<~OUTPUT)
|
313
|
+
#{WORD_HDR.sub('<title>blank</title>', '')}
|
314
|
+
#{DEFAULT_STYLESHEET} #{WORD_HDR_END}
|
315
|
+
#{word_body('', '<div style="mso-element:footnote-list"/>')} #{WORD_FTR1}
|
316
|
+
OUTPUT
|
309
317
|
end
|
310
318
|
|
311
319
|
it "processes a stylesheet in an HTML document with an empty head" do
|
312
320
|
Html2Doc.process(html_input_empty_head(""), filename: "test", stylesheet: "lib/html2doc/wordstyle.css")
|
313
|
-
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
314
|
-
to match_fuzzy(<<~OUTPUT)
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
321
|
+
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
322
|
+
.to match_fuzzy(<<~OUTPUT)
|
323
|
+
#{WORD_HDR.sub('<title>blank</title>', '')}
|
324
|
+
#{DEFAULT_STYLESHEET}
|
325
|
+
#{WORD_HDR_END.sub('<meta name="Originator" content="Me"/>' + "\n", '').sub("</style>\n</head>", '</style></head>')}
|
326
|
+
#{word_body('', '<div style="mso-element:footnote-list"/>')} #{WORD_FTR1}
|
327
|
+
OUTPUT
|
320
328
|
end
|
321
329
|
|
322
330
|
it "processes a header" do
|
323
331
|
Html2Doc.process(html_input(""), filename: "test", header_file: "spec/header.html")
|
324
332
|
html = guid_clean(File.read("test.doc", encoding: "utf-8"))
|
325
|
-
hdr = Base64.decode64(html.sub(%r{^.*Content-Location: file:///C:/Doc/test_files/header.html}, "")
|
326
|
-
sub(%r{^.*Content-Type: text/html charset="utf-8"}m, "")
|
327
|
-
sub(%r{------=_NextPart_--.*$}m, "")).force_encoding("UTF-8")
|
328
|
-
#expect(hdr.gsub(/\xa0/, " ")).to match_fuzzy(HEADERHTML)
|
329
|
-
expect(HTMLEntities.new.encode(hdr, :hexadecimal)
|
330
|
-
gsub(
|
331
|
-
gsub(
|
332
|
-
expect(html.sub(%r{Content-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
333
|
+
hdr = Base64.decode64(html.sub(%r{^.*Content-Location: file:///C:/Doc/test_files/header.html}, "")
|
334
|
+
.sub(%r{^.*Content-Type: text/html charset="utf-8"}m, "")
|
335
|
+
.sub(%r{------=_NextPart_--.*$}m, "")).force_encoding("UTF-8")
|
336
|
+
# expect(hdr.gsub(/\xa0/, " ")).to match_fuzzy(HEADERHTML)
|
337
|
+
expect(HTMLEntities.new.encode(hdr, :hexadecimal)
|
338
|
+
.gsub(/</, "<").gsub(/>/, ">").gsub(/'/, "'").gsub(/"/, '"')
|
339
|
+
.gsub(/
/, "
").gsub(/
/, "\n")).to match_fuzzy(HEADERHTML)
|
340
|
+
expect(html.sub(%r{Content-ID: <header.html>.*$}m, ""))
|
341
|
+
.to match_fuzzy(<<~OUTPUT)
|
342
|
+
#{WORD_HDR} #{DEFAULT_STYLESHEET.gsub(/url\("[^"]+"\)/, 'url(cid:header.html)')}
|
343
|
+
#{WORD_HDR_END} #{word_body('', '<div style="mso-element:footnote-list"/>')} #{WORD_FTR2}
|
344
|
+
OUTPUT
|
337
345
|
end
|
338
346
|
|
339
347
|
it "processes a header with an image" do
|
340
348
|
Html2Doc.process(html_input(""), filename: "test", header_file: "spec/header_img.html")
|
341
349
|
doc = guid_clean(File.read("test.doc", encoding: "utf-8"))
|
342
350
|
expect(doc).to match(%r{Content-Type: image/png})
|
343
|
-
expect(doc).to match(%r{
|
351
|
+
expect(doc).to match(%r{iVBORw0KGgoAAAANSUhEUgAAA5cAAAN7CAYAAADRE24cAAAgAElEQVR4XuydB5gUxdaGC65gTogB})
|
344
352
|
end
|
345
353
|
|
346
354
|
it "processes a header with an image with absolute path" do
|
@@ -351,130 +359,152 @@ RSpec.describe Html2Doc do
|
|
351
359
|
Html2Doc.process(html_input(""), filename: "test", header_file: "spec/header_img1.html")
|
352
360
|
doc = guid_clean(File.read("test.doc", encoding: "utf-8"))
|
353
361
|
expect(doc).to match(%r{Content-Type: image/png})
|
354
|
-
expect(doc).to match(%r{
|
362
|
+
expect(doc).to match(%r{iVBORw0KGgoAAAANSUhEUgAAA5cAAAN7CAYAAADRE24cAAAgAElEQVR4XuydB5gUxdaGC65gTogB})
|
355
363
|
end
|
356
364
|
|
357
|
-
|
358
365
|
it "processes a populated document" do
|
359
366
|
simple_body = "<h1>Hello word!</h1>
|
360
367
|
<div>This is a very simple document</div>"
|
361
368
|
Html2Doc.process(html_input(simple_body), filename: "test")
|
362
|
-
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
363
|
-
to match_fuzzy(<<~OUTPUT)
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
369
|
+
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
370
|
+
.to match_fuzzy(<<~OUTPUT)
|
371
|
+
#{WORD_HDR} #{DEFAULT_STYLESHEET} #{WORD_HDR_END}
|
372
|
+
#{word_body(simple_body, '<div style="mso-element:footnote-list"/>')}
|
373
|
+
#{WORD_FTR1}
|
374
|
+
OUTPUT
|
368
375
|
end
|
369
376
|
|
370
377
|
it "processes AsciiMath" do
|
371
378
|
Html2Doc.process(html_input(%[<div>{{sum_(i=1)^n i^3=((n(n+1))/2)^2 text("integer"))}}</div>]), filename: "test", asciimathdelims: ["{{", "}}"])
|
372
|
-
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
373
|
-
to match_fuzzy(<<~OUTPUT)
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
end
|
383
|
-
|
384
|
-
|
385
|
-
Html2Doc.process(html_input(%[<div>{{bb (-log_2 (p_u)) bb "
|
386
|
-
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
387
|
-
to match_fuzzy(<<~OUTPUT)
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
379
|
+
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
380
|
+
.to match_fuzzy(<<~OUTPUT)
|
381
|
+
#{WORD_HDR} #{DEFAULT_STYLESHEET} #{WORD_HDR_END}
|
382
|
+
#{word_body(%{
|
383
|
+
<div><m:oMath>
|
384
|
+
<m:nary><m:naryPr><m:chr m:val="∑"></m:chr><m:limLoc m:val="undOvr"></m:limLoc><m:grow m:val="on"></m:grow><m:subHide m:val="off"></m:subHide><m:supHide m:val="off"></m:supHide></m:naryPr><m:sub><m:r><m:t>i=1</m:t></m:r></m:sub><m:sup><m:r><m:t>n</m:t></m:r></m:sup><m:e><m:sSup><m:e><m:r><m:t>i</m:t></m:r></m:e><m:sup><m:r><m:t>3</m:t></m:r></m:sup></m:sSup></m:e></m:nary><span style="font-style:normal;"><m:r><m:rPr><m:sty m:val="p"></m:sty></m:rPr><m:t>=</m:t></m:r></span><m:sSup><m:e><m:d><m:dPr><m:sepChr m:val=","></m:sepChr></m:dPr><m:e><m:f><m:fPr><m:type m:val="bar"></m:type></m:fPr><m:num><m:r><m:t>n</m:t></m:r><m:d><m:dPr><m:sepChr m:val=","></m:sepChr></m:dPr><m:e><m:r><m:t>n+1</m:t></m:r></m:e></m:d></m:num><m:den><m:r><m:t>2</m:t></m:r></m:den></m:f></m:e></m:d></m:e><m:sup><m:r><m:t>2</m:t></m:r></m:sup></m:sSup><m:r><m:rPr><m:nor></m:nor></m:rPr><m:t>"integer"</m:t></m:r><span style="font-style:normal;"><m:r><m:rPr><m:sty m:val="p"></m:sty></m:rPr><m:t>)</m:t></m:r></span>
|
385
|
+
</m:oMath>
|
386
|
+
</div>}, '<div style="mso-element:footnote-list"/>')}
|
387
|
+
#{WORD_FTR1}
|
388
|
+
OUTPUT
|
389
|
+
end
|
390
|
+
|
391
|
+
it "processes mstyle" do
|
392
|
+
Html2Doc.process(html_input(%[<div>{{bb (-log_2 (p_u)) bb "BB" bbb "BBB" cc "CC" bcc "BCC" tt "TT" fr "FR" bfr "BFR" sf "SF" bsf "BSFα" sfi "SFI" sfbi "SFBIα" bii "BII" ii "II"}}</div>]), filename: "test", asciimathdelims: ["{{", "}}"])
|
393
|
+
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
394
|
+
.to match_fuzzy(<<~OUTPUT)
|
395
|
+
#{WORD_HDR} #{DEFAULT_STYLESHEET} #{WORD_HDR_END}
|
396
|
+
#{word_body(%{
|
397
|
+
<div><m:oMath>
|
398
|
+
<span style="font-style:normal;font-weight:bold;"><m:r><m:rPr><m:sty m:val="b"></m:sty></m:rPr><m:t>−</m:t></m:r></span><m:sSub><m:e><span style="font-style:normal;font-weight:bold;"><m:r><m:rPr><m:sty m:val="b"></m:sty></m:rPr><m:t>log</m:t></m:r></span></m:e><m:sub><span style="font-style:normal;font-weight:bold;"><m:r><m:rPr><m:sty m:val="b"></m:sty></m:rPr><m:t>2</m:t></m:r></span></m:sub></m:sSub><m:d><m:dPr><m:sepChr m:val=","></m:sepChr></m:dPr><m:e><m:sSub><m:e><span style="font-style:normal;font-weight:bold;"><m:r><m:rPr><m:sty m:val="b"></m:sty></m:rPr><m:t>p</m:t></m:r></span></m:e><m:sub><span style="font-style:normal;font-weight:bold;"><m:r><m:rPr><m:sty m:val="b"></m:sty></m:rPr><m:t>u</m:t></m:r></span></m:sub></m:sSub></m:e></m:d><span style="font-style:normal;font-weight:bold;"><m:r><m:rPr><m:nor></m:nor><m:sty m:val="b"></m:sty></m:rPr><m:t>BB</m:t></m:r></span><m:r><m:rPr><m:nor></m:nor><m:scr m:val="double-struck"></m:scr><m:sty m:val="p"></m:sty></m:rPr><m:t>𝔹𝔹𝔹</m:t></m:r><m:r><m:rPr><m:nor></m:nor><m:scr m:val="script"></m:scr></m:rPr><m:t>𝒞𝒞</m:t></m:r><m:r><m:rPr><m:nor></m:nor><m:scr m:val="script"></m:scr><m:sty m:val="b"></m:sty></m:rPr><m:t>𝓑𝓒𝓒</m:t></m:r><m:r><m:rPr><m:nor></m:nor><m:scr m:val="monospace"></m:scr><m:sty m:val="p"></m:sty></m:rPr><m:t>𝚃𝚃</m:t></m:r><m:r><m:rPr><m:nor></m:nor><m:scr m:val="fraktur"></m:scr><m:sty m:val="p"></m:sty></m:rPr><m:t>𝔉ℜ</m:t></m:r><m:r><m:rPr><m:nor></m:nor><m:scr m:val="fraktur"></m:scr><m:sty m:val="b"></m:sty></m:rPr><m:t>𝕭𝕱𝕽</m:t></m:r><m:r><m:rPr><m:nor></m:nor><m:scr m:val="sans-serif"></m:scr><m:sty m:val="p"></m:sty></m:rPr><m:t>𝖲𝖥</m:t></m:r><m:r><m:rPr><m:nor></m:nor><m:scr m:val="sans-serif"></m:scr><m:sty m:val="b"></m:sty></m:rPr><m:t>𝗕𝗦𝗙𝝰</m:t></m:r><m:r><m:rPr><m:nor></m:nor><m:scr m:val="sans-serif"></m:scr></m:rPr><m:t>𝖲𝖥𝖨</m:t></m:r><m:r><m:rPr><m:nor></m:nor><m:scr m:val="sans-serif"></m:scr><m:sty m:val="bi"></m:sty></m:rPr><m:t>𝙎𝙁𝘽𝙄𝞪</m:t></m:r><span class="nostem" style="font-weight:bold;"><em></em><m:r><m:rPr><m:nor></m:nor><m:sty m:val="bi"></m:sty></m:rPr><m:t>BII</m:t></m:r></span><span class="nostem"><em></em><m:r><m:rPr><m:nor></m:nor><m:sty m:val="i"></m:sty></m:rPr><m:t>II</m:t></m:r></span>
|
399
|
+
</m:oMath>
|
400
|
+
</div>}, '<div style="mso-element:footnote-list"/>')}
|
401
|
+
#{WORD_FTR1}
|
402
|
+
OUTPUT
|
396
403
|
end
|
397
404
|
|
398
405
|
it "processes spaces in AsciiMath" do
|
399
406
|
Html2Doc.process(html_input(%[<div>{{text " integer ")}}</div>]), filename: "test", asciimathdelims: ["{{", "}}"])
|
400
|
-
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
401
|
-
to match_fuzzy(<<~OUTPUT)
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
407
|
+
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
408
|
+
.to match_fuzzy(<<~OUTPUT)
|
409
|
+
#{WORD_HDR} #{DEFAULT_STYLESHEET} #{WORD_HDR_END}
|
410
|
+
#{word_body('
|
411
|
+
<div><m:oMath>
|
412
|
+
<m:r><m:t>text</m:t></m:r><m:r><m:rPr><m:nor></m:nor></m:rPr><m:t> integer </m:t></m:r><span style="font-style:normal;"><m:r><m:rPr><m:sty m:val="p"></m:sty></m:rPr><m:t>)</m:t></m:r></span>
|
413
|
+
</m:oMath>
|
414
|
+
</div>', '<div style="mso-element:footnote-list"/>')}
|
415
|
+
#{WORD_FTR1}
|
416
|
+
OUTPUT
|
410
417
|
end
|
411
418
|
|
412
419
|
it "processes spaces in MathML mtext" do
|
413
420
|
Html2Doc.process(html_input("<div><math xmlns='http://www.w3.org/1998/Math/MathML'>
|
414
421
|
<mrow><mi>H</mi><mtext> original </mtext><mi>J</mi></mrow>
|
415
422
|
</math></div>"), filename: "test", asciimathdelims: ["{{", "}}"])
|
416
|
-
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
417
|
-
to match_fuzzy(<<~OUTPUT)
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
423
|
+
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
424
|
+
.to match_fuzzy(<<~OUTPUT)
|
425
|
+
#{WORD_HDR} #{DEFAULT_STYLESHEET} #{WORD_HDR_END}
|
426
|
+
#{word_body('<div><m:oMath>
|
427
|
+
<m:r><m:t>H</m:t></m:r><m:r><m:rPr><m:nor></m:nor></m:rPr><m:t> original </m:t></m:r><m:r><m:t>J</m:t></m:r>
|
428
|
+
</m:oMath>
|
429
|
+
</div>', '<div style="mso-element:footnote-list"/>')}
|
430
|
+
#{WORD_FTR1}
|
431
|
+
OUTPUT
|
432
|
+
end
|
433
|
+
|
434
|
+
it "unwraps accent in MathML" do
|
435
|
+
Html2Doc.process(html_input("<div><math xmlns='http://www.w3.org/1998/Math/MathML'>
|
436
|
+
<mover accent='true'><mrow><mi>p</mi></mrow><mrow><mo>^</mo></mrow></mover>
|
437
|
+
</math></div>"), filename: "test", asciimathdelims: ["{{", "}}"])
|
438
|
+
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
439
|
+
.to match_fuzzy(<<~OUTPUT)
|
440
|
+
#{WORD_HDR} #{DEFAULT_STYLESHEET} #{WORD_HDR_END}
|
441
|
+
#{word_body('<div><m:oMath>
|
442
|
+
<m:acc><m:accPr><m:chr m:val="^"></m:chr></m:accPr><m:e><m:r><m:t>p</m:t></m:r></m:e></m:acc>
|
443
|
+
</m:oMath>
|
444
|
+
</div>', '<div style="mso-element:footnote-list"/>')}
|
445
|
+
#{WORD_FTR1}
|
446
|
+
OUTPUT
|
425
447
|
end
|
426
448
|
|
427
449
|
it "left-aligns AsciiMath" do
|
428
450
|
Html2Doc.process(html_input("<div style='text-align:left;'>{{sum_(i=1)^n i^3=((n(n+1))/2)^2}}</div>"), filename: "test", asciimathdelims: ["{{", "}}"])
|
429
|
-
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
430
|
-
to match_fuzzy(<<~OUTPUT)
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
451
|
+
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
452
|
+
.to match_fuzzy(<<~OUTPUT)
|
453
|
+
#{WORD_HDR} #{DEFAULT_STYLESHEET} #{WORD_HDR_END}
|
454
|
+
#{word_body(%{
|
455
|
+
<div style="text-align:left;"><m:oMathPara><m:oMathParaPr><m:jc m:val="left"/></m:oMathParaPr><m:oMath>
|
456
|
+
<m:nary><m:naryPr><m:chr m:val="∑"></m:chr><m:limLoc m:val="undOvr"></m:limLoc><m:grow m:val="on"></m:grow><m:subHide m:val="off"></m:subHide><m:supHide m:val="off"></m:supHide></m:naryPr><m:sub><m:r><m:t>i=1</m:t></m:r></m:sub><m:sup><m:r><m:t>n</m:t></m:r></m:sup><m:e><m:sSup><m:e><m:r><m:t>i</m:t></m:r></m:e><m:sup><m:r><m:t>3</m:t></m:r></m:sup></m:sSup></m:e></m:nary><span style="font-style:normal;"><m:r><m:rPr><m:sty m:val="p"></m:sty></m:rPr><m:t>=</m:t></m:r></span><m:sSup><m:e><m:d><m:dPr><m:sepChr m:val=","></m:sepChr></m:dPr><m:e><m:f><m:fPr><m:type m:val="bar"></m:type></m:fPr><m:num><m:r><m:t>n</m:t></m:r><m:d><m:dPr><m:sepChr m:val=","></m:sepChr></m:dPr><m:e><m:r><m:t>n+1</m:t></m:r></m:e></m:d></m:num><m:den><m:r><m:t>2</m:t></m:r></m:den></m:f></m:e></m:d></m:e><m:sup><m:r><m:t>2</m:t></m:r></m:sup></m:sSup>
|
457
|
+
</m:oMath>
|
458
|
+
</m:oMathPara></div>}, '<div style="mso-element:footnote-list"/>')}
|
459
|
+
#{WORD_FTR1}
|
460
|
+
OUTPUT
|
439
461
|
end
|
440
462
|
|
441
463
|
it "right-aligns AsciiMath" do
|
442
464
|
Html2Doc.process(html_input("<div style='text-align:right;'>{{sum_(i=1)^n i^3=((n(n+1))/2)^2}}</div>"), filename: "test", asciimathdelims: ["{{", "}}"])
|
443
|
-
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
444
|
-
to match_fuzzy(<<~OUTPUT)
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
465
|
+
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
466
|
+
.to match_fuzzy(<<~OUTPUT)
|
467
|
+
#{WORD_HDR} #{DEFAULT_STYLESHEET} #{WORD_HDR_END}
|
468
|
+
#{word_body(%{
|
469
|
+
<div style="text-align:right;"><m:oMathPara><m:oMathParaPr><m:jc m:val="right"/></m:oMathParaPr><m:oMath>
|
470
|
+
<m:nary><m:naryPr><m:chr m:val="∑"></m:chr><m:limLoc m:val="undOvr"></m:limLoc><m:grow m:val="on"></m:grow><m:subHide m:val="off"></m:subHide><m:supHide m:val="off"></m:supHide></m:naryPr><m:sub><m:r><m:t>i=1</m:t></m:r></m:sub><m:sup><m:r><m:t>n</m:t></m:r></m:sup><m:e><m:sSup><m:e><m:r><m:t>i</m:t></m:r></m:e><m:sup><m:r><m:t>3</m:t></m:r></m:sup></m:sSup></m:e></m:nary><span style="font-style:normal;"><m:r><m:rPr><m:sty m:val="p"></m:sty></m:rPr><m:t>=</m:t></m:r></span><m:sSup><m:e><m:d><m:dPr><m:sepChr m:val=","></m:sepChr></m:dPr><m:e><m:f><m:fPr><m:type m:val="bar"></m:type></m:fPr><m:num><m:r><m:t>n</m:t></m:r><m:d><m:dPr><m:sepChr m:val=","></m:sepChr></m:dPr><m:e><m:r><m:t>n+1</m:t></m:r></m:e></m:d></m:num><m:den><m:r><m:t>2</m:t></m:r></m:den></m:f></m:e></m:d></m:e><m:sup><m:r><m:t>2</m:t></m:r></m:sup></m:sSup>
|
471
|
+
</m:oMath>
|
472
|
+
</m:oMathPara></div>}, '<div style="mso-element:footnote-list"/>')}
|
473
|
+
#{WORD_FTR1}
|
474
|
+
OUTPUT
|
475
|
+
end
|
476
|
+
|
477
|
+
it "raises error in processing of broken AsciiMath" do
|
478
|
+
begin
|
479
|
+
expect { Html2Doc.process(html_input(%[<div style='text-align:right;'>{{u_c = 6.6"unitsml(kHz)}}</div>]), filename: "test", asciimathdelims: ["{{", "}}"]) }.to output('parsing: u_c = 6.6"unitsml(kHz)').to_stderr
|
480
|
+
rescue StandardError
|
481
|
+
end
|
482
|
+
expect { Html2Doc.process(html_input(%[<div style='text-align:right;'>{{u_c = 6.6"unitsml(kHz)}}</div>]), filename: "test", asciimathdelims: ["{{", "}}"]) }.to raise_error(StandardError)
|
453
483
|
end
|
454
484
|
|
455
485
|
it "wraps msup after munderover in MathML" do
|
456
486
|
Html2Doc.process(html_input("<div><math xmlns='http://www.w3.org/1998/Math/MathML'>
|
457
487
|
<munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>0</mn></mrow><mrow><mi>n</mi></mrow></munderover><msup><mn>2</mn><mrow><mi>i</mi></mrow></msup></math></div>"), filename: "test", asciimathdelims: ["{{", "}}"])
|
458
|
-
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
459
|
-
to match_fuzzy(<<~OUTPUT)
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
488
|
+
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
489
|
+
.to match_fuzzy(<<~OUTPUT)
|
490
|
+
#{WORD_HDR} #{DEFAULT_STYLESHEET} #{WORD_HDR_END}
|
491
|
+
#{word_body('<div><m:oMath>
|
492
|
+
<m:nary><m:naryPr><m:chr m:val="∑"></m:chr><m:limLoc m:val="undOvr"></m:limLoc><m:grow m:val="on"></m:grow><m:subHide m:val="off"></m:subHide><m:supHide m:val="off"></m:supHide></m:naryPr><m:sub><m:r><m:t>i=0</m:t></m:r></m:sub><m:sup><m:r><m:t>n</m:t></m:r></m:sup><m:e><m:sSup><m:e><m:r><m:t>2</m:t></m:r></m:e><m:sup><m:r><m:t>i</m:t></m:r></m:sup></m:sSup></m:e></m:nary></m:oMath>
|
493
|
+
</div>', '<div style="mso-element:footnote-list"/>')}
|
494
|
+
#{WORD_FTR1}
|
495
|
+
OUTPUT
|
466
496
|
end
|
467
497
|
|
468
498
|
it "processes tabs" do
|
469
499
|
simple_body = "<h1>Hello word!</h1>
|
470
500
|
<div>This is a very &tab; simple document</div>"
|
471
501
|
Html2Doc.process(html_input(simple_body), filename: "test")
|
472
|
-
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
473
|
-
to match_fuzzy(<<~OUTPUT)
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
502
|
+
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
503
|
+
.to match_fuzzy(<<~OUTPUT)
|
504
|
+
#{WORD_HDR} #{DEFAULT_STYLESHEET} #{WORD_HDR_END}
|
505
|
+
#{word_body(simple_body.gsub(/&tab;/, %[<span style="mso-tab-count:1">  </span>]), '<div style="mso-element:footnote-list"/>')}
|
506
|
+
#{WORD_FTR1}
|
507
|
+
OUTPUT
|
478
508
|
end
|
479
509
|
|
480
510
|
it "makes unstyled paragraphs be MsoNormal" do
|
@@ -482,12 +512,12 @@ RSpec.describe Html2Doc do
|
|
482
512
|
<p>This is a very simple document</p>
|
483
513
|
<p class="x">This style stays</p>'
|
484
514
|
Html2Doc.process(html_input(simple_body), filename: "test")
|
485
|
-
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
486
|
-
to match_fuzzy(<<~OUTPUT)
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
515
|
+
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
516
|
+
.to match_fuzzy(<<~OUTPUT)
|
517
|
+
#{WORD_HDR} #{DEFAULT_STYLESHEET} #{WORD_HDR_END}
|
518
|
+
#{word_body(simple_body.gsub(/<p>/, %[<p class="MsoNormal">]), '<div style="mso-element:footnote-list"/>')}
|
519
|
+
#{WORD_FTR1}
|
520
|
+
OUTPUT
|
491
521
|
end
|
492
522
|
|
493
523
|
it "makes unstyled list entries be MsoNormal" do
|
@@ -497,12 +527,12 @@ RSpec.describe Html2Doc do
|
|
497
527
|
<li class="x">This style stays</li>
|
498
528
|
</ul>'
|
499
529
|
Html2Doc.process(html_input(simple_body), filename: "test")
|
500
|
-
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
501
|
-
to match_fuzzy(<<~OUTPUT)
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
530
|
+
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
531
|
+
.to match_fuzzy(<<~OUTPUT)
|
532
|
+
#{WORD_HDR} #{DEFAULT_STYLESHEET} #{WORD_HDR_END}
|
533
|
+
#{word_body(simple_body.gsub(/<li>/, %[<li class="MsoNormal">]), '<div style="mso-element:footnote-list"/>')}
|
534
|
+
#{WORD_FTR1}
|
535
|
+
OUTPUT
|
506
536
|
end
|
507
537
|
|
508
538
|
it "resizes images for height, in a file in a subdirectory" do
|
@@ -511,9 +541,9 @@ RSpec.describe Html2Doc do
|
|
511
541
|
testdoc = File.read("spec/test.doc", encoding: "utf-8")
|
512
542
|
expect(testdoc).to match(%r{Content-Type: image/png})
|
513
543
|
expect(image_clean(guid_clean(testdoc))).to match_fuzzy(<<~OUTPUT)
|
514
|
-
|
515
|
-
|
516
|
-
|
544
|
+
#{WORD_HDR} #{DEFAULT_STYLESHEET} #{WORD_HDR_END}
|
545
|
+
#{image_clean(word_body('<img src="cid:cb7b0d19-891e-4634-815a-570d019d454c.png" width="400" height="388"></img>', '<div style="mso-element:footnote-list"/>'))}
|
546
|
+
#{image_clean(WORD_FTR3)}
|
517
547
|
OUTPUT
|
518
548
|
end
|
519
549
|
|
@@ -523,9 +553,9 @@ RSpec.describe Html2Doc do
|
|
523
553
|
testdoc = File.read("test.doc", encoding: "utf-8")
|
524
554
|
expect(testdoc).to match(%r{Content-Type: image/gif})
|
525
555
|
expect(image_clean(guid_clean(testdoc))).to match_fuzzy(<<~OUTPUT)
|
526
|
-
|
527
|
-
|
528
|
-
|
556
|
+
#{WORD_HDR} #{DEFAULT_STYLESHEET} #{WORD_HDR_END}
|
557
|
+
#{image_clean(word_body('<img src="cid:cb7b0d19-891e-4634-815a-570d019d454c.gif" width="400" height="118"></img>', '<div style="mso-element:footnote-list"/>'))}
|
558
|
+
#{image_clean(WORD_FTR3).gsub(/image\.png/, 'image.gif')}
|
529
559
|
OUTPUT
|
530
560
|
end
|
531
561
|
|
@@ -535,9 +565,9 @@ RSpec.describe Html2Doc do
|
|
535
565
|
testdoc = File.read("test.doc", encoding: "utf-8")
|
536
566
|
expect(testdoc).to match(%r{Content-Type: image/jpeg})
|
537
567
|
expect(image_clean(guid_clean(testdoc))).to match_fuzzy(<<~OUTPUT)
|
538
|
-
|
539
|
-
|
540
|
-
|
568
|
+
#{WORD_HDR} #{DEFAULT_STYLESHEET} #{WORD_HDR_END}
|
569
|
+
#{image_clean(word_body('<img src="cid:cb7b0d19-891e-4634-815a-570d019d454c.jpg" width="208" height="680"></img>', '<div style="mso-element:footnote-list"/>'))}
|
570
|
+
#{image_clean(WORD_FTR3).gsub(/image\.png/, 'image.jpg')}
|
541
571
|
OUTPUT
|
542
572
|
end
|
543
573
|
|
@@ -577,49 +607,47 @@ RSpec.describe Html2Doc do
|
|
577
607
|
Html2Doc.process(html_input(simple_body), filename: "test")
|
578
608
|
testdoc = File.read("test.doc", encoding: "utf-8")
|
579
609
|
expect(image_clean(guid_clean(testdoc))).to match_fuzzy(<<~OUTPUT)
|
580
|
-
|
581
|
-
|
582
|
-
|
610
|
+
#{WORD_HDR} #{DEFAULT_STYLESHEET} #{WORD_HDR_END}
|
611
|
+
#{image_clean(word_body('<img src="https://example.com/19160-6.png"></img>', '<div style="mso-element:footnote-list"/>'))}
|
612
|
+
#{image_clean(WORD_FTR1)}
|
583
613
|
OUTPUT
|
584
614
|
end
|
585
615
|
|
586
616
|
it "deals with absolute image locations" do
|
587
|
-
simple_body = %{<img src="#{
|
617
|
+
simple_body = %{<img src="#{__dir__}/19160-6.png">}
|
588
618
|
Html2Doc.process(html_input(simple_body), filename: "spec/test")
|
589
619
|
testdoc = File.read("spec/test.doc", encoding: "utf-8")
|
590
620
|
expect(testdoc).to match(%r{Content-Type: image/png})
|
591
621
|
expect(image_clean(guid_clean(testdoc))).to match_fuzzy(<<~OUTPUT)
|
592
|
-
|
593
|
-
|
594
|
-
|
622
|
+
#{WORD_HDR} #{DEFAULT_STYLESHEET} #{WORD_HDR_END}
|
623
|
+
#{image_clean(word_body('<img src="cid:cb7b0d19-891e-4634-815a-570d019d454c.png" width="400" height="388"></img>', '<div style="mso-element:footnote-list"/>'))}
|
624
|
+
#{image_clean(WORD_FTR3)}
|
595
625
|
OUTPUT
|
596
626
|
end
|
597
627
|
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
end
|
603
|
-
=end
|
628
|
+
# it "warns about SVG" do
|
629
|
+
# simple_body = '<img src="https://example.com/19160-6.svg">'
|
630
|
+
# expect{ Html2Doc.process(html_input(simple_body), filename: "test") }.to output("https://example.com/19160-6.svg: SVG not supported\n").to_stderr
|
631
|
+
# end
|
604
632
|
|
605
633
|
it "processes epub:type footnotes" do
|
606
|
-
simple_body = '<div>This is a very simple
|
634
|
+
simple_body = '<div>This is a very simple
|
607
635
|
document<a epub:type="footnote" href="#a1">1</a> allegedly<a epub:type="footnote" href="#a2">2</a></div>
|
608
636
|
<aside id="a1">Footnote</aside>
|
609
637
|
<aside id="a2">Other Footnote</aside>'
|
610
638
|
Html2Doc.process(html_input(simple_body), filename: "test")
|
611
|
-
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
612
|
-
to match_fuzzy(<<~OUTPUT)
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
<p id="" class="MsoFootnoteText"><a style="mso-footnote-id:ftn1" href="#_ftn1" name="_ftnref1" title="" id="_ftnref1"><span class="MsoFootnoteReference"><span style="mso-special-character:footnote"></span></span></a>Footnote</p></div>
|
618
|
-
<div style="mso-element:footnote" id="ftn2">
|
619
|
-
<p id="" class="MsoFootnoteText"><a style="mso-footnote-id:ftn2" href="#_ftn2" name="_ftnref2" title="" id="_ftnref2"><span class="MsoFootnoteReference"><span style="mso-special-character:footnote"></span></span></a>Other Footnote</p></div>
|
620
|
-
</div>')}
|
621
|
-
|
622
|
-
|
639
|
+
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
640
|
+
.to match_fuzzy(<<~OUTPUT)
|
641
|
+
#{WORD_HDR} #{DEFAULT_STYLESHEET} #{WORD_HDR_END}
|
642
|
+
#{word_body('<div>This is a very simple
|
643
|
+
document<a epub:type="footnote" href="#_ftn1" style="mso-footnote-id:ftn1" name="_ftnref1" title="" id="_ftnref1"><span class="MsoFootnoteReference"><span style="mso-special-character:footnote"></span></span></a> allegedly<a epub:type="footnote" href="#_ftn2" style="mso-footnote-id:ftn2" name="_ftnref2" title="" id="_ftnref2"><span class="MsoFootnoteReference"><span style="mso-special-character:footnote"></span></span></a></div>',
|
644
|
+
'<div style="mso-element:footnote-list"><div style="mso-element:footnote" id="ftn1">
|
645
|
+
<p id="" class="MsoFootnoteText"><a style="mso-footnote-id:ftn1" href="#_ftn1" name="_ftnref1" title="" id="_ftnref1"><span class="MsoFootnoteReference"><span style="mso-special-character:footnote"></span></span></a>Footnote</p></div>
|
646
|
+
<div style="mso-element:footnote" id="ftn2">
|
647
|
+
<p id="" class="MsoFootnoteText"><a style="mso-footnote-id:ftn2" href="#_ftn2" name="_ftnref2" title="" id="_ftnref2"><span class="MsoFootnoteReference"><span style="mso-special-character:footnote"></span></span></a>Other Footnote</p></div>
|
648
|
+
</div>')}
|
649
|
+
#{WORD_FTR1}
|
650
|
+
OUTPUT
|
623
651
|
end
|
624
652
|
|
625
653
|
it "processes class footnotes" do
|
@@ -628,38 +656,38 @@ RSpec.describe Html2Doc do
|
|
628
656
|
<aside id="a1">Footnote</aside>
|
629
657
|
<aside id="a2">Other Footnote</aside>'
|
630
658
|
Html2Doc.process(html_input(simple_body), filename: "test")
|
631
|
-
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
632
|
-
to match_fuzzy(<<~OUTPUT)
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
<p id="" class="MsoFootnoteText"><a style="mso-footnote-id:ftn1" href="#_ftn1" name="_ftnref1" title="" id="_ftnref1"><span class="MsoFootnoteReference"><span style="mso-special-character:footnote"></span></span></a>Footnote</p></div>
|
638
|
-
<div style="mso-element:footnote" id="ftn2">
|
639
|
-
<p id="" class="MsoFootnoteText"><a style="mso-footnote-id:ftn2" href="#_ftn2" name="_ftnref2" title="" id="_ftnref2"><span class="MsoFootnoteReference"><span style="mso-special-character:footnote"></span></span></a>Other Footnote</p></div>
|
640
|
-
</div>')}
|
641
|
-
|
642
|
-
|
659
|
+
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
660
|
+
.to match_fuzzy(<<~OUTPUT)
|
661
|
+
#{WORD_HDR} #{DEFAULT_STYLESHEET} #{WORD_HDR_END}
|
662
|
+
#{word_body('<div>This is a very simple
|
663
|
+
document<a class="footnote" href="#_ftn1" style="mso-footnote-id:ftn1" name="_ftnref1" title="" id="_ftnref1"><span class="MsoFootnoteReference"><span style="mso-special-character:footnote"></span></span></a> allegedly<a class="footnote" href="#_ftn2" style="mso-footnote-id:ftn2" name="_ftnref2" title="" id="_ftnref2"><span class="MsoFootnoteReference"><span style="mso-special-character:footnote"></span></span></a></div>',
|
664
|
+
'<div style="mso-element:footnote-list"><div style="mso-element:footnote" id="ftn1">
|
665
|
+
<p id="" class="MsoFootnoteText"><a style="mso-footnote-id:ftn1" href="#_ftn1" name="_ftnref1" title="" id="_ftnref1"><span class="MsoFootnoteReference"><span style="mso-special-character:footnote"></span></span></a>Footnote</p></div>
|
666
|
+
<div style="mso-element:footnote" id="ftn2">
|
667
|
+
<p id="" class="MsoFootnoteText"><a style="mso-footnote-id:ftn2" href="#_ftn2" name="_ftnref2" title="" id="_ftnref2"><span class="MsoFootnoteReference"><span style="mso-special-character:footnote"></span></span></a>Other Footnote</p></div>
|
668
|
+
</div>')}
|
669
|
+
#{WORD_FTR1}
|
670
|
+
OUTPUT
|
643
671
|
end
|
644
672
|
|
645
673
|
it "processes footnotes with text wrapping the footnote reference" do
|
646
|
-
|
674
|
+
simple_body = '<div>This is a very simple
|
647
675
|
document<a class="footnote" href="#a1">(<span class="MsoFootnoteReference">1</span>)</a> allegedly<a class="footnote" href="#a2">2</a></div>
|
648
676
|
<aside id="a1">Footnote</aside>
|
649
677
|
<aside id="a2">Other Footnote</aside>'
|
650
678
|
Html2Doc.process(html_input(simple_body), filename: "test")
|
651
|
-
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
652
|
-
to match_fuzzy(<<~OUTPUT)
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
<p id="" class="MsoFootnoteText"><a style="mso-footnote-id:ftn1" href="#_ftn1" name="_ftnref1" title="" id="_ftnref1"><span class="MsoFootnoteReference">(</span><span class="MsoFootnoteReference"><span style="mso-special-character:footnote"></span></span><span class="MsoFootnoteReference">)</span></a>Footnote</p></div>
|
658
|
-
<div style="mso-element:footnote" id="ftn2">
|
659
|
-
<p id="" class="MsoFootnoteText"><a style="mso-footnote-id:ftn2" href="#_ftn2" name="_ftnref2" title="" id="_ftnref2"><span class="MsoFootnoteReference"><span style="mso-special-character:footnote"></span></span></a>Other Footnote</p></div>
|
660
|
-
</div>')}
|
661
|
-
|
662
|
-
|
679
|
+
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
680
|
+
.to match_fuzzy(<<~OUTPUT)
|
681
|
+
#{WORD_HDR} #{DEFAULT_STYLESHEET} #{WORD_HDR_END}
|
682
|
+
#{word_body('<div>This is a very simple
|
683
|
+
document<a class="footnote" href="#_ftn1" style="mso-footnote-id:ftn1" name="_ftnref1" title="" id="_ftnref1"><span class="MsoFootnoteReference">(</span><span class="MsoFootnoteReference"><span style="mso-special-character:footnote"></span></span><span class="MsoFootnoteReference">)</span></a> allegedly<a class="footnote" href="#_ftn2" style="mso-footnote-id:ftn2" name="_ftnref2" title="" id="_ftnref2"><span class="MsoFootnoteReference"><span style="mso-special-character:footnote"></span></span></a></div>',
|
684
|
+
'<div style="mso-element:footnote-list"><div style="mso-element:footnote" id="ftn1">
|
685
|
+
<p id="" class="MsoFootnoteText"><a style="mso-footnote-id:ftn1" href="#_ftn1" name="_ftnref1" title="" id="_ftnref1"><span class="MsoFootnoteReference">(</span><span class="MsoFootnoteReference"><span style="mso-special-character:footnote"></span></span><span class="MsoFootnoteReference">)</span></a>Footnote</p></div>
|
686
|
+
<div style="mso-element:footnote" id="ftn2">
|
687
|
+
<p id="" class="MsoFootnoteText"><a style="mso-footnote-id:ftn2" href="#_ftn2" name="_ftnref2" title="" id="_ftnref2"><span class="MsoFootnoteReference"><span style="mso-special-character:footnote"></span></span></a>Other Footnote</p></div>
|
688
|
+
</div>')}
|
689
|
+
#{WORD_FTR1}
|
690
|
+
OUTPUT
|
663
691
|
end
|
664
692
|
|
665
693
|
it "extracts paragraphs from footnotes" do
|
@@ -668,18 +696,18 @@ RSpec.describe Html2Doc do
|
|
668
696
|
<aside id="a1"><p>Footnote</p></aside>
|
669
697
|
<div id="a2"><p>Other Footnote</p></div>'
|
670
698
|
Html2Doc.process(html_input(simple_body), filename: "test")
|
671
|
-
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
672
|
-
to match_fuzzy(<<~OUTPUT)
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
<p class="MsoFootnoteText"><a style="mso-footnote-id:ftn1" href="#_ftn1" name="_ftnref1" title="" id="_ftnref1"><span class="MsoFootnoteReference"><span style="mso-special-character:footnote"></span></span></a>Footnote</p></div>
|
678
|
-
<div style="mso-element:footnote" id="ftn2">
|
679
|
-
<p class="MsoFootnoteText"><a style="mso-footnote-id:ftn2" href="#_ftn2" name="_ftnref2" title="" id="_ftnref2"><span class="MsoFootnoteReference"><span style="mso-special-character:footnote"></span></span></a>Other Footnote</p></div>
|
680
|
-
</div>')}
|
681
|
-
|
682
|
-
|
699
|
+
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
700
|
+
.to match_fuzzy(<<~OUTPUT)
|
701
|
+
#{WORD_HDR} #{DEFAULT_STYLESHEET} #{WORD_HDR_END}
|
702
|
+
#{word_body('<div>This is a very simple
|
703
|
+
document<a class="footnote" href="#_ftn1" style="mso-footnote-id:ftn1" name="_ftnref1" title="" id="_ftnref1"><span class="MsoFootnoteReference"><span style="mso-special-character:footnote"></span></span></a> allegedly<a class="footnote" href="#_ftn2" style="mso-footnote-id:ftn2" name="_ftnref2" title="" id="_ftnref2"><span class="MsoFootnoteReference"><span style="mso-special-character:footnote"></span></span></a></div>',
|
704
|
+
'<div style="mso-element:footnote-list"><div style="mso-element:footnote" id="ftn1">
|
705
|
+
<p class="MsoFootnoteText"><a style="mso-footnote-id:ftn1" href="#_ftn1" name="_ftnref1" title="" id="_ftnref1"><span class="MsoFootnoteReference"><span style="mso-special-character:footnote"></span></span></a>Footnote</p></div>
|
706
|
+
<div style="mso-element:footnote" id="ftn2">
|
707
|
+
<p class="MsoFootnoteText"><a style="mso-footnote-id:ftn2" href="#_ftn2" name="_ftnref2" title="" id="_ftnref2"><span class="MsoFootnoteReference"><span style="mso-special-character:footnote"></span></span></a>Other Footnote</p></div>
|
708
|
+
</div>')}
|
709
|
+
#{WORD_FTR1}
|
710
|
+
OUTPUT
|
683
711
|
end
|
684
712
|
|
685
713
|
it "labels lists with list styles" do
|
@@ -687,38 +715,37 @@ RSpec.describe Html2Doc do
|
|
687
715
|
<div><ul id="0">
|
688
716
|
<li><div><p><ol id="1"><li><ul id="2"><li><p><ol id="3"><li><ol id="4"><li>A</li><li><p>B</p><p>B2</p></li><li>C</li></ol></li></ol></p></li></ul></li></ol></p></div></li><div><ul id="5"><li>C</li></ul></div>
|
689
717
|
BODY
|
690
|
-
Html2Doc.process(html_input(simple_body), filename: "test", liststyles: {ul: "l1", ol: "l2"})
|
691
|
-
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
692
|
-
to match_fuzzy(<<~OUTPUT)
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
718
|
+
Html2Doc.process(html_input(simple_body), filename: "test", liststyles: { ul: "l1", ol: "l2" })
|
719
|
+
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
720
|
+
.to match_fuzzy(<<~OUTPUT)
|
721
|
+
#{WORD_HDR} #{DEFAULT_STYLESHEET} #{WORD_HDR_END}
|
722
|
+
#{word_body('<div>
|
723
|
+
<p style="mso-list:l1 level1 lfo1;" class="MsoListParagraphCxSpFirst"><div><p class="MsoNormal"><p style="mso-list:l2 level2 lfo1;" class="MsoListParagraphCxSpFirst"><p style="mso-list:l2 level4 lfo1;" class="MsoListParagraphCxSpFirst"><p style="mso-list:l2 level5 lfo1;" class="MsoListParagraphCxSpFirst">A</p><p style="mso-list:l2 level5 lfo1;" class="MsoListParagraphCxSpMiddle">B<p class="MsoListParagraphCxSpMiddle">B2</p></p><p style="mso-list:l2 level5 lfo1;" class="MsoListParagraphCxSpLast">C</p></p></p></p></div></p><div><p style="mso-list:l1 level1 lfo2;" class="MsoListParagraphCxSpFirst">C</p></div>
|
724
|
+
</div>',
|
725
|
+
'<div style="mso-element:footnote-list"/>')}
|
726
|
+
#{WORD_FTR1}
|
727
|
+
OUTPUT
|
700
728
|
end
|
701
729
|
|
702
|
-
|
703
730
|
it "restarts numbering of lists with list styles" do
|
704
731
|
simple_body = <<~BODY
|
705
732
|
<div>
|
706
733
|
<ol id="1"><li><div><p><ol id="2"><li><ul id="3"><li><p><ol id="4"><li><ol id="5"><li>A</li></ol></li></ol></p></li></ul></li></ol></p></div></li></ol>
|
707
734
|
<ol id="6"><li><div><p><ol id="7"><li><ul id="8"><li><p><ol id="9"><li><ol id="10"><li>A</li></ol></li></ol></p></li></ul></li></ol></p></div></li></ol></div>
|
708
735
|
BODY
|
709
|
-
Html2Doc.process(html_input(simple_body), filename: "test", liststyles: {ul: "l1", ol: "l2"})
|
710
|
-
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
711
|
-
to match_fuzzy(<<~OUTPUT)
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
end
|
720
|
-
|
721
|
-
|
736
|
+
Html2Doc.process(html_input(simple_body), filename: "test", liststyles: { ul: "l1", ol: "l2" })
|
737
|
+
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
738
|
+
.to match_fuzzy(<<~OUTPUT)
|
739
|
+
#{WORD_HDR} #{DEFAULT_STYLESHEET} #{WORD_HDR_END}
|
740
|
+
#{word_body('<div>
|
741
|
+
<p style="mso-list:l2 level1 lfo1;" class="MsoListParagraphCxSpFirst"><div><p class="MsoNormal"><p style="mso-list:l2 level2 lfo1;" class="MsoListParagraphCxSpFirst"><p style="mso-list:l2 level4 lfo1;" class="MsoListParagraphCxSpFirst"><p style="mso-list:l2 level5 lfo1;" class="MsoListParagraphCxSpFirst">A</p></p></p></p></div></p>
|
742
|
+
<p style="mso-list:l2 level1 lfo2;" class="MsoListParagraphCxSpFirst"><div><p class="MsoNormal"><p style="mso-list:l2 level2 lfo2;" class="MsoListParagraphCxSpFirst"><p style="mso-list:l2 level4 lfo2;" class="MsoListParagraphCxSpFirst"><p style="mso-list:l2 level5 lfo2;" class="MsoListParagraphCxSpFirst">A</p></p></p></p></div></p></div>',
|
743
|
+
'<div style="mso-element:footnote-list"/>')}
|
744
|
+
#{WORD_FTR1}
|
745
|
+
OUTPUT
|
746
|
+
end
|
747
|
+
|
748
|
+
it "labels lists with multiple list styles" do
|
722
749
|
simple_body = <<~BODY
|
723
750
|
<div><ul class="steps" id="0">
|
724
751
|
<li><div><p><ol id="1"><li><ul id="2"><li><p><ol id="3"><li><ol id="4"><li>A</li><li><p>B</p><p>B2</p></li><li>C</li></ol></li></ol></p></li></ul></li></ol></p></div></li></ul></div>
|
@@ -727,19 +754,19 @@ RSpec.describe Html2Doc do
|
|
727
754
|
<div><ul class="other" id="10">
|
728
755
|
<li><div><p><ol id="11"><li><ul id="12"><li><p><ol id="13"><li><ol id="14"><li>A</li><li><p>B</p><p>B2</p></li><li>C</li></ol></li></ol></p></li></ul></li></ol></p></div></li></ul></div>
|
729
756
|
BODY
|
730
|
-
Html2Doc.process(html_input(simple_body), filename: "test", liststyles: {ul: "l1", ol: "l2", steps: "l3"})
|
731
|
-
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
732
|
-
to match_fuzzy(<<~OUTPUT)
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
757
|
+
Html2Doc.process(html_input(simple_body), filename: "test", liststyles: { ul: "l1", ol: "l2", steps: "l3" })
|
758
|
+
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
759
|
+
.to match_fuzzy(<<~OUTPUT)
|
760
|
+
#{WORD_HDR} #{DEFAULT_STYLESHEET} #{WORD_HDR_END}
|
761
|
+
#{word_body('<div>
|
762
|
+
<p style="mso-list:l3 level1 lfo2;" class="MsoListParagraphCxSpFirst"><div><p class="MsoNormal"><p style="mso-list:l3 level2 lfo2;" class="MsoListParagraphCxSpFirst"><p style="mso-list:l3 level4 lfo2;" class="MsoListParagraphCxSpFirst"><p style="mso-list:l3 level5 lfo2;" class="MsoListParagraphCxSpFirst">A</p><p style="mso-list:l3 level5 lfo2;" class="MsoListParagraphCxSpMiddle">B<p class="MsoListParagraphCxSpMiddle">B2</p></p><p style="mso-list:l3 level5 lfo2;" class="MsoListParagraphCxSpLast">C</p></p></p></p></div></p></div>
|
763
|
+
<div>
|
764
|
+
<p style="mso-list:l1 level1 lfo1;" class="MsoListParagraphCxSpFirst"><div><p class="MsoNormal"><p style="mso-list:l2 level2 lfo1;" class="MsoListParagraphCxSpFirst"><p style="mso-list:l2 level4 lfo1;" class="MsoListParagraphCxSpFirst"><p style="mso-list:l2 level5 lfo1;" class="MsoListParagraphCxSpFirst">A</p><p style="mso-list:l2 level5 lfo1;" class="MsoListParagraphCxSpMiddle">B<p class="MsoListParagraphCxSpMiddle">B2</p></p><p style="mso-list:l2 level5 lfo1;" class="MsoListParagraphCxSpLast">C</p></p></p></p></div></p></div>
|
765
|
+
<div>
|
766
|
+
<p style="mso-list:l1 level1 lfo3;" class="MsoListParagraphCxSpFirst"><div><p class="MsoNormal"><p style="mso-list:l2 level2 lfo3;" class="MsoListParagraphCxSpFirst"><p style="mso-list:l2 level4 lfo3;" class="MsoListParagraphCxSpFirst"><p style="mso-list:l2 level5 lfo3;" class="MsoListParagraphCxSpFirst">A</p><p style="mso-list:l2 level5 lfo3;" class="MsoListParagraphCxSpMiddle">B<p class="MsoListParagraphCxSpMiddle">B2</p></p><p style="mso-list:l2 level5 lfo3;" class="MsoListParagraphCxSpLast">C</p></p></p></p></div></p></div>',
|
767
|
+
'<div style="mso-element:footnote-list"/>')}
|
768
|
+
#{WORD_FTR1}
|
769
|
+
OUTPUT
|
743
770
|
end
|
744
771
|
|
745
772
|
it "replaces id attributes with explicit a@name bookmarks" do
|
@@ -749,17 +776,17 @@ RSpec.describe Html2Doc do
|
|
749
776
|
<p id="b"/>
|
750
777
|
</div>
|
751
778
|
BODY
|
752
|
-
Html2Doc.process(html_input(simple_body), filename: "test", liststyles: {ul: "l1", ol: "l2"})
|
753
|
-
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
754
|
-
to match_fuzzy(<<~OUTPUT)
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
779
|
+
Html2Doc.process(html_input(simple_body), filename: "test", liststyles: { ul: "l1", ol: "l2" })
|
780
|
+
expect(guid_clean(File.read("test.doc", encoding: "utf-8")))
|
781
|
+
.to match_fuzzy(<<~OUTPUT)
|
782
|
+
#{WORD_HDR} #{DEFAULT_STYLESHEET} #{WORD_HDR_END}
|
783
|
+
#{word_body('<div>
|
784
|
+
<p class="MsoNormal"><a name="a" id="a"></a>Hello</p>
|
785
|
+
<p class="MsoNormal"><a name="b" id="b"></a></p>
|
786
|
+
</div>',
|
787
|
+
'<div style="mso-element:footnote-list"/>')}
|
788
|
+
#{WORD_FTR1}
|
789
|
+
OUTPUT
|
763
790
|
end
|
764
791
|
|
765
792
|
it "test image base64 image encoding" do
|
@@ -767,7 +794,7 @@ RSpec.describe Html2Doc do
|
|
767
794
|
Html2Doc.process(html_input(simple_body), filename: "spec/test", debug: true)
|
768
795
|
testdoc = File.read("spec/test.doc", encoding: "utf-8")
|
769
796
|
base64_image = testdoc[/image\/png\n\n(.*?)\n\n----/m, 1].gsub!("\n", "")
|
770
|
-
base64_image_basename = testdoc[%r{Content-
|
797
|
+
base64_image_basename = testdoc[%r{Content-ID: <([0-9a-z\-]+)\.png}m, 1]
|
771
798
|
doc_bin_image = Base64.strict_decode64(base64_image)
|
772
799
|
file_bin_image = IO.read("spec/test_files/#{base64_image_basename}.png", mode: "rb")
|
773
800
|
expect(doc_bin_image).to eq file_bin_image
|