docxi 0.0.2 → 0.1.0.rc1
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 +5 -5
- data/CHANGELOG.md +31 -0
- data/README.md +79 -4
- data/Rakefile +28 -0
- data/lib/docxi/content_types.rb +6 -2
- data/lib/docxi/document.rb +5 -5
- data/lib/docxi/properties.rb +2 -4
- data/lib/docxi/relationships.rb +1 -2
- data/lib/docxi/util.rb +19 -0
- data/lib/docxi/version.rb +1 -1
- data/lib/docxi/word/contents/frame.rb +84 -0
- data/lib/docxi/word/contents/image.rb +74 -10
- data/lib/docxi/word/contents/paragraph.rb +68 -1
- data/lib/docxi/word/contents/tab.rb +33 -0
- data/lib/docxi/word/contents/table.rb +80 -0
- data/lib/docxi/word/contents/text.rb +7 -1
- data/lib/docxi/word/contents.rb +2 -0
- data/lib/docxi/word/document.rb +45 -6
- data/lib/docxi/word/effects.rb +1 -2
- data/lib/docxi/word/endnotes.rb +1 -2
- data/lib/docxi/word/fonts.rb +1 -2
- data/lib/docxi/word/footers/footer.rb +24 -6
- data/lib/docxi/word/footnotes.rb +1 -2
- data/lib/docxi/word/headers/header.rb +57 -13
- data/lib/docxi/word/helpers.rb +12 -0
- data/lib/docxi/word/hyperlinks/hyperlink.rb +94 -0
- data/lib/docxi/word/hyperlinks.rb +30 -0
- data/lib/docxi/word/medias/media.rb +18 -0
- data/lib/docxi/word/medias.rb +1 -2
- data/lib/docxi/word/numbering.rb +1 -2
- data/lib/docxi/word/relationships/relationship.rb +8 -3
- data/lib/docxi/word/relationships.rb +5 -6
- data/lib/docxi/word/settings.rb +1 -2
- data/lib/docxi/word/styles.rb +6 -6
- data/lib/docxi/word/themes.rb +1 -2
- data/lib/docxi/word/web_settings.rb +1 -2
- data/lib/docxi.rb +12 -1
- metadata +74 -20
|
@@ -28,6 +28,8 @@ module Docxi
|
|
|
28
28
|
xml['w'].tblPr do
|
|
29
29
|
xml['w'].tblStyle( 'w:val' => options[:style] ) if options[:style]
|
|
30
30
|
xml['w'].tblW( 'w:w' => options[:width], 'w:type' => "auto" ) if options[:width]
|
|
31
|
+
xml['w'].jc( 'w:val' => options[:align] ) if options[:align]
|
|
32
|
+
xml['w'].tblInd( 'w:w' => options[:iwidth], 'w:type' => "dxa" ) if options[:iwidth]
|
|
31
33
|
xml['w'].tblLook( 'w:val' => "04A0", 'w:firstRow' => 1, 'w:lastRow' => 0, 'w:firstColumn' => 1, 'w:lastColumn' => 0, 'w:noHBand' => 0, 'w:noVBand' => 1 )
|
|
32
34
|
if @options[:borders]
|
|
33
35
|
xml['w'].tblBorders do
|
|
@@ -40,6 +42,15 @@ module Docxi
|
|
|
40
42
|
end
|
|
41
43
|
end
|
|
42
44
|
end
|
|
45
|
+
if @options[:padding]
|
|
46
|
+
xml['w'].tblCellMar do
|
|
47
|
+
xml['w'].top( 'w:w' => "288", 'w:type' => "dxa" )
|
|
48
|
+
xml['w'].left( 'w:w' => "573", 'w:type' => "dxa" )
|
|
49
|
+
xml['w'].bottom( 'w:w' => "288", 'w:type' => "dxa" )
|
|
50
|
+
xml['w'].right( 'w:w' => "573", 'w:type' => "dxa" )
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
43
54
|
end
|
|
44
55
|
xml['w'].tblGrid do
|
|
45
56
|
if options[:columns_width]
|
|
@@ -81,6 +92,12 @@ module Docxi
|
|
|
81
92
|
|
|
82
93
|
def render(xml)
|
|
83
94
|
xml['w'].tr do
|
|
95
|
+
if Docxi::Util.present?(options[:height])
|
|
96
|
+
xml['w'].trPr do
|
|
97
|
+
xml['w'].trHeight('w:val' => options[:height], 'w:hRule' => 'atLeast')
|
|
98
|
+
xml['w'].cantSplit('w:val' => 'false')
|
|
99
|
+
end
|
|
100
|
+
end
|
|
84
101
|
@cells.each do |cell|
|
|
85
102
|
cell.render(xml)
|
|
86
103
|
end
|
|
@@ -102,6 +119,9 @@ module Docxi
|
|
|
102
119
|
end
|
|
103
120
|
|
|
104
121
|
def render(xml)
|
|
122
|
+
if Docxi::Util.blank?(options[:fill])
|
|
123
|
+
options[:fill] = 'FFFFFF'
|
|
124
|
+
end
|
|
105
125
|
xml['w'].tc do
|
|
106
126
|
xml['w'].tcPr do
|
|
107
127
|
xml['w'].tcW( 'w:w' => ( options[:width].to_i * 14.92 ).to_i, 'w:type' => "dxa" ) if options[:width]
|
|
@@ -150,6 +170,18 @@ module Docxi
|
|
|
150
170
|
img
|
|
151
171
|
end
|
|
152
172
|
|
|
173
|
+
def page_numbers
|
|
174
|
+
numbers = PageNumbers.new
|
|
175
|
+
@content << numbers
|
|
176
|
+
numbers
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def p(options={}, &block)
|
|
180
|
+
element = Docxi::Word::Contents::Paragraph.new(options, &block)
|
|
181
|
+
@content << element
|
|
182
|
+
element
|
|
183
|
+
end
|
|
184
|
+
|
|
153
185
|
class Image
|
|
154
186
|
attr_accessor :media, :options
|
|
155
187
|
def initialize(media, options={})
|
|
@@ -215,6 +247,54 @@ module Docxi
|
|
|
215
247
|
end
|
|
216
248
|
end
|
|
217
249
|
end
|
|
250
|
+
|
|
251
|
+
class PageNumbers
|
|
252
|
+
|
|
253
|
+
attr_accessor :options
|
|
254
|
+
def initialize(options={})
|
|
255
|
+
@options = options
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
def render(xml)
|
|
259
|
+
xml['w'].sdt do
|
|
260
|
+
xml['w'].sdtPr do
|
|
261
|
+
xml['w'].id( 'w:val' => "-472213903" )
|
|
262
|
+
xml['w'].docPartObj do
|
|
263
|
+
xml['w'].docPartGallery( 'w:val' => "Page Numbers (Bottom of Page)" )
|
|
264
|
+
xml['w'].docPartUnique
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
xml['w'].sdtContent do
|
|
268
|
+
xml['w'].p do
|
|
269
|
+
xml['w'].pPr do
|
|
270
|
+
xml['w'].jc( 'w:val' => @options[:align] || 'right' )
|
|
271
|
+
end
|
|
272
|
+
xml['w'].r do
|
|
273
|
+
xml['w'].rPr do
|
|
274
|
+
xml['w'].rFonts( 'w:cs'=> 'Arial', 'w:ascii'=> 'Arial', 'w:hAnsi' => 'Arial' )
|
|
275
|
+
xml['w'].color( 'w:val' => '404040')
|
|
276
|
+
xml['w'].sz( 'w:val' => '20' )
|
|
277
|
+
end
|
|
278
|
+
xml['w'].t 'GlobalOptions '
|
|
279
|
+
end
|
|
280
|
+
xml['w'].r do
|
|
281
|
+
xml['w'].fldChar( 'w:fldCharType' => "begin" )
|
|
282
|
+
end
|
|
283
|
+
xml['w'].r do
|
|
284
|
+
xml['w'].instrText "PAGE \* MERGEFORMAT"
|
|
285
|
+
end
|
|
286
|
+
xml['w'].r do
|
|
287
|
+
xml['w'].fldChar( 'w:fldCharType' => "separate" )
|
|
288
|
+
end
|
|
289
|
+
xml['w'].r do
|
|
290
|
+
xml['w'].fldChar( 'w:fldCharType' => "end" )
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
|
|
218
298
|
end
|
|
219
299
|
end
|
|
220
300
|
end
|
|
@@ -14,13 +14,19 @@ module Docxi
|
|
|
14
14
|
if !@text.nil?
|
|
15
15
|
xml['w'].r do
|
|
16
16
|
xml['w'].rPr do
|
|
17
|
+
xml['w'].rFonts( 'w:cs'=> @options[:font], 'w:ascii'=> @options[:font], 'w:hAnsi' => @options[:font] ) if @options[:font]
|
|
17
18
|
xml['w'].b if @options[:bold]
|
|
18
19
|
xml['w'].i if @options[:italic]
|
|
19
20
|
xml['w'].u( 'w:val' => "single" ) if options[:underline]
|
|
20
21
|
xml['w'].color( 'w:val' => @options[:color] ) if @options[:color]
|
|
21
22
|
xml['w'].sz( 'w:val' => @options[:size].to_i * 2 ) if @options[:size]
|
|
23
|
+
xml['w'].shd( 'w:val' => 'clear','w:fill' => @options[:fill] ) if @options[:fill]
|
|
24
|
+
end
|
|
25
|
+
if @options[:space]
|
|
26
|
+
xml['w'].t( @text, 'xml:space' => "preserve" )
|
|
27
|
+
else
|
|
28
|
+
xml['w'].t @text
|
|
22
29
|
end
|
|
23
|
-
xml['w'].t @text
|
|
24
30
|
end
|
|
25
31
|
if options[:br]
|
|
26
32
|
br = Docxi::Word::Contents::Break.new
|
data/lib/docxi/word/contents.rb
CHANGED
data/lib/docxi/word/document.rb
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
require_relative 'hyperlinks/hyperlink.rb'
|
|
2
|
+
require_relative 'hyperlinks.rb'
|
|
1
3
|
module Docxi
|
|
2
4
|
module Word
|
|
3
5
|
class Document
|
|
4
6
|
|
|
5
7
|
include Helpers
|
|
6
8
|
|
|
7
|
-
attr_accessor :options, :fonts, :setings, :styles, :numbering, :effects, :web_settings, :themes, :relationships, :footnotes, :endnotes, :footers, :headers
|
|
9
|
+
attr_accessor :options, :fonts, :setings, :styles, :numbering, :effects, :web_settings, :themes, :relationships, :footnotes, :endnotes, :footers, :headers, :hyperlinks
|
|
8
10
|
|
|
9
11
|
def initialize(options)
|
|
10
12
|
@options = options
|
|
@@ -26,6 +28,22 @@ module Docxi
|
|
|
26
28
|
@footer = footer
|
|
27
29
|
end
|
|
28
30
|
|
|
31
|
+
def add_first_footer(footer, options={})
|
|
32
|
+
footer.id = footers.sequence
|
|
33
|
+
rel = relationships.add(footer.content_type, footer.target)
|
|
34
|
+
footer.sequence = rel.id
|
|
35
|
+
footers.add(footer)
|
|
36
|
+
@first_footer = footer
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def add_first_header(header, options={})
|
|
40
|
+
header.id = headers.sequence
|
|
41
|
+
rel = relationships.add(header.content_type, header.target)
|
|
42
|
+
header.sequence = rel.id
|
|
43
|
+
headers.add(header)
|
|
44
|
+
@first_header = header
|
|
45
|
+
end
|
|
46
|
+
|
|
29
47
|
def add_header(header, options={})
|
|
30
48
|
header.id = headers.sequence
|
|
31
49
|
rel = relationships.add(header.content_type, header.target)
|
|
@@ -34,6 +52,14 @@ module Docxi
|
|
|
34
52
|
@header = header
|
|
35
53
|
end
|
|
36
54
|
|
|
55
|
+
def add_hyperlink(link, options={})
|
|
56
|
+
hyperlink = Hyperlinks::Hyperlink.new(hyperlinks.sequence, options)
|
|
57
|
+
rel = relationships.add(hyperlink.content_type, link, 'External')
|
|
58
|
+
hyperlink.set_sequence(rel.id)
|
|
59
|
+
hyperlinks.add(hyperlink)
|
|
60
|
+
return rel.id
|
|
61
|
+
end
|
|
62
|
+
|
|
37
63
|
def fonts
|
|
38
64
|
@fonts ||= Fonts.new
|
|
39
65
|
end
|
|
@@ -82,13 +108,24 @@ module Docxi
|
|
|
82
108
|
@footers ||= Footers.new
|
|
83
109
|
end
|
|
84
110
|
|
|
111
|
+
def first_footer
|
|
112
|
+
@first_footer ||= Footers.new
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def first_header
|
|
116
|
+
@first_header ||= Headers.new
|
|
117
|
+
end
|
|
118
|
+
|
|
85
119
|
def headers
|
|
86
120
|
@headers ||= Headers.new
|
|
87
121
|
end
|
|
88
122
|
|
|
123
|
+
def hyperlinks
|
|
124
|
+
@hyperlinks ||= Hyperlinks.new
|
|
125
|
+
end
|
|
126
|
+
|
|
89
127
|
def render(zip)
|
|
90
|
-
|
|
91
|
-
zip.write(Docxi.to_xml(document))
|
|
128
|
+
Docxi.write_entry(zip, 'word/document.xml', Docxi.to_xml(document))
|
|
92
129
|
|
|
93
130
|
fonts.render(zip)
|
|
94
131
|
settings.render(zip)
|
|
@@ -108,7 +145,7 @@ module Docxi
|
|
|
108
145
|
private
|
|
109
146
|
def document
|
|
110
147
|
Nokogiri::XML::Builder.with(Nokogiri::XML('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>')) do |xml|
|
|
111
|
-
xml.document('xmlns:
|
|
148
|
+
xml.document('xmlns:o' => 'urn:schemas-microsoft-com:office:office', 'xmlns:r' => 'http://schemas.openxmlformats.org/officeDocument/2006/relationships' ,'xmlns:v' => 'urn:schemas-microsoft-com:vml', 'xmlns:w' => 'http://schemas.openxmlformats.org/wordprocessingml/2006/main', 'xmlns:w10' =>'urn:schemas-microsoft-com:office:word', 'xmlns:wp' =>'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing') do
|
|
112
149
|
xml.parent.namespace = xml.parent.namespace_definitions.find{|ns| ns.prefix == "w" }
|
|
113
150
|
|
|
114
151
|
xml['w'].body do
|
|
@@ -122,11 +159,13 @@ module Docxi
|
|
|
122
159
|
xml['w'].bookmarkEnd('w:id' => "0")
|
|
123
160
|
end
|
|
124
161
|
xml['w'].sectPr do
|
|
125
|
-
xml['w'].footerReference( 'w:type' => "default", 'r:id' => @footer.sequence ) if @footer
|
|
126
162
|
xml['w'].headerReference( 'w:type' => "default", 'r:id' => @header.sequence ) if @header
|
|
163
|
+
xml['w'].headerReference( 'w:type' => "first", 'r:id' => @first_header.sequence ) if @first_header
|
|
164
|
+
xml['w'].footerReference( 'w:type' => "default", 'r:id' => @footer.sequence ) if @footer
|
|
165
|
+
xml['w'].footerReference( 'w:type' => "first", 'r:id' => @first_footer.sequence ) if @first_footer
|
|
127
166
|
xml['w'].titlePg
|
|
128
167
|
xml['w'].pgSz( 'w:w' => 12240, 'w:h' => 15840 )
|
|
129
|
-
xml['w'].pgMar( 'w:top' =>
|
|
168
|
+
xml['w'].pgMar( 'w:top' => @options[:top], 'w:right' => @options[:right], 'w:bottom' => @options[:bottom], 'w:left' => @options[:left], 'w:header' => Docxi::Util.present?(@options[:header]) ? @options[:header] : 190, 'w:footer' => Docxi::Util.present?(@options[:footer]) ? @options[:footer] : 200 , 'w:gutter' => 0)
|
|
130
169
|
xml['w'].cols( 'w:space' => 720)
|
|
131
170
|
xml['w'].docGrid( 'w:linePitch' => "360")
|
|
132
171
|
end
|
data/lib/docxi/word/effects.rb
CHANGED
data/lib/docxi/word/endnotes.rb
CHANGED
data/lib/docxi/word/fonts.rb
CHANGED
|
@@ -18,6 +18,12 @@ module Docxi
|
|
|
18
18
|
end
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
+
def br(options={})
|
|
22
|
+
br = Docxi::Word::Contents::Break.new(options)
|
|
23
|
+
@content << br
|
|
24
|
+
br
|
|
25
|
+
end
|
|
26
|
+
|
|
21
27
|
def content_type
|
|
22
28
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer"
|
|
23
29
|
end
|
|
@@ -27,12 +33,10 @@ module Docxi
|
|
|
27
33
|
end
|
|
28
34
|
|
|
29
35
|
def render(zip)
|
|
30
|
-
|
|
31
|
-
zip.write(Docxi.to_xml(document))
|
|
36
|
+
Docxi.write_entry(zip, "word/#{target}", Docxi.to_xml(document))
|
|
32
37
|
|
|
33
38
|
if !@relationships.empty?
|
|
34
|
-
|
|
35
|
-
zip.write(Docxi.to_xml(relationships))
|
|
39
|
+
Docxi.write_entry(zip, "word/_rels/#{target}.rels", Docxi.to_xml(relationships))
|
|
36
40
|
end
|
|
37
41
|
end
|
|
38
42
|
|
|
@@ -45,12 +49,18 @@ module Docxi
|
|
|
45
49
|
element
|
|
46
50
|
end
|
|
47
51
|
|
|
48
|
-
def page_numbers
|
|
49
|
-
numbers = PageNumbers.new
|
|
52
|
+
def page_numbers(options={})
|
|
53
|
+
numbers = PageNumbers.new(options)
|
|
50
54
|
@content << numbers
|
|
51
55
|
numbers
|
|
52
56
|
end
|
|
53
57
|
|
|
58
|
+
def table(options={}, &block)
|
|
59
|
+
table = Docxi::Word::Contents::Table.new(options, &block)
|
|
60
|
+
@content << table
|
|
61
|
+
table
|
|
62
|
+
end
|
|
63
|
+
|
|
54
64
|
class PageNumbers
|
|
55
65
|
|
|
56
66
|
attr_accessor :options
|
|
@@ -72,6 +82,14 @@ module Docxi
|
|
|
72
82
|
xml['w'].pPr do
|
|
73
83
|
xml['w'].jc( 'w:val' => @options[:align] || 'right' )
|
|
74
84
|
end
|
|
85
|
+
xml['w'].r do
|
|
86
|
+
xml['w'].rPr do
|
|
87
|
+
xml['w'].rFonts( 'w:cs'=> 'Arial', 'w:ascii'=> 'Arial', 'w:hAnsi' => 'Arial' )
|
|
88
|
+
xml['w'].color( 'w:val' => '404040')
|
|
89
|
+
xml['w'].sz( 'w:val' => '20' )
|
|
90
|
+
end
|
|
91
|
+
xml['w'].t @options[:name].to_s+' '
|
|
92
|
+
end
|
|
75
93
|
xml['w'].r do
|
|
76
94
|
xml['w'].fldChar( 'w:fldCharType' => "begin" )
|
|
77
95
|
end
|
data/lib/docxi/word/footnotes.rb
CHANGED
|
@@ -27,12 +27,10 @@ module Docxi
|
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
def render(zip)
|
|
30
|
-
|
|
31
|
-
zip.write(Docxi.to_xml(document))
|
|
30
|
+
Docxi.write_entry(zip, "word/#{target}", Docxi.to_xml(document))
|
|
32
31
|
|
|
33
32
|
if !@relationships.empty?
|
|
34
|
-
|
|
35
|
-
zip.write(Docxi.to_xml(relationships))
|
|
33
|
+
Docxi.write_entry(zip, "word/_rels/#{target}.rels", Docxi.to_xml(relationships))
|
|
36
34
|
end
|
|
37
35
|
end
|
|
38
36
|
|
|
@@ -43,11 +41,38 @@ module Docxi
|
|
|
43
41
|
img
|
|
44
42
|
end
|
|
45
43
|
|
|
44
|
+
def text(text, options={})
|
|
45
|
+
options = @options.merge(options)
|
|
46
|
+
element = Docxi::Word::Contents::Paragraph.new(options) do |p|
|
|
47
|
+
p.text(text)
|
|
48
|
+
end
|
|
49
|
+
@content << element
|
|
50
|
+
element
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def page_numbers(options={})
|
|
54
|
+
numbers = Docxi::Word::Footers::Footer::PageNumbers.new(options)
|
|
55
|
+
@content << numbers
|
|
56
|
+
numbers
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def br(options={})
|
|
60
|
+
br = Docxi::Word::Contents::Break.new(options)
|
|
61
|
+
@content << br
|
|
62
|
+
br
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def table(options={}, &block)
|
|
66
|
+
table = Docxi::Word::Contents::Table.new(options, &block)
|
|
67
|
+
@content << table
|
|
68
|
+
table
|
|
69
|
+
end
|
|
70
|
+
|
|
46
71
|
class Image
|
|
47
72
|
attr_accessor :media, :options
|
|
48
73
|
def initialize(media, options={})
|
|
49
74
|
@media = media
|
|
50
|
-
@media.file.rewind
|
|
75
|
+
# @media.file.rewind
|
|
51
76
|
@options = options
|
|
52
77
|
end
|
|
53
78
|
|
|
@@ -69,23 +94,35 @@ module Docxi
|
|
|
69
94
|
xml['w'].noProof
|
|
70
95
|
end
|
|
71
96
|
xml['w'].drawing do
|
|
72
|
-
xml['wp'].
|
|
73
|
-
xml['wp'].
|
|
74
|
-
xml['wp'].
|
|
97
|
+
xml['wp'].anchor( "behindDoc" => options[:behind] ,"distT" => 0,"distB" => 0, "distL" => 0, "distR" => 0 ,"simplePos" => 0 ,"locked" => 0, "layoutInCell" => 1, "allowOverlap" => 1, "relativeHeight" => 4) do
|
|
98
|
+
xml['wp'].simplePos('x'=> 0 , 'y' => 0 )
|
|
99
|
+
xml['wp'].positionH("relativeFrom" => "column") do
|
|
100
|
+
xml['wp'].posOffset options[:pH]
|
|
101
|
+
end
|
|
102
|
+
xml['wp'].positionV("relativeFrom" => "paragraph") do
|
|
103
|
+
xml['wp'].posOffset options[:pV]
|
|
104
|
+
end
|
|
105
|
+
xml['wp'].extent( 'cx' => ( options[:width] * options[:height] * 14.92 ).to_i, 'cy' => ( options[:width] * options[:height] * 14.92 ).to_i ) if options[:width] && options[:height]
|
|
106
|
+
xml['wp'].effectExtent( 'l' => 0, 't' => 0, 'r' => 0, 'b' => 0 )
|
|
107
|
+
if options[:wrap] == "none"
|
|
108
|
+
xml['wp'].wrapNone
|
|
109
|
+
else
|
|
110
|
+
xml['wp'].wrapSquare("wrapText"=> "bothSides")
|
|
111
|
+
end
|
|
75
112
|
xml['wp'].docPr( 'id' => 1, 'name'=> "Image", 'descr' => "image")
|
|
76
113
|
xml['wp'].cNvGraphicFramePr do
|
|
77
|
-
xml.graphicFrameLocks( 'xmlns:a' => "http://schemas.openxmlformats.org/drawingml/2006/main", 'noChangeAspect' => 1 ) do
|
|
114
|
+
xml.graphicFrameLocks( 'xmlns:a' => "http://schemas.openxmlformats.org/drawingml/2006/main", 'noChangeAspect' => "1" ) do
|
|
78
115
|
xml.parent.namespace = xml.parent.namespace_definitions.find{|ns| ns.prefix == "a" }
|
|
79
116
|
end
|
|
80
117
|
end
|
|
81
118
|
xml.graphic( 'xmlns:a' => "http://schemas.openxmlformats.org/drawingml/2006/main" ) do
|
|
82
119
|
xml.parent.namespace = xml.parent.namespace_definitions.find{|ns| ns.prefix == "a" }
|
|
83
120
|
xml['a'].graphicData( 'uri' => "http://schemas.openxmlformats.org/drawingml/2006/picture") do
|
|
84
|
-
xml.pic( 'xmlns:pic' => "http://schemas.openxmlformats.org/drawingml/2006/picture"
|
|
121
|
+
xml.pic( 'xmlns:pic' => "http://schemas.openxmlformats.org/drawingml/2006/picture") do
|
|
85
122
|
xml.parent.namespace = xml.parent.namespace_definitions.find{|ns| ns.prefix == "pic" }
|
|
86
123
|
xml['pic'].nvPicPr do
|
|
87
124
|
xml['pic'].cNvPr( 'id' => 0, 'name' => "Image" )
|
|
88
|
-
xml['pic'].cNvPicPr
|
|
125
|
+
xml['pic'].cNvPicPr
|
|
89
126
|
end
|
|
90
127
|
xml['pic'].blipFill do
|
|
91
128
|
xml['a'].blip( 'r:embed' => @media.sequence ) do
|
|
@@ -95,14 +132,21 @@ module Docxi
|
|
|
95
132
|
xml['a'].fillRect
|
|
96
133
|
end
|
|
97
134
|
end
|
|
98
|
-
xml['pic'].spPr do
|
|
135
|
+
xml['pic'].spPr( 'bwMode' => "auto" ) do
|
|
99
136
|
xml['a'].xfrm do
|
|
100
137
|
xml['a'].off( 'x' => 0, 'y' => 0 )
|
|
101
|
-
xml['a'].ext( 'cx' => ( width *
|
|
138
|
+
xml['a'].ext( 'cx' => ( options[:width] * options[:height] * 14.92 ).to_i, 'cy' => ( options[:width] * options[:height] * 14.92).to_i ) if options[:width] && options[:height]
|
|
102
139
|
end
|
|
103
140
|
xml['a'].prstGeom( 'prst' => "rect" ) do
|
|
104
141
|
xml['a'].avLst
|
|
105
142
|
end
|
|
143
|
+
# xml['a'].noFill
|
|
144
|
+
# xml['a'].ln('w' => "9525") do
|
|
145
|
+
# xml['a'].noFill
|
|
146
|
+
# xml['a'].miter('lim'=>"800000")
|
|
147
|
+
# xml['a'].headEnd
|
|
148
|
+
# xml['a'].tailEnd
|
|
149
|
+
# end
|
|
106
150
|
end
|
|
107
151
|
end
|
|
108
152
|
end
|
data/lib/docxi/word/helpers.rb
CHANGED
|
@@ -8,12 +8,24 @@ module Docxi
|
|
|
8
8
|
end
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
+
def frame(text, options={})
|
|
12
|
+
p(options) do |p|
|
|
13
|
+
p.frame(options) { |f| f.text text }
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
11
17
|
def br(options={})
|
|
12
18
|
element = Docxi::Word::Contents::Break.new(options)
|
|
13
19
|
@content << element
|
|
14
20
|
element
|
|
15
21
|
end
|
|
16
22
|
|
|
23
|
+
def tab(options={})
|
|
24
|
+
element = Docxi::Word::Contents::Tab.new(options)
|
|
25
|
+
@content << element
|
|
26
|
+
element
|
|
27
|
+
end
|
|
28
|
+
|
|
17
29
|
def p(options={}, &block)
|
|
18
30
|
element = Docxi::Word::Contents::Paragraph.new(options, &block)
|
|
19
31
|
@content << element
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
#encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Docxi
|
|
4
|
+
module Word
|
|
5
|
+
class Hyperlinks
|
|
6
|
+
class Hyperlink
|
|
7
|
+
|
|
8
|
+
attr_accessor :id, :sequence
|
|
9
|
+
def initialize(id,options={})
|
|
10
|
+
@options = options
|
|
11
|
+
@id = id
|
|
12
|
+
|
|
13
|
+
if block_given?
|
|
14
|
+
yield self
|
|
15
|
+
else
|
|
16
|
+
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def set_sequence(sequence)
|
|
21
|
+
@sequence = sequence
|
|
22
|
+
self
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def content_type
|
|
26
|
+
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def target
|
|
30
|
+
"document.xml"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def render(zip)
|
|
34
|
+
Docxi.write_entry(zip, "word/#{target}", Docxi.to_xml(document))
|
|
35
|
+
if !@relationships.empty?
|
|
36
|
+
Docxi.write_entry(zip, "word/_rels/#{target}.rels", Docxi.to_xml(relationships))
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def hyperlink(text,link)
|
|
41
|
+
text = Hyperlink.new(text, link, id)
|
|
42
|
+
@content << text
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class Hyperlink
|
|
46
|
+
attr_accessor :text, :link
|
|
47
|
+
def initialize(text, link )
|
|
48
|
+
@text = text
|
|
49
|
+
@link = link
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def content_type
|
|
53
|
+
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def render(xml)
|
|
57
|
+
xml['w'].hyperlink('w:id' => '1') do
|
|
58
|
+
xml['w'].r do
|
|
59
|
+
xml['w'].pPr do
|
|
60
|
+
xml['w'].rStyle( 'w:val' => "InternetLink")
|
|
61
|
+
end
|
|
62
|
+
xml['w'].t @text
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
def document
|
|
71
|
+
Nokogiri::XML::Builder.with(Nokogiri::XML('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>')) do |xml|
|
|
72
|
+
xml.hdr( 'xmlns:wpc' => "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas", 'xmlns:mc' => "http://schemas.openxmlformats.org/markup-compatibility/2006", 'xmlns:o' => "urn:schemas-microsoft-com:office:office", 'xmlns:r' => "http://schemas.openxmlformats.org/officeDocument/2006/relationships", 'xmlns:m' => "http://schemas.openxmlformats.org/officeDocument/2006/math", 'xmlns:v' => "urn:schemas-microsoft-com:vml", 'xmlns:wp14' => "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing", 'xmlns:wp' => "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing", 'xmlns:w10' => "urn:schemas-microsoft-com:office:word", 'xmlns:w' => "http://schemas.openxmlformats.org/wordprocessingml/2006/main", 'xmlns:w14' => "http://schemas.microsoft.com/office/word/2010/wordml", 'xmlns:wpg' => "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup", 'xmlns:wpi' => "http://schemas.microsoft.com/office/word/2010/wordprocessingInk", 'xmlns:wne' => "http://schemas.microsoft.com/office/word/2006/wordml", 'xmlns:wps' => "http://schemas.microsoft.com/office/word/2010/wordprocessingShape", 'mc:Ignorable' => "w14 wp14" ) do
|
|
73
|
+
xml.parent.namespace = xml.parent.namespace_definitions.find{|ns| ns.prefix == "w" }
|
|
74
|
+
@content.each do |element|
|
|
75
|
+
element.render(xml)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def relationships
|
|
82
|
+
Nokogiri::XML::Builder.with(Nokogiri::XML('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>')) do |xml|
|
|
83
|
+
xml.Relationships(xmlns: 'http://schemas.openxmlformats.org/package/2006/relationships') do
|
|
84
|
+
@relationships.each do |relationship|
|
|
85
|
+
xml.Relationship('Id' => relationship.sequence, 'Type' => relationship.content_type, 'Target' => relationship.target)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require 'docxi/word/hyperlinks/hyperlink'
|
|
2
|
+
|
|
3
|
+
module Docxi
|
|
4
|
+
module Word
|
|
5
|
+
class Hyperlinks
|
|
6
|
+
|
|
7
|
+
attr_accessor :hyperlinks, :counter
|
|
8
|
+
def initialize
|
|
9
|
+
@hyperlinks = []
|
|
10
|
+
@counter = 0
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def add(hyperlink)
|
|
14
|
+
@hyperlinks << hyperlink
|
|
15
|
+
hyperlink
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def sequence
|
|
19
|
+
@counter += 1
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def render(zip)
|
|
23
|
+
@hyperlinks.each do |hyperlink|
|
|
24
|
+
hyperlink.render(zip)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -3,6 +3,8 @@ module Docxi
|
|
|
3
3
|
class Medias
|
|
4
4
|
class Media
|
|
5
5
|
|
|
6
|
+
URL = %r{\A(?:https?|ftp)://}i
|
|
7
|
+
|
|
6
8
|
attr_accessor :id, :sequence, :file
|
|
7
9
|
def initialize(id, file, options)
|
|
8
10
|
@id = id
|
|
@@ -10,6 +12,22 @@ module Docxi
|
|
|
10
12
|
self
|
|
11
13
|
end
|
|
12
14
|
|
|
15
|
+
# Strings are URLs or file paths. Kernel#open, and File.binread on
|
|
16
|
+
# Ruby 2.5, run strings starting with "|" as shell commands, and
|
|
17
|
+
# Kernel#open stopped fetching URLs in Ruby 3.
|
|
18
|
+
def read
|
|
19
|
+
if @file.is_a?(String)
|
|
20
|
+
if @file =~ URL
|
|
21
|
+
require 'open-uri'
|
|
22
|
+
URI.parse(@file).open { |io| io.read }
|
|
23
|
+
else
|
|
24
|
+
File.open(@file, 'rb') { |file| file.read }
|
|
25
|
+
end
|
|
26
|
+
else
|
|
27
|
+
@file.read
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
13
31
|
def set_sequence(sequence)
|
|
14
32
|
@sequence = sequence
|
|
15
33
|
self
|