sablon 0.0.22 → 0.1.0
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/Gemfile.lock +1 -1
- data/README.md +94 -22
- data/lib/sablon.rb +1 -0
- data/lib/sablon/configuration/configuration.rb +73 -1
- data/lib/sablon/content.rb +77 -3
- data/lib/sablon/environment.rb +3 -0
- data/lib/sablon/html/ast.rb +249 -76
- data/lib/sablon/html/ast_builder.rb +2 -7
- data/lib/sablon/html/node_properties.rb +91 -0
- data/lib/sablon/relationship.rb +47 -0
- data/lib/sablon/template.rb +30 -0
- data/lib/sablon/version.rb +1 -1
- data/test/content_test.rb +121 -42
- data/test/fixtures/html/html_test_content.html +106 -15
- data/test/fixtures/html_sample.docx +0 -0
- data/test/fixtures/insertion_template.docx +0 -0
- data/test/html/ast_builder_test.rb +0 -5
- data/test/html/ast_test.rb +35 -0
- data/test/html/converter_style_test.rb +535 -0
- data/test/html/converter_test.rb +412 -528
- data/test/html/node_properties_test.rb +21 -0
- data/test/html_test.rb +12 -3
- data/test/test_helper.rb +16 -0
- metadata +7 -3
Binary file
|
Binary file
|
@@ -34,11 +34,6 @@ class HTMLConverterASTBuilderTest < Sablon::TestCase
|
|
34
34
|
@bulider.send(:validate_structure, span, div)
|
35
35
|
end
|
36
36
|
assert_equal "Invalid HTML structure: div is not a valid child element of span.", e.message
|
37
|
-
# test inline tag with no parent
|
38
|
-
e = assert_raises ArgumentError do
|
39
|
-
@bulider.send(:validate_structure, root, span)
|
40
|
-
end
|
41
|
-
assert_equal "Invalid HTML structure: span needs to be wrapped in a block level tag.", e.message
|
42
37
|
end
|
43
38
|
|
44
39
|
def test_merge_properties
|
data/test/html/ast_test.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
require "test_helper"
|
3
|
+
require 'securerandom'
|
3
4
|
|
4
5
|
class HTMLConverterASTTest < Sablon::TestCase
|
5
6
|
def setup
|
@@ -32,6 +33,12 @@ class HTMLConverterASTTest < Sablon::TestCase
|
|
32
33
|
assert_equal '<Root: [<Paragraph{Paragraph}: [<Run{}: Lorem >, <Run{i}: ipsum dolor sit amet>]>]>', ast.inspect
|
33
34
|
end
|
34
35
|
|
36
|
+
def test_a
|
37
|
+
input = '<p>Lorem <a href="http://www.google.com">google</a></p>'
|
38
|
+
ast = @converter.processed_ast(input)
|
39
|
+
assert_equal '<Root: [<Paragraph{Paragraph}: [<Run{}: Lorem >, <Hyperlink{target:http://www.google.com}: [<Run{rStyle=Hyperlink}: google>]>]>]>', ast.inspect
|
40
|
+
end
|
41
|
+
|
35
42
|
def test_br_in_strong
|
36
43
|
input = '<div><strong>Lorem<br />ipsum<br />dolor</strong></div>'
|
37
44
|
par = @converter.processed_ast(input).grep(Sablon::HTMLConverter::Paragraph).first
|
@@ -103,6 +110,34 @@ class HTMLConverterASTTest < Sablon::TestCase
|
|
103
110
|
assert_equal %w[0 1 2 1 0 1 2], get_numpr_prop_from_ast(ast, :ilvl)
|
104
111
|
end
|
105
112
|
|
113
|
+
def test_table_tag
|
114
|
+
input='<table></table>'
|
115
|
+
ast = @converter.processed_ast(input)
|
116
|
+
assert_equal '<Root: [<Table{}: []>]>', ast.inspect
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_table_with_table_row
|
120
|
+
input='<table><tr></tr></table>'
|
121
|
+
ast = @converter.processed_ast(input)
|
122
|
+
assert_equal '<Root: [<Table{}: [<TableRow{}: []>]>]>', ast.inspect
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_table_with_table_row_and_table_cell
|
126
|
+
input='<table><tr><td>Content</td></tr></table>'
|
127
|
+
ast = @converter.processed_ast(input)
|
128
|
+
assert_equal '<Root: [<Table{}: [<TableRow{}: [<TableCell{}: [<Paragraph{Paragraph}: [<Run{}: Content>]>]>]>]>]>', ast.inspect
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_table_with_table_row_and_table_cell_and_caption
|
132
|
+
input='<table><caption>Table Title</caption><tr><td>Content</td></tr></table>'
|
133
|
+
ast = @converter.processed_ast(input)
|
134
|
+
assert_equal '<Root: [<Table{}: <Paragraph{Caption}: [<Run{}: Table Title>]>, [<TableRow{}: [<TableCell{}: [<Paragraph{Paragraph}: [<Run{}: Content>]>]>]>]>]>', ast.inspect
|
135
|
+
#
|
136
|
+
input='<table><caption style="caption-side: bottom">Table Title</caption><tr><td>Content</td></tr></table>'
|
137
|
+
ast = @converter.processed_ast(input)
|
138
|
+
assert_equal '<Root: [<Table{}: [<TableRow{}: [<TableCell{}: [<Paragraph{Paragraph}: [<Run{}: Content>]>]>]>], <Paragraph{Caption}: [<Run{}: Table Title>]>>]>', ast.inspect
|
139
|
+
end
|
140
|
+
|
106
141
|
private
|
107
142
|
|
108
143
|
# returns the numid attribute from paragraphs
|
@@ -0,0 +1,535 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require "test_helper"
|
3
|
+
|
4
|
+
class HTMLConverterStyleTest < Sablon::TestCase
|
5
|
+
def setup
|
6
|
+
super
|
7
|
+
@env = Sablon::Environment.new(nil)
|
8
|
+
@converter = Sablon::HTMLConverter.new
|
9
|
+
end
|
10
|
+
|
11
|
+
# testing direct CSS style -> WordML conversion for paragraphs
|
12
|
+
|
13
|
+
def test_paragraph_with_background_color
|
14
|
+
input = '<p style="background-color: #123456"></p>'
|
15
|
+
expected_output = para_with_ppr('<w:shd w:val="clear" w:fill="123456" />')
|
16
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_paragraph_with_borders
|
20
|
+
# Basic single line black border
|
21
|
+
input = '<p style="border: 1px"></p>'
|
22
|
+
ppr = <<-DOCX.strip
|
23
|
+
<w:pBdr>
|
24
|
+
<w:top w:sz="2" w:val="single" w:color="000000" />
|
25
|
+
<w:bottom w:sz="2" w:val="single" w:color="000000" />
|
26
|
+
<w:left w:sz="2" w:val="single" w:color="000000" />
|
27
|
+
<w:right w:sz="2" w:val="single" w:color="000000" />
|
28
|
+
</w:pBdr>
|
29
|
+
DOCX
|
30
|
+
expected_output = para_with_ppr(ppr)
|
31
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
32
|
+
# border with a line style
|
33
|
+
input = '<p style="border: 1px wavy"></p>'
|
34
|
+
ppr = <<-DOCX.strip
|
35
|
+
<w:pBdr>
|
36
|
+
<w:top w:sz="2" w:val="wavy" w:color="000000" />
|
37
|
+
<w:bottom w:sz="2" w:val="wavy" w:color="000000" />
|
38
|
+
<w:left w:sz="2" w:val="wavy" w:color="000000" />
|
39
|
+
<w:right w:sz="2" w:val="wavy" w:color="000000" />
|
40
|
+
</w:pBdr>
|
41
|
+
DOCX
|
42
|
+
expected_output = para_with_ppr(ppr)
|
43
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
44
|
+
# border with line style and color
|
45
|
+
input = '<p style="border: 1px wavy #123456"></p>'
|
46
|
+
ppr = <<-DOCX.strip
|
47
|
+
<w:pBdr>
|
48
|
+
<w:top w:sz="2" w:val="wavy" w:color="123456" />
|
49
|
+
<w:bottom w:sz="2" w:val="wavy" w:color="123456" />
|
50
|
+
<w:left w:sz="2" w:val="wavy" w:color="123456" />
|
51
|
+
<w:right w:sz="2" w:val="wavy" w:color="123456" />
|
52
|
+
</w:pBdr>
|
53
|
+
DOCX
|
54
|
+
expected_output = para_with_ppr(ppr)
|
55
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_paragraph_with_text_align
|
59
|
+
input = '<p style="text-align: both"></p>'
|
60
|
+
expected_output = para_with_ppr('<w:jc w:val="both" />')
|
61
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_paragraph_with_vertical_align
|
65
|
+
input = '<p style="vertical-align: baseline"></p>'
|
66
|
+
expected_output = para_with_ppr('<w:textAlignment w:val="baseline" />')
|
67
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_paragraph_with_unsupported_property
|
71
|
+
input = '<p style="unsupported: true"></p>'
|
72
|
+
expected_output = para_with_ppr('')
|
73
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
74
|
+
end
|
75
|
+
|
76
|
+
# test that styles defined on the <a> tag are passed down to runs
|
77
|
+
def test_hyperlink_with_font_style
|
78
|
+
uid_generator = UIDTestGenerator.new
|
79
|
+
SecureRandom.stub(:uuid, uid_generator.method(:new_uid)) do |secure_random_instance|
|
80
|
+
uid_generator.reset
|
81
|
+
input = '<p><a href="http://www.google.com" style="font-style: italic">Google</a></p>'
|
82
|
+
expected_output = hyperlink_with_rpr('<w:i />', secure_random_instance.uuid)
|
83
|
+
uid_generator.reset
|
84
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_run_with_background_color
|
89
|
+
input = '<p><span style="background-color: #123456">test</span></p>'
|
90
|
+
expected_output = run_with_rpr('<w:shd w:val="clear" w:fill="123456" />')
|
91
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_run_with_color
|
95
|
+
input = '<p><span style="color: #123456">test</span></p>'
|
96
|
+
expected_output = run_with_rpr('<w:color w:val="123456" />')
|
97
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_run_with_font_size
|
101
|
+
input = '<p><span style="font-size: 20">test</span></p>'
|
102
|
+
expected_output = run_with_rpr('<w:sz w:val="40" />')
|
103
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
104
|
+
|
105
|
+
# test that non-numeric are ignored
|
106
|
+
input = '<p><span style="font-size: 20pts">test</span></p>'
|
107
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
108
|
+
|
109
|
+
# test that floats round up
|
110
|
+
input = '<p><span style="font-size: 19.1pts">test</span></p>'
|
111
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_run_with_font_style
|
115
|
+
input = '<p><span style="font-style: bold">test</span></p>'
|
116
|
+
expected_output = run_with_rpr('<w:b />')
|
117
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
118
|
+
|
119
|
+
# test italics
|
120
|
+
input = '<p><span style="font-style: italic">test</span></p>'
|
121
|
+
expected_output = run_with_rpr('<w:i />')
|
122
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_run_with_font_wieght
|
126
|
+
input = '<p><span style="font-weight: bold">test</span></p>'
|
127
|
+
expected_output = run_with_rpr('<w:b />')
|
128
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_run_with_text_decoration
|
132
|
+
# testing underline configurations
|
133
|
+
input = '<p><span style="text-decoration: underline">test</span></p>'
|
134
|
+
expected_output = run_with_rpr('<w:u w:val="single" />')
|
135
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
136
|
+
|
137
|
+
input = '<p><span style="text-decoration: underline dash">test</span></p>'
|
138
|
+
expected_output = run_with_rpr('<w:u w:val="dash" w:color="auto" />')
|
139
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
140
|
+
|
141
|
+
input = '<p><span style="text-decoration: underline dash #123456">test</span></p>'
|
142
|
+
expected_output = run_with_rpr('<w:u w:val="dash" w:color="123456" />')
|
143
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
144
|
+
|
145
|
+
# testing line-through
|
146
|
+
input = '<p><span style="text-decoration: line-through">test</span></p>'
|
147
|
+
expected_output = run_with_rpr('<w:strike w:val="true" />')
|
148
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
149
|
+
|
150
|
+
# testing that unsupported values are passed through as a toggle
|
151
|
+
input = '<p><span style="text-decoration: strike">test</span></p>'
|
152
|
+
expected_output = run_with_rpr('<w:strike w:val="true" />')
|
153
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
154
|
+
|
155
|
+
input = '<p><span style="text-decoration: emboss">test</span></p>'
|
156
|
+
expected_output = run_with_rpr('<w:emboss w:val="true" />')
|
157
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_run_with_vertical_align
|
161
|
+
input = '<p><span style="vertical-align: subscript">test</span></p>'
|
162
|
+
expected_output = run_with_rpr('<w:vertAlign w:val="subscript" />')
|
163
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
164
|
+
|
165
|
+
input = '<p><span style="vertical-align: superscript">test</span></p>'
|
166
|
+
expected_output = run_with_rpr('<w:vertAlign w:val="superscript" />')
|
167
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
168
|
+
end
|
169
|
+
|
170
|
+
def test_run_with_unsupported_property
|
171
|
+
input = '<p><span style="unsupported: true">test</span></p>'
|
172
|
+
expected_output = '<w:p><w:pPr><w:pStyle w:val="Paragraph" /></w:pPr><w:r><w:t xml:space="preserve">test</w:t></w:r></w:p>'
|
173
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
174
|
+
end
|
175
|
+
|
176
|
+
# tests with nested runs and styles
|
177
|
+
|
178
|
+
def test_paragraph_props_passed_to_runs
|
179
|
+
input = '<p style="color: #123456"><b>Lorem</b><span>ipsum</span></p>'
|
180
|
+
expected_output = <<-DOCX.strip
|
181
|
+
<w:p>
|
182
|
+
<w:pPr>
|
183
|
+
<w:pStyle w:val="Paragraph" />
|
184
|
+
</w:pPr>
|
185
|
+
<w:r>
|
186
|
+
<w:rPr>
|
187
|
+
<w:color w:val="123456" />
|
188
|
+
<w:b />
|
189
|
+
</w:rPr>
|
190
|
+
<w:t xml:space="preserve">Lorem</w:t>
|
191
|
+
</w:r>
|
192
|
+
<w:r>
|
193
|
+
<w:rPr>
|
194
|
+
<w:color w:val="123456" />
|
195
|
+
</w:rPr>
|
196
|
+
<w:t xml:space="preserve">ipsum</w:t>
|
197
|
+
</w:r>
|
198
|
+
</w:p>
|
199
|
+
DOCX
|
200
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
201
|
+
end
|
202
|
+
|
203
|
+
def test_run_prop_override_paragraph_prop
|
204
|
+
input = '<p style="text-align: center; color: #FF0000">Lorem<span style="color: blue;">ipsum</span></p>'
|
205
|
+
expected_output = <<-DOCX.strip
|
206
|
+
<w:p>
|
207
|
+
<w:pPr>
|
208
|
+
<w:pStyle w:val="Paragraph" />
|
209
|
+
<w:jc w:val="center" />
|
210
|
+
</w:pPr>
|
211
|
+
<w:r>
|
212
|
+
<w:rPr>
|
213
|
+
<w:color w:val="FF0000" />
|
214
|
+
</w:rPr>
|
215
|
+
<w:t xml:space="preserve">Lorem</w:t>
|
216
|
+
</w:r>
|
217
|
+
<w:r>
|
218
|
+
<w:rPr>
|
219
|
+
<w:color w:val="blue" />
|
220
|
+
</w:rPr>
|
221
|
+
<w:t xml:space="preserve">ipsum</w:t>
|
222
|
+
</w:r>
|
223
|
+
</w:p>
|
224
|
+
DOCX
|
225
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
226
|
+
end
|
227
|
+
|
228
|
+
def test_inline_style_overrides_tag_style
|
229
|
+
# Note: a toggle property can not be removed once it becomes a symbol
|
230
|
+
# unless there is a specific CSS style that will set it to false. This
|
231
|
+
# is because CSS styles can only override parent properties not remove them.
|
232
|
+
input = '<p><u style="text-decoration: underline wavyDouble">test</u></p>'
|
233
|
+
expected_output = run_with_rpr('<w:u w:val="wavyDouble" w:color="auto" />')
|
234
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
235
|
+
end
|
236
|
+
|
237
|
+
def test_conversion_of_a_registered_tag_without_ast_class
|
238
|
+
# This registers a new tag with the configuration object and then trys
|
239
|
+
# to convert it
|
240
|
+
Sablon.configure do |config|
|
241
|
+
config.register_html_tag(:bgcyan, :inline, properties: { 'highlight' => { val: 'cyan' } })
|
242
|
+
end
|
243
|
+
#
|
244
|
+
input = '<p><bgcyan>test</bgcyan></p>'
|
245
|
+
expected_output = run_with_rpr('<w:highlight w:val="cyan" />')
|
246
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
247
|
+
|
248
|
+
# remove the tag to avoid any accidental side effects
|
249
|
+
Sablon.configure do |config|
|
250
|
+
config.remove_html_tag(:bgcyan)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
def test_conversion_of_a_registered_tag_with_ast_class
|
255
|
+
Sablon.configure do |config|
|
256
|
+
# create the AST class and then pass it onto the register tag method
|
257
|
+
ast_class = Class.new(Sablon::HTMLConverter::Node) do
|
258
|
+
def self.name
|
259
|
+
'TestInstr'
|
260
|
+
end
|
261
|
+
|
262
|
+
def initialize(_env, node, _properties)
|
263
|
+
@content = node.text
|
264
|
+
end
|
265
|
+
|
266
|
+
def inspect
|
267
|
+
@content
|
268
|
+
end
|
269
|
+
|
270
|
+
def to_docx
|
271
|
+
"<w:instrText xml:space=\"preserve\"> #{@content} </w:instrText>"
|
272
|
+
end
|
273
|
+
end
|
274
|
+
#
|
275
|
+
config.register_html_tag(:test_instr, :inline, ast_class: ast_class)
|
276
|
+
end
|
277
|
+
#
|
278
|
+
input = '<p><test_instr>test</test_instr></p>'
|
279
|
+
expected_output = <<-DOCX.strip
|
280
|
+
<w:p>
|
281
|
+
<w:pPr>
|
282
|
+
<w:pStyle w:val="Paragraph" />
|
283
|
+
</w:pPr>
|
284
|
+
<w:instrText xml:space="preserve"> test </w:instrText>
|
285
|
+
</w:p>
|
286
|
+
DOCX
|
287
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
288
|
+
|
289
|
+
# remove the tag to avoid any accidental side effects
|
290
|
+
Sablon.configure do |config|
|
291
|
+
config.remove_html_tag(:test_instr)
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
def test_conversion_of_registered_style_attribute
|
296
|
+
Sablon.configure do |config|
|
297
|
+
converter = ->(v) { return :highlight, v }
|
298
|
+
config.register_style_converter(:run, 'test-highlight', converter)
|
299
|
+
end
|
300
|
+
#
|
301
|
+
input = '<p><span style="test-highlight: green">test</span></p>'
|
302
|
+
expected_output = run_with_rpr('<w:highlight w:val="green" />')
|
303
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
304
|
+
#
|
305
|
+
Sablon.configure do |config|
|
306
|
+
config.remove_style_converter(:run, 'test-highlight')
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
def test_table_border_conversion
|
311
|
+
input = '<table style="border: 1px dotted #eaf"><tr><td></td></tr></table>'
|
312
|
+
props = <<-DOCX.strip
|
313
|
+
<w:tblBorders>
|
314
|
+
<w:top w:sz="2" w:val="dotted" w:color="eaf" />
|
315
|
+
<w:start w:sz="2" w:val="dotted" w:color="eaf" />
|
316
|
+
<w:bottom w:sz="2" w:val="dotted" w:color="eaf" />
|
317
|
+
<w:end w:sz="2" w:val="dotted" w:color="eaf" />
|
318
|
+
<w:insideH w:sz="2" w:val="dotted" w:color="eaf" />
|
319
|
+
<w:insideV w:sz="2" w:val="dotted" w:color="eaf" />
|
320
|
+
</w:tblBorders>
|
321
|
+
DOCX
|
322
|
+
expected_output = table_with_props(props)
|
323
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
324
|
+
end
|
325
|
+
|
326
|
+
def test_table_margin_conversion
|
327
|
+
# test with single value
|
328
|
+
input = '<table style="margin: 2"><tr><td></td></tr></table>'
|
329
|
+
props = <<-DOCX.strip
|
330
|
+
<w:tblCellMar>
|
331
|
+
<w:top w:w="4" w:type="dxa" />
|
332
|
+
<w:end w:w="4" w:type="dxa" />
|
333
|
+
<w:bottom w:w="4" w:type="dxa" />
|
334
|
+
<w:start w:w="4" w:type="dxa" />
|
335
|
+
</w:tblCellMar>
|
336
|
+
DOCX
|
337
|
+
expected_output = table_with_props(props)
|
338
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
339
|
+
|
340
|
+
# test with two values
|
341
|
+
input = '<table style="margin: 2 4"><tr><td></td></tr></table>'
|
342
|
+
props = <<-DOCX.strip
|
343
|
+
<w:tblCellMar>
|
344
|
+
<w:top w:w="4" w:type="dxa" />
|
345
|
+
<w:end w:w="8" w:type="dxa" />
|
346
|
+
<w:bottom w:w="4" w:type="dxa" />
|
347
|
+
<w:start w:w="8" w:type="dxa" />
|
348
|
+
</w:tblCellMar>
|
349
|
+
DOCX
|
350
|
+
expected_output = table_with_props(props)
|
351
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
352
|
+
|
353
|
+
# test with three values
|
354
|
+
input = '<table style="margin: 2 4 8"><tr><td></td></tr></table>'
|
355
|
+
props = <<-DOCX.strip
|
356
|
+
<w:tblCellMar>
|
357
|
+
<w:top w:w="4" w:type="dxa" />
|
358
|
+
<w:end w:w="8" w:type="dxa" />
|
359
|
+
<w:bottom w:w="16" w:type="dxa" />
|
360
|
+
<w:start w:w="8" w:type="dxa" />
|
361
|
+
</w:tblCellMar>
|
362
|
+
DOCX
|
363
|
+
expected_output = table_with_props(props)
|
364
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
365
|
+
|
366
|
+
# test with four values
|
367
|
+
input = '<table style="margin: 2 4 8 16"><tr><td></td></tr></table>'
|
368
|
+
props = <<-DOCX.strip
|
369
|
+
<w:tblCellMar>
|
370
|
+
<w:top w:w="4" w:type="dxa" />
|
371
|
+
<w:end w:w="8" w:type="dxa" />
|
372
|
+
<w:bottom w:w="16" w:type="dxa" />
|
373
|
+
<w:start w:w="32" w:type="dxa" />
|
374
|
+
</w:tblCellMar>
|
375
|
+
DOCX
|
376
|
+
expected_output = table_with_props(props)
|
377
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
378
|
+
end
|
379
|
+
|
380
|
+
def test_table_cellspacing_conversion
|
381
|
+
input = '<table style="cellspacing: 1"><tr><td></td></tr></table>'
|
382
|
+
expected_output = table_with_props('<w:tblCellSpacing w:w="2" w:type="dxa" />')
|
383
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
384
|
+
end
|
385
|
+
|
386
|
+
def test_table_width_conversion
|
387
|
+
input = '<table style="width: 1"><tr><td></td></tr></table>'
|
388
|
+
expected_output = table_with_props('<w:tblW w:w="2" w:type="dxa" />')
|
389
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
390
|
+
end
|
391
|
+
|
392
|
+
def test_table_cell_borders_conversion
|
393
|
+
input = '<table><tr><td style="border: 1px dotted #eaf"></td></tr></table>'
|
394
|
+
props = <<-DOCX.strip
|
395
|
+
<w:tcBorders>
|
396
|
+
<w:top w:sz="2" w:val="dotted" w:color="eaf" />
|
397
|
+
<w:start w:sz="2" w:val="dotted" w:color="eaf" />
|
398
|
+
<w:bottom w:sz="2" w:val="dotted" w:color="eaf" />
|
399
|
+
<w:end w:sz="2" w:val="dotted" w:color="eaf" />
|
400
|
+
<w:insideH w:sz="2" w:val="dotted" w:color="eaf" />
|
401
|
+
<w:insideV w:sz="2" w:val="dotted" w:color="eaf" />
|
402
|
+
</w:tcBorders>
|
403
|
+
DOCX
|
404
|
+
expected_output = table_with_props('', '', props)
|
405
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
406
|
+
end
|
407
|
+
|
408
|
+
def test_table_cell_colspan_conversion
|
409
|
+
input = '<table><tr><td style="colspan: 2"></td></tr></table>'
|
410
|
+
expected_output = table_with_props('', '', '<w:gridSpan w:val="2" />')
|
411
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
412
|
+
end
|
413
|
+
|
414
|
+
def test_table_cell_margin_conversion
|
415
|
+
# test with four values
|
416
|
+
input = '<table><tr><td style="margin: 2 4 8 16"></td></tr></table>'
|
417
|
+
props = <<-DOCX.strip
|
418
|
+
<w:tcMar>
|
419
|
+
<w:top w:w="4" w:type="dxa" />
|
420
|
+
<w:end w:w="8" w:type="dxa" />
|
421
|
+
<w:bottom w:w="16" w:type="dxa" />
|
422
|
+
<w:start w:w="32" w:type="dxa" />
|
423
|
+
</w:tcMar>
|
424
|
+
DOCX
|
425
|
+
expected_output = table_with_props('', '', props)
|
426
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
427
|
+
end
|
428
|
+
|
429
|
+
def test_table_cell_rowspan_conversion
|
430
|
+
input = '<table><tr><td style="rowspan: start"></td></tr></table>'
|
431
|
+
expected_output = table_with_props('', '', '<w:vMerge w:val="restart" />')
|
432
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
433
|
+
#
|
434
|
+
input = '<table><tr><td style="rowspan: continue"></td></tr></table>'
|
435
|
+
expected_output = table_with_props('', '', '<w:vMerge w:val="continue" />')
|
436
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
437
|
+
#
|
438
|
+
input = '<table><tr><td style="rowspan: end"></td></tr></table>'
|
439
|
+
expected_output = table_with_props('', '', '<w:vMerge />')
|
440
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
441
|
+
end
|
442
|
+
|
443
|
+
def test_table_cell_vertical_align_conversion
|
444
|
+
input = '<table><tr><td style="vertical-align: top"></td></tr></table>'
|
445
|
+
expected_output = table_with_props('', '', '<w:vAlign w:val="top" />')
|
446
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
447
|
+
end
|
448
|
+
|
449
|
+
def test_table_cell_white_space_conversion
|
450
|
+
input = '<table><tr><td style="white-space: nowrap"></td></tr></table>'
|
451
|
+
expected_output = table_with_props('', '', '<w:noWrap />')
|
452
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
453
|
+
#
|
454
|
+
input = '<table><tr><td style="white-space: fit"></td></tr></table>'
|
455
|
+
expected_output = table_with_props('', '', '<w:tcFitText w:val="true" />')
|
456
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
457
|
+
end
|
458
|
+
|
459
|
+
def test_table_cell_width_conversion
|
460
|
+
input = '<table><tr><td style="width: 100"></td></tr></table>'
|
461
|
+
expected_output = table_with_props('', '', '<w:tcW w:w="200" w:type="dxa" />')
|
462
|
+
assert_equal normalize_wordml(expected_output), process(input)
|
463
|
+
end
|
464
|
+
|
465
|
+
private
|
466
|
+
|
467
|
+
def process(input)
|
468
|
+
@converter.process(input, @env)
|
469
|
+
end
|
470
|
+
|
471
|
+
def table_with_props(tbl_pr_str, tr_pr_str = '', tc_pr_str = '')
|
472
|
+
tbl_str = <<-DOCX.strip
|
473
|
+
<w:tbl>
|
474
|
+
%s
|
475
|
+
<w:tr>
|
476
|
+
%s
|
477
|
+
<w:tc>
|
478
|
+
%s
|
479
|
+
<w:p><w:pPr><w:pStyle w:val="Paragraph" /></w:pPr></w:p>
|
480
|
+
</w:tc>
|
481
|
+
</w:tr>
|
482
|
+
</w:tbl>
|
483
|
+
DOCX
|
484
|
+
tbl_pr_str = "<w:tblPr>#{tbl_pr_str}</w:tblPr>" unless tbl_pr_str == ''
|
485
|
+
tr_pr_str = "<w:trPr>#{tr_pr_str}</w:trPr>" unless tr_pr_str == ''
|
486
|
+
tc_pr_str = "<w:tcPr>#{tc_pr_str}</w:tcPr>" unless tc_pr_str == ''
|
487
|
+
format(tbl_str, tbl_pr_str, tr_pr_str, tc_pr_str)
|
488
|
+
end
|
489
|
+
|
490
|
+
def para_with_ppr(ppr_str)
|
491
|
+
para_str = '<w:p><w:pPr><w:pStyle w:val="Paragraph" />%s</w:pPr></w:p>'
|
492
|
+
format(para_str, ppr_str)
|
493
|
+
end
|
494
|
+
|
495
|
+
def run_with_rpr(rpr_str)
|
496
|
+
para_str = <<-DOCX.strip
|
497
|
+
<w:p>
|
498
|
+
<w:pPr>
|
499
|
+
<w:pStyle w:val="Paragraph" />
|
500
|
+
</w:pPr>
|
501
|
+
<w:r>
|
502
|
+
<w:rPr>
|
503
|
+
%s
|
504
|
+
</w:rPr>
|
505
|
+
<w:t xml:space="preserve">test</w:t>
|
506
|
+
</w:r>
|
507
|
+
</w:p>
|
508
|
+
DOCX
|
509
|
+
format(para_str, rpr_str)
|
510
|
+
end
|
511
|
+
|
512
|
+
def hyperlink_with_rpr(rpr_str, id)
|
513
|
+
para_str = <<-DOCX.strip
|
514
|
+
<w:p>
|
515
|
+
<w:pPr>
|
516
|
+
<w:pStyle w:val="Paragraph" />
|
517
|
+
</w:pPr>
|
518
|
+
<w:hyperlink r:id="rId#{id}">
|
519
|
+
<w:r>
|
520
|
+
<w:rPr>
|
521
|
+
<w:rStyle w:val="Hyperlink" />
|
522
|
+
%s
|
523
|
+
</w:rPr>
|
524
|
+
<w:t xml:space="preserve">Google</w:t>
|
525
|
+
</w:r>
|
526
|
+
</w:hyperlink>
|
527
|
+
</w:p>
|
528
|
+
DOCX
|
529
|
+
format(para_str, rpr_str)
|
530
|
+
end
|
531
|
+
|
532
|
+
def normalize_wordml(wordml)
|
533
|
+
wordml.gsub(/^\s+/, '').tr("\n", '')
|
534
|
+
end
|
535
|
+
end
|