docxer 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +22 -0
- data/README.md +119 -0
- data/Rakefile +9 -0
- data/lib/docxer.rb +29 -0
- data/lib/docxer/content_types.rb +68 -0
- data/lib/docxer/content_types/default.rb +18 -0
- data/lib/docxer/content_types/override.rb +18 -0
- data/lib/docxer/document.rb +36 -0
- data/lib/docxer/properties.rb +29 -0
- data/lib/docxer/properties/app.rb +37 -0
- data/lib/docxer/properties/core.rb +32 -0
- data/lib/docxer/relationships.rb +49 -0
- data/lib/docxer/relationships/relationship.rb +19 -0
- data/lib/docxer/version.rb +3 -0
- data/lib/docxer/word.rb +16 -0
- data/lib/docxer/word/contents.rb +6 -0
- data/lib/docxer/word/contents/break.rb +33 -0
- data/lib/docxer/word/contents/image.rb +38 -0
- data/lib/docxer/word/contents/paragraph.rb +59 -0
- data/lib/docxer/word/contents/table.rb +223 -0
- data/lib/docxer/word/contents/table_of_content.rb +75 -0
- data/lib/docxer/word/contents/text.rb +34 -0
- data/lib/docxer/word/document.rb +144 -0
- data/lib/docxer/word/effects.rb +210 -0
- data/lib/docxer/word/endnotes.rb +39 -0
- data/lib/docxer/word/fonts.rb +42 -0
- data/lib/docxer/word/fonts/font.rb +25 -0
- data/lib/docxer/word/footers.rb +30 -0
- data/lib/docxer/word/footers/footer.rb +118 -0
- data/lib/docxer/word/footnotes.rb +40 -0
- data/lib/docxer/word/headers.rb +30 -0
- data/lib/docxer/word/headers/header.rb +142 -0
- data/lib/docxer/word/helpers.rb +37 -0
- data/lib/docxer/word/medias.rb +31 -0
- data/lib/docxer/word/medias/media.rb +37 -0
- data/lib/docxer/word/numbering.rb +141 -0
- data/lib/docxer/word/relationships.rb +57 -0
- data/lib/docxer/word/relationships/relationship.rb +21 -0
- data/lib/docxer/word/settings.rb +61 -0
- data/lib/docxer/word/styles.rb +235 -0
- data/lib/docxer/word/themes.rb +30 -0
- data/lib/docxer/word/themes/theme.rb +313 -0
- data/lib/docxer/word/web_settings.rb +29 -0
- metadata +121 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
module Docxer
|
2
|
+
class Relationships
|
3
|
+
class Relationship
|
4
|
+
|
5
|
+
attr_accessor :id, :type, :target
|
6
|
+
|
7
|
+
def initialize(id, type, target)
|
8
|
+
@id = id
|
9
|
+
@type = type
|
10
|
+
@target = target
|
11
|
+
end
|
12
|
+
|
13
|
+
def build(xml)
|
14
|
+
xml.Relationship('Id' => @id, 'Type' => @type, 'Target' => @target)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/docxer/word.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'docxer/word/fonts'
|
2
|
+
require 'docxer/word/settings'
|
3
|
+
require 'docxer/word/styles'
|
4
|
+
require 'docxer/word/numbering'
|
5
|
+
require 'docxer/word/effects'
|
6
|
+
require 'docxer/word/web_settings'
|
7
|
+
require 'docxer/word/themes'
|
8
|
+
require 'docxer/word/medias'
|
9
|
+
require 'docxer/word/relationships'
|
10
|
+
require 'docxer/word/footnotes'
|
11
|
+
require 'docxer/word/footers'
|
12
|
+
require 'docxer/word/headers'
|
13
|
+
require 'docxer/word/endnotes'
|
14
|
+
require 'docxer/word/contents'
|
15
|
+
require 'docxer/word/helpers'
|
16
|
+
require 'docxer/word/document'
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Docxer
|
2
|
+
module Word
|
3
|
+
module Contents
|
4
|
+
|
5
|
+
class Break
|
6
|
+
|
7
|
+
attr_accessor :options
|
8
|
+
def initialize(options={})
|
9
|
+
@options = options
|
10
|
+
@options[:times] ||= 1
|
11
|
+
end
|
12
|
+
|
13
|
+
def render(xml)
|
14
|
+
if @options[:page]
|
15
|
+
xml['w'].p do
|
16
|
+
xml['w'].r do
|
17
|
+
xml['w'].br( 'w:type' => "page" )
|
18
|
+
end
|
19
|
+
end
|
20
|
+
else
|
21
|
+
@options[:times].times do
|
22
|
+
xml['w'].r do
|
23
|
+
xml['w'].br
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Docxer
|
2
|
+
module Word
|
3
|
+
module Contents
|
4
|
+
|
5
|
+
class Image
|
6
|
+
|
7
|
+
attr_accessor :media, :options
|
8
|
+
def initialize(media, options={})
|
9
|
+
@media = media
|
10
|
+
@media.file.rewind
|
11
|
+
@options = options
|
12
|
+
end
|
13
|
+
|
14
|
+
def styles
|
15
|
+
if @options[:style]
|
16
|
+
@options[:style].collect{|k, v| [k, v].join(':')}.join(';')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def render(xml)
|
21
|
+
xml['w'].r do
|
22
|
+
xml['w'].rPr do
|
23
|
+
xml['w'].noProof
|
24
|
+
end
|
25
|
+
xml['w'].pict do
|
26
|
+
xml['v'].shape( 'id' => @media.uniq_id, 'type' => @media.type, 'style' => styles ) do
|
27
|
+
xml['v'].imagedata( 'r:id' => @media.sequence, 'o:title' => @options[:title] )
|
28
|
+
end
|
29
|
+
end
|
30
|
+
xml['w'].rPr do
|
31
|
+
xml['w'].noProof
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Docxer
|
2
|
+
module Word
|
3
|
+
module Contents
|
4
|
+
|
5
|
+
class Paragraph
|
6
|
+
|
7
|
+
attr_accessor :content, :options
|
8
|
+
def initialize(options={})
|
9
|
+
@content = []
|
10
|
+
@options = options
|
11
|
+
|
12
|
+
if block_given?
|
13
|
+
yield self
|
14
|
+
else
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def render(xml)
|
20
|
+
xml['w'].p do
|
21
|
+
xml['w'].pPr do
|
22
|
+
xml['w'].jc( 'w:val' => @options[:align]) if @options[:align]
|
23
|
+
if options[:ul]
|
24
|
+
xml['w'].numPr do
|
25
|
+
xml['w'].ilvl( 'w:val' => 0 )
|
26
|
+
xml['w'].numId( 'w:val' => 1 )
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
@content.each do |element|
|
31
|
+
element.render(xml)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def text(text, options={})
|
37
|
+
options = @options.merge(options)
|
38
|
+
text = Docxer::Word::Contents::Text.new(text, options)
|
39
|
+
@content << text
|
40
|
+
text
|
41
|
+
end
|
42
|
+
|
43
|
+
def br(options={})
|
44
|
+
br = Docxer::Word::Contents::Break.new(options)
|
45
|
+
@content << br
|
46
|
+
br
|
47
|
+
end
|
48
|
+
|
49
|
+
def image(image, options={})
|
50
|
+
img = Docxer::Word::Contents::Image.new(image, options)
|
51
|
+
@content << img
|
52
|
+
img
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,223 @@
|
|
1
|
+
module Docxer
|
2
|
+
module Word
|
3
|
+
module Contents
|
4
|
+
|
5
|
+
class Table
|
6
|
+
|
7
|
+
attr_accessor :options, :rows
|
8
|
+
def initialize(options={})
|
9
|
+
@options = options
|
10
|
+
@rows = []
|
11
|
+
|
12
|
+
if block_given?
|
13
|
+
yield self
|
14
|
+
else
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def tr(options={}, &block)
|
20
|
+
options = @options.merge(options)
|
21
|
+
row = TableRow.new(options, &block)
|
22
|
+
@rows << row
|
23
|
+
row
|
24
|
+
end
|
25
|
+
|
26
|
+
def render(xml)
|
27
|
+
xml['w'].tbl do
|
28
|
+
xml['w'].tblPr do
|
29
|
+
xml['w'].tblStyle( 'w:val' => options[:style] ) if options[:style]
|
30
|
+
xml['w'].tblW( 'w:w' => options[:width], 'w:type' => "auto" ) if options[:width]
|
31
|
+
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
|
+
if @options[:borders]
|
33
|
+
xml['w'].tblBorders do
|
34
|
+
@options[:borders].each do |k, v|
|
35
|
+
if v.nil?
|
36
|
+
xml['w'].send(k, 'w:val' => "none", 'w:sz' => "0", 'w:space' => "0", 'w:color' => "auto" )
|
37
|
+
else
|
38
|
+
xml['w'].send(k, 'w:val' => "none", 'w:sz' => v, 'w:space' => "0", 'w:color' => "auto" )
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
xml['w'].tblGrid do
|
45
|
+
if options[:columns_width]
|
46
|
+
options[:columns_width].each do |width|
|
47
|
+
xml['w'].gridCol( 'w:w' => width.to_i * 14.92 )
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
@rows.each do |row|
|
52
|
+
row.render(xml)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class TableRow
|
58
|
+
|
59
|
+
attr_accessor :options, :cells
|
60
|
+
def initialize(options={})
|
61
|
+
@options = options
|
62
|
+
@cells = []
|
63
|
+
|
64
|
+
if block_given?
|
65
|
+
yield self
|
66
|
+
else
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def tc(options={}, &block)
|
72
|
+
if @options[:columns_width]
|
73
|
+
width = @options[:columns_width][@cells.size]
|
74
|
+
options[:width] ||= width if width
|
75
|
+
end
|
76
|
+
options = @options.merge(options)
|
77
|
+
cell = TableCell.new(options, &block)
|
78
|
+
@cells << cell
|
79
|
+
cell
|
80
|
+
end
|
81
|
+
|
82
|
+
def render(xml)
|
83
|
+
xml['w'].tr do
|
84
|
+
@cells.each do |cell|
|
85
|
+
cell.render(xml)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
class TableCell
|
91
|
+
|
92
|
+
attr_accessor :options, :content
|
93
|
+
def initialize(options={})
|
94
|
+
@options = options
|
95
|
+
@content = []
|
96
|
+
|
97
|
+
if block_given?
|
98
|
+
yield self
|
99
|
+
else
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def render(xml)
|
105
|
+
xml['w'].tc do
|
106
|
+
xml['w'].tcPr do
|
107
|
+
xml['w'].tcW( 'w:w' => ( options[:width].to_i * 14.92 ).to_i, 'w:type' => "dxa" ) if options[:width]
|
108
|
+
xml['w'].shd( 'w:val' => "clear", 'w:color' => "auto", 'w:fill' => options[:fill] ) if options[:fill]
|
109
|
+
if options[:borders]
|
110
|
+
xml['w'].tcBorders do
|
111
|
+
options[:borders].each do |k, v|
|
112
|
+
if v.nil?
|
113
|
+
xml['w'].send(k, 'w:val' => "nil" )
|
114
|
+
else
|
115
|
+
xml['w'].send(k, 'w:val' => "single", 'w:sz' => v, 'w:space' => "0", 'w:color' => "auto" )
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
if options[:merged]
|
121
|
+
xml['w'].vMerge
|
122
|
+
else
|
123
|
+
xml['w'].vAlign( 'w:val' => options[:valign] ) if options[:valign]
|
124
|
+
xml['w'].gridSpan( 'w:val' => options[:colspan] ) if options[:colspan]
|
125
|
+
xml['w'].vMerge( 'w:val' => "restart" ) if options[:rowspan]
|
126
|
+
end
|
127
|
+
end
|
128
|
+
if options[:merged]
|
129
|
+
xml['w'].p
|
130
|
+
else
|
131
|
+
@content.each do |element|
|
132
|
+
element.render(xml)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def text(text, options={})
|
139
|
+
options = @options.merge(options)
|
140
|
+
element = Docxer::Word::Contents::Paragraph.new(options) do |p|
|
141
|
+
p.text(text)
|
142
|
+
end
|
143
|
+
@content << element
|
144
|
+
element
|
145
|
+
end
|
146
|
+
|
147
|
+
def image(image, options={})
|
148
|
+
img = Image.new(image, options)
|
149
|
+
@content << img
|
150
|
+
img
|
151
|
+
end
|
152
|
+
|
153
|
+
class Image
|
154
|
+
attr_accessor :media, :options
|
155
|
+
def initialize(media, options={})
|
156
|
+
@media = media
|
157
|
+
@options = options
|
158
|
+
end
|
159
|
+
|
160
|
+
def render(xml)
|
161
|
+
xml['w'].p do
|
162
|
+
xml['w'].r do
|
163
|
+
xml['w'].rPr do
|
164
|
+
xml['w'].noProof
|
165
|
+
end
|
166
|
+
xml['w'].drawing do
|
167
|
+
xml['wp'].inline( 'distT' => 0, 'distB' => 0, 'distL' => 0, 'distR' => 0 ) do
|
168
|
+
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]
|
169
|
+
xml['wp'].effectExtent( 'l' => 0, 't' => 0, 'r' => 0, 'b' => 0 )
|
170
|
+
xml['wp'].docPr( 'id' => @media.id, 'name'=> "Image", 'descr' => "image")
|
171
|
+
xml['wp'].cNvGraphicFramePr do
|
172
|
+
xml.graphicFrameLocks( 'xmlns:a' => "http://schemas.openxmlformats.org/drawingml/2006/main", 'noChangeAspect' => "1" ) do
|
173
|
+
xml.parent.namespace = xml.parent.namespace_definitions.find{|ns| ns.prefix == "a" }
|
174
|
+
end
|
175
|
+
end
|
176
|
+
xml.graphic( 'xmlns:a' => "http://schemas.openxmlformats.org/drawingml/2006/main" ) do
|
177
|
+
xml.parent.namespace = xml.parent.namespace_definitions.find{|ns| ns.prefix == "a" }
|
178
|
+
xml['a'].graphicData( 'uri' => "http://schemas.openxmlformats.org/drawingml/2006/picture") do
|
179
|
+
xml.pic( 'xmlns:pic' => "http://schemas.openxmlformats.org/drawingml/2006/picture") do
|
180
|
+
xml.parent.namespace = xml.parent.namespace_definitions.find{|ns| ns.prefix == "pic" }
|
181
|
+
xml['pic'].nvPicPr do
|
182
|
+
xml['pic'].cNvPr( 'id' => 0, 'name' => "Image", 'descr' => "description" )
|
183
|
+
xml['pic'].cNvPicPr do
|
184
|
+
xml['a'].picLocks( 'noChangeAspect' => "1", 'noChangeArrowheads' => "1" )
|
185
|
+
end
|
186
|
+
end
|
187
|
+
xml['pic'].blipFill do
|
188
|
+
xml['a'].blip( 'r:embed' => @media.sequence ) do
|
189
|
+
xml['a'].extLst
|
190
|
+
end
|
191
|
+
xml['a'].srcRect
|
192
|
+
xml['a'].stretch do
|
193
|
+
xml['a'].fillRect
|
194
|
+
end
|
195
|
+
end
|
196
|
+
xml['pic'].spPr( 'bwMode' => "auto" ) do
|
197
|
+
xml['a'].xfrm do
|
198
|
+
xml['a'].off( 'x' => 0, 'y' => 0 )
|
199
|
+
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]
|
200
|
+
end
|
201
|
+
xml['a'].prstGeom( 'prst' => "rect" ) do
|
202
|
+
xml['a'].avLst
|
203
|
+
end
|
204
|
+
xml['a'].noFill
|
205
|
+
xml['a'].ln do
|
206
|
+
xml['a'].noFill
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Docxer
|
2
|
+
module Word
|
3
|
+
module Contents
|
4
|
+
|
5
|
+
class TableOfContent
|
6
|
+
|
7
|
+
attr_accessor :options, :rows
|
8
|
+
def initialize(options={})
|
9
|
+
@options = options
|
10
|
+
@rows = []
|
11
|
+
|
12
|
+
if block_given?
|
13
|
+
yield self
|
14
|
+
else
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_row(text, page=nil, options={})
|
20
|
+
row = Row.new(text, page, options)
|
21
|
+
@rows << row
|
22
|
+
row
|
23
|
+
end
|
24
|
+
|
25
|
+
def render(xml)
|
26
|
+
@rows.each do |row|
|
27
|
+
row.render(xml)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
class Row
|
33
|
+
|
34
|
+
attr_accessor :text, :page, :options
|
35
|
+
def initialize(text, page=nil, options={})
|
36
|
+
@text = text
|
37
|
+
@page = page
|
38
|
+
@options = options
|
39
|
+
end
|
40
|
+
|
41
|
+
def render(xml)
|
42
|
+
if @page.nil?
|
43
|
+
xml['w'].p do
|
44
|
+
xml['w'].pPr do
|
45
|
+
xml['w'].spacing( 'w:before' => "0", 'w:after' => "160")
|
46
|
+
end
|
47
|
+
xml['w'].r do
|
48
|
+
xml['w'].tab
|
49
|
+
xml['w'].t @text
|
50
|
+
end
|
51
|
+
end
|
52
|
+
else
|
53
|
+
xml['w'].p do
|
54
|
+
xml['w'].pPr do
|
55
|
+
xml['w'].pStyle( 'w:val' => "ListParagraph") # TODO: Apply styles
|
56
|
+
xml['w'].spacing( 'w:before' => "0", 'w:after' => "160")
|
57
|
+
xml['w'].tabs do
|
58
|
+
xml['w'].tab( 'w:val' => "right", 'w:leader' => @options[:leader] || 'dot', 'w:pos' => @options[:pos] || 9360 )
|
59
|
+
end
|
60
|
+
end
|
61
|
+
xml['w'].r do
|
62
|
+
xml['w'].t @text
|
63
|
+
end
|
64
|
+
xml['w'].r do
|
65
|
+
xml['w'].tab
|
66
|
+
xml['w'].t( @page, 'xml:space' => "preserve" )
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|