docxi 0.0.2 → 0.0.6
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/README.md +45 -4
- data/lib/docxi/content_types.rb +5 -0
- data/lib/docxi/document.rb +4 -4
- 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/document.rb +44 -4
- data/lib/docxi/word/footers/footer.rb +22 -2
- data/lib/docxi/word/headers/header.rb +55 -9
- data/lib/docxi/word/helpers.rb +12 -0
- data/lib/docxi/word/hyperlinks.rb +30 -0
- data/lib/docxi/word/hyperlinks/hyperlink.rb +96 -0
- data/lib/docxi/word/medias.rb +7 -1
- data/lib/docxi/word/relationships.rb +4 -4
- data/lib/docxi/word/relationships/relationship.rb +8 -3
- data/lib/docxi/word/styles.rb +5 -4
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5076084e490ded4f975883817964681a11cb0020
|
|
4
|
+
data.tar.gz: 8e6c401e687f6eaad1c5a1c23060481f0e552576
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2b1f94d68e5d454c5703c9c26ab851bd4a886a2c7c7c27f8162d7fa2ef3599dd0eb179e02f18a1bef9065b4df27c31bff15f3383d0e99e0e95279f184b152a52
|
|
7
|
+
data.tar.gz: 7e714bdd0ccbfb487180beb5ef57f3fbb84c3ff6661d929d0750d9bc2f336cbf6af9b5b8ff4a14b962cd299ec7942cf181664e8feef9f3bcd6318bc30086f396
|
data/README.md
CHANGED
|
@@ -11,11 +11,16 @@ Docxi gem provides ability to create docx documents using Ruby.
|
|
|
11
11
|
7. Page Numbering
|
|
12
12
|
|
|
13
13
|
At the moment, the gem supports a limited number of functions, but the development of the gem is still in progress, and perhaps functionality will be expanded in the future. First of all, try to add documentation for the code and tests.
|
|
14
|
-
|
|
14
|
+
## NOTE
|
|
15
|
+
Use Latest version of Gem. Old Version has bugs.
|
|
15
16
|
## Usage
|
|
16
17
|
|
|
17
18
|
```ruby
|
|
18
|
-
|
|
19
|
+
# default attributes (top: 720,right: 1440,left: 1440,bottom: 720,footer: 200, header: 190)
|
|
20
|
+
word = Docxi::Document.new
|
|
21
|
+
# or change margins
|
|
22
|
+
# word = Docxi::Document.new(top: 0,right: 0,left: 0,bottom: 0)
|
|
23
|
+
|
|
19
24
|
document = word.document
|
|
20
25
|
|
|
21
26
|
# Creates Header
|
|
@@ -39,8 +44,8 @@ end
|
|
|
39
44
|
document.add_footer(footer)
|
|
40
45
|
|
|
41
46
|
# Creates paragraph
|
|
42
|
-
document.p(size:
|
|
43
|
-
p.text "Title"
|
|
47
|
+
document.p(size: 12, bold: true, align: "center", color: "000000", fill: "AAAAAA") do |p|
|
|
48
|
+
p.text "Title", size: 12, bold: true, align: "center", color: "000000"
|
|
44
49
|
# Adds 3 break lines
|
|
45
50
|
p.br times: 3
|
|
46
51
|
end
|
|
@@ -103,14 +108,50 @@ document.table( columns_width: [ 316, 160, 135 ] ) do |table|
|
|
|
103
108
|
end
|
|
104
109
|
end
|
|
105
110
|
|
|
111
|
+
# Adds table with row height and column indentation
|
|
112
|
+
document.table( columns_width: [ 316, 160, 135 ], height: 268, iwidth: 108) do |table|
|
|
113
|
+
# Adds row with specific styles
|
|
114
|
+
table.tr(fill: "FBD4B4", bold: true, align: 'center' ) do |tr|
|
|
115
|
+
# Adds cells
|
|
116
|
+
tr.tc(borders: { top: 1, right: nil, bottom: 1, left: 1 }) do |tc|
|
|
117
|
+
tc.text "Header 1"
|
|
118
|
+
end
|
|
119
|
+
tr.tc(borders: { top: 1, right: nil, bottom: 1, left: nil }) do |tc|
|
|
120
|
+
tc.text "Header 2"
|
|
121
|
+
end
|
|
122
|
+
tr.tc(borders: { top: 1, right: 1, bottom: 1, left: nil }) do |tc|
|
|
123
|
+
tc.text "Header 3"
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
|
|
106
129
|
# Adds image
|
|
107
130
|
document.p do |p|
|
|
108
131
|
p.text "Image Example", size: 16, bold: true, italic: true, underline: true, br: true
|
|
109
132
|
|
|
110
133
|
# Adds image to container
|
|
111
134
|
media = document.add_media File.open('image.png')
|
|
135
|
+
# Or add image URL
|
|
136
|
+
media = document.add_media image_url
|
|
112
137
|
# Insert media into paragraph
|
|
113
138
|
p.image media, style: { width: '200pt', height: '200pt' }
|
|
139
|
+
|
|
140
|
+
# Add Hyperlink
|
|
141
|
+
hyper = document.add_hyperlink("http://google.com")
|
|
142
|
+
p.hyperlink "Go to Google", "http://google.com", hyper
|
|
143
|
+
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Add Underline
|
|
147
|
+
document.p(bottom: true) do |p|
|
|
148
|
+
p.text "Example text"
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# Set position of Paragraph
|
|
152
|
+
document.p(fill: "d7d7d7",align: "center", right: -1000, left: -1000) do |p|
|
|
153
|
+
p.text "Example Text 2"
|
|
154
|
+
p.br
|
|
114
155
|
end
|
|
115
156
|
|
|
116
157
|
# Creates Word Document
|
data/lib/docxi/content_types.rb
CHANGED
|
@@ -11,6 +11,7 @@ module Docxi
|
|
|
11
11
|
add(:default, "rels", "application/vnd.openxmlformats-package.relationships+xml")
|
|
12
12
|
add(:default, "xml", "application/xml")
|
|
13
13
|
add(:default, "png", "image/png")
|
|
14
|
+
add(:override, "/_rels/.rels","application/vnd.openxmlformats-package.relationships+xml")
|
|
14
15
|
add(:override, "/word/document.xml", "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml")
|
|
15
16
|
add(:override, "/word/styles.xml", "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml")
|
|
16
17
|
add(:override, "/word/stylesWithEffects.xml", "application/vnd.ms-word.stylesWithEffects+xml")
|
|
@@ -24,7 +25,11 @@ module Docxi
|
|
|
24
25
|
add(:override, "/word/footnotes.xml", "application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml")
|
|
25
26
|
add(:override, "/word/endnotes.xml", "application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml")
|
|
26
27
|
add(:override, "/word/footer1.xml", "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml")
|
|
28
|
+
add(:override, "/word/footer2.xml", "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml")
|
|
27
29
|
add(:override, "/word/header1.xml", "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml")
|
|
30
|
+
add(:override, "/word/header2.xml", "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml")
|
|
31
|
+
add(:override, "/word/_rels/header2.xml.rels", "application/vnd.openxmlformats-package.relationships+xml")
|
|
32
|
+
add(:override, "/word/_rels/document.xml.rels", "application/vnd.openxmlformats-package.relationships+xml")
|
|
28
33
|
end
|
|
29
34
|
|
|
30
35
|
def add(type, attr, content)
|
data/lib/docxi/document.rb
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
module Docxi
|
|
2
2
|
class Document
|
|
3
3
|
|
|
4
|
-
attr_accessor :document, :properties, :relationships, :content_types
|
|
4
|
+
attr_accessor :document, :properties, :relationships, :content_types, :options
|
|
5
5
|
|
|
6
|
-
def initialize
|
|
7
|
-
|
|
6
|
+
def initialize(options = {top: 720,right: 1440,left: 1440,bottom: 720,footer: 200, header: 190})
|
|
7
|
+
@options = options
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def relationships
|
|
@@ -20,7 +20,7 @@ module Docxi
|
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def document
|
|
23
|
-
@document ||= Word::Document.new(
|
|
23
|
+
@document ||= Word::Document.new(options)
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def render
|
data/lib/docxi/version.rb
CHANGED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
module Docxi
|
|
2
|
+
module Word
|
|
3
|
+
module Contents
|
|
4
|
+
|
|
5
|
+
class Frame
|
|
6
|
+
|
|
7
|
+
attr_accessor :content, :options
|
|
8
|
+
def initialize(options={})
|
|
9
|
+
@content = []
|
|
10
|
+
@options = options
|
|
11
|
+
if block_given?
|
|
12
|
+
yield self
|
|
13
|
+
else
|
|
14
|
+
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def render(xml)
|
|
19
|
+
xml['w'].r do
|
|
20
|
+
xml['w'].pict do
|
|
21
|
+
xml['v'].rect("fillcolor"=>"#bfbfbf[2412]", "strokecolor"=>"000000","strokeweight"=>"0pt", "style"=> @options[:style]) do
|
|
22
|
+
xml['v'].fill("opacity" =>"52429f")
|
|
23
|
+
xml['v'].textbox("inset" => "0in,0in,0in,0in") do
|
|
24
|
+
xml['w'].txbxContent do
|
|
25
|
+
xml['w'].p do
|
|
26
|
+
xml['w'].pPr do
|
|
27
|
+
xml['w'].pStyle('w:val'=>"Normal")
|
|
28
|
+
xml['w'].pBdr do
|
|
29
|
+
xml['w'].top('w:val'=>"nil")
|
|
30
|
+
xml['w'].left('w:val'=>"nil")
|
|
31
|
+
xml['w'].bottom('w:val'=>"nil")
|
|
32
|
+
xml['w'].right('w:val'=>"nil")
|
|
33
|
+
end
|
|
34
|
+
if @options[:spacing]
|
|
35
|
+
xml['w'].spacing('w:before'=>"240")
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
@content.each do |element|
|
|
39
|
+
element.render(xml)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
xml['w10'].wrap('type'=>"topAndBottom")
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def br(options={})
|
|
51
|
+
br = Docxi::Word::Contents::Break.new(options)
|
|
52
|
+
@content << br
|
|
53
|
+
br
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def tab(options={})
|
|
57
|
+
tab = Docxi::Word::Contents::Tab.new(options)
|
|
58
|
+
@content << tab
|
|
59
|
+
tab
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def frame(options={}, &block)
|
|
63
|
+
element = Docxi::Word::Contents::Frame.new(options, &block)
|
|
64
|
+
@content << element
|
|
65
|
+
element
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def text(text, options={})
|
|
69
|
+
options = @options.merge(options)
|
|
70
|
+
text = Docxi::Word::Contents::Text.new(text, options)
|
|
71
|
+
@content << text
|
|
72
|
+
text
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def image(image, options={})
|
|
76
|
+
img = Docxi::Word::Contents::Image.new(image, options)
|
|
77
|
+
@content << img
|
|
78
|
+
img
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -7,7 +7,7 @@ module Docxi
|
|
|
7
7
|
attr_accessor :media, :options
|
|
8
8
|
def initialize(media, options={})
|
|
9
9
|
@media = media
|
|
10
|
-
@media.file.rewind
|
|
10
|
+
# @media.file.rewind
|
|
11
11
|
@options = options
|
|
12
12
|
end
|
|
13
13
|
|
|
@@ -19,16 +19,80 @@ module Docxi
|
|
|
19
19
|
|
|
20
20
|
def render(xml)
|
|
21
21
|
xml['w'].r do
|
|
22
|
-
|
|
23
|
-
xml['w'].
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
if options[:pH] and options[:pV] and options[:wrap]
|
|
23
|
+
xml['w'].drawing do
|
|
24
|
+
xml['wp'].anchor( "behindDoc" => 1 ,"distT" => 0,"distB" => 0, "distL" => 0, "distR" => 0 ,"simplePos" => 0 ,"locked" => 0, "layoutInCell" => 1, "allowOverlap" => 1, "relativeHeight" => 3) do
|
|
25
|
+
xml['wp'].simplePos('x'=> 0 , 'y' => 0 )
|
|
26
|
+
xml['wp'].positionH("relativeFrom" => "column") do
|
|
27
|
+
xml['wp'].posOffset options[:pH]
|
|
28
|
+
end
|
|
29
|
+
xml['wp'].positionV("relativeFrom" => "paragraph") do
|
|
30
|
+
xml['wp'].posOffset options[:pV]
|
|
31
|
+
end
|
|
32
|
+
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]
|
|
33
|
+
xml['wp'].effectExtent( 'l' => 0, 't' => 0, 'r' => 0, 'b' => 0 )
|
|
34
|
+
xml['wp'].wrapNone
|
|
35
|
+
xml['wp'].docPr( 'id' => 1, 'name'=> "Image", 'descr' => "image")
|
|
36
|
+
xml['wp'].cNvGraphicFramePr do
|
|
37
|
+
xml.graphicFrameLocks( 'xmlns:a' => "http://schemas.openxmlformats.org/drawingml/2006/main", 'noChangeAspect' => "1" ) do
|
|
38
|
+
xml.parent.namespace = xml.parent.namespace_definitions.find{|ns| ns.prefix == "a" }
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
xml.graphic( 'xmlns:a' => "http://schemas.openxmlformats.org/drawingml/2006/main" ) do
|
|
42
|
+
xml.parent.namespace = xml.parent.namespace_definitions.find{|ns| ns.prefix == "a" }
|
|
43
|
+
xml['a'].graphicData( 'uri' => "http://schemas.openxmlformats.org/drawingml/2006/picture") do
|
|
44
|
+
xml.pic( 'xmlns:pic' => "http://schemas.openxmlformats.org/drawingml/2006/picture") do
|
|
45
|
+
xml.parent.namespace = xml.parent.namespace_definitions.find{|ns| ns.prefix == "pic" }
|
|
46
|
+
xml['pic'].nvPicPr do
|
|
47
|
+
xml['pic'].cNvPr( 'id' => 0, 'name' => "Image" )
|
|
48
|
+
xml['pic'].cNvPicPr do
|
|
49
|
+
xml['a'].picLocks( 'noChangeAspect' => "1", 'noChangeArrowheads' => "1" )
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
xml['pic'].blipFill do
|
|
53
|
+
xml['a'].blip( 'r:embed' => @media.sequence )
|
|
54
|
+
xml['a'].stretch do
|
|
55
|
+
xml['a'].fillRect
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
xml['pic'].spPr( 'bwMode' => "auto" ) do
|
|
59
|
+
xml['a'].xfrm do
|
|
60
|
+
xml['a'].off( 'x' => 0, 'y' => 0 )
|
|
61
|
+
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]
|
|
62
|
+
end
|
|
63
|
+
xml['a'].prstGeom( 'prst' => "rect" ) do
|
|
64
|
+
xml['a'].avLst
|
|
65
|
+
end
|
|
66
|
+
xml['a'].noFill
|
|
67
|
+
xml['a'].ln('w' => "9525") do
|
|
68
|
+
xml['a'].noFill
|
|
69
|
+
xml['a'].miter('lim'=>"800000")
|
|
70
|
+
xml['a'].headEnd
|
|
71
|
+
xml['a'].tailEnd
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
else
|
|
80
|
+
xml['w'].pict do
|
|
81
|
+
unless options[:fill_color]
|
|
82
|
+
xml['v'].rect( 'id' => @media.uniq_id, 'type' => @media.type, 'style' => styles, :stroked => "f" ) do
|
|
83
|
+
xml['v'].imagedata( 'r:id' => @media.sequence, 'o:title' => @options[:title] )
|
|
84
|
+
xml['v'].wrap('v:type' => 'none') if options[:wrap]
|
|
85
|
+
end
|
|
86
|
+
else
|
|
87
|
+
xml['v'].rect("fillcolor"=> options[:fill_color], 'id' => @media.uniq_id, 'type' => @media.type, 'style' => styles, :stroked => "f" ) do
|
|
88
|
+
if options[:opacity].present?
|
|
89
|
+
xml['v'].fill("opacity" => options[:opacity])
|
|
90
|
+
end
|
|
91
|
+
xml['v'].imagedata( 'r:id' => @media.sequence, 'o:title' => @options[:title] )
|
|
92
|
+
xml['v'].wrap('v:type' => 'none') if options[:wrap]
|
|
93
|
+
end
|
|
94
|
+
end
|
|
28
95
|
end
|
|
29
|
-
end
|
|
30
|
-
xml['w'].rPr do
|
|
31
|
-
xml['w'].noProof
|
|
32
96
|
end
|
|
33
97
|
end
|
|
34
98
|
end
|
|
@@ -4,10 +4,11 @@ module Docxi
|
|
|
4
4
|
|
|
5
5
|
class Paragraph
|
|
6
6
|
|
|
7
|
-
attr_accessor :content, :options
|
|
7
|
+
attr_accessor :content, :options, :relationships, :id
|
|
8
8
|
def initialize(options={})
|
|
9
9
|
@content = []
|
|
10
10
|
@options = options
|
|
11
|
+
@relationships = []
|
|
11
12
|
|
|
12
13
|
if block_given?
|
|
13
14
|
yield self
|
|
@@ -16,16 +17,70 @@ module Docxi
|
|
|
16
17
|
end
|
|
17
18
|
end
|
|
18
19
|
|
|
20
|
+
def content_type
|
|
21
|
+
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def target
|
|
25
|
+
"document.xml"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def hyperlink(text,link,id)
|
|
30
|
+
text = Hyperlink.new(text, link, id)
|
|
31
|
+
@content << text
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
class Hyperlink
|
|
35
|
+
attr_accessor :text, :link, :id
|
|
36
|
+
def initialize(text, link, id )
|
|
37
|
+
@text = text
|
|
38
|
+
@link = link
|
|
39
|
+
@id = id
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def content_type
|
|
43
|
+
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def render(xml)
|
|
47
|
+
xml['w'].pPr do
|
|
48
|
+
xml['w'].pStyle('w:val' => "Normal")
|
|
49
|
+
xml['w'].rPr do
|
|
50
|
+
xml['w'].rStyle('w:val' => "InternetLink")
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
xml['w'].hyperlink('r:id' => @id) do
|
|
54
|
+
xml['w'].r do
|
|
55
|
+
xml['w'].rPr do
|
|
56
|
+
xml['w'].rStyle( 'w:val' => "InternetLink")
|
|
57
|
+
end
|
|
58
|
+
xml['w'].t @text
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
19
64
|
def render(xml)
|
|
20
65
|
xml['w'].p do
|
|
21
66
|
xml['w'].pPr do
|
|
22
67
|
xml['w'].jc( 'w:val' => @options[:align]) if @options[:align]
|
|
68
|
+
xml['w'].shd( 'w:val' => 'clear','w:fill' => @options[:fill] ) if @options[:fill]
|
|
69
|
+
xml['w'].ind( 'w:left' => @options[:left], 'w:right' => @options[:right] ) if @options[:left] and @options[:right]
|
|
23
70
|
if options[:ul]
|
|
24
71
|
xml['w'].numPr do
|
|
25
72
|
xml['w'].ilvl( 'w:val' => 0 )
|
|
26
73
|
xml['w'].numId( 'w:val' => 1 )
|
|
27
74
|
end
|
|
28
75
|
end
|
|
76
|
+
if options[:bottom]
|
|
77
|
+
xml['w'].pBdr do
|
|
78
|
+
xml['w'].top( 'w:val' => "nil")
|
|
79
|
+
xml['w'].left('w:val' => "nil")
|
|
80
|
+
xml['w'].bottom('w:val'=>"single", 'w:sz'=>"4", 'w:space'=>"1", 'w:color'=>"000000")
|
|
81
|
+
xml['w'].right('w:val'=>"nil")
|
|
82
|
+
end
|
|
83
|
+
end
|
|
29
84
|
end
|
|
30
85
|
@content.each do |element|
|
|
31
86
|
element.render(xml)
|
|
@@ -40,12 +95,24 @@ module Docxi
|
|
|
40
95
|
text
|
|
41
96
|
end
|
|
42
97
|
|
|
98
|
+
def frame(options={}, &block)
|
|
99
|
+
element = Docxi::Word::Contents::Frame.new(options, &block)
|
|
100
|
+
@content << element
|
|
101
|
+
element
|
|
102
|
+
end
|
|
103
|
+
|
|
43
104
|
def br(options={})
|
|
44
105
|
br = Docxi::Word::Contents::Break.new(options)
|
|
45
106
|
@content << br
|
|
46
107
|
br
|
|
47
108
|
end
|
|
48
109
|
|
|
110
|
+
def tab(options={})
|
|
111
|
+
tab = Docxi::Word::Contents::Tab.new(options)
|
|
112
|
+
@content << tab
|
|
113
|
+
tab
|
|
114
|
+
end
|
|
115
|
+
|
|
49
116
|
def image(image, options={})
|
|
50
117
|
img = Docxi::Word::Contents::Image.new(image, options)
|
|
51
118
|
@content << img
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Docxi
|
|
2
|
+
module Word
|
|
3
|
+
module Contents
|
|
4
|
+
|
|
5
|
+
class Tab
|
|
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'].tab
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
else
|
|
21
|
+
@options[:times].times do
|
|
22
|
+
xml['w'].r do
|
|
23
|
+
xml['w'].tab
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -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 options[:height].present?
|
|
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 options[:fill].blank?
|
|
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/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,10 +108,22 @@ 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
128
|
zip.put_next_entry('word/document.xml')
|
|
91
129
|
zip.write(Docxi.to_xml(document))
|
|
@@ -108,7 +146,7 @@ module Docxi
|
|
|
108
146
|
private
|
|
109
147
|
def document
|
|
110
148
|
Nokogiri::XML::Builder.with(Nokogiri::XML('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>')) do |xml|
|
|
111
|
-
xml.document('xmlns:
|
|
149
|
+
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
150
|
xml.parent.namespace = xml.parent.namespace_definitions.find{|ns| ns.prefix == "w" }
|
|
113
151
|
|
|
114
152
|
xml['w'].body do
|
|
@@ -122,11 +160,13 @@ module Docxi
|
|
|
122
160
|
xml['w'].bookmarkEnd('w:id' => "0")
|
|
123
161
|
end
|
|
124
162
|
xml['w'].sectPr do
|
|
125
|
-
xml['w'].footerReference( 'w:type' => "default", 'r:id' => @footer.sequence ) if @footer
|
|
126
163
|
xml['w'].headerReference( 'w:type' => "default", 'r:id' => @header.sequence ) if @header
|
|
164
|
+
xml['w'].headerReference( 'w:type' => "first", 'r:id' => @first_header.sequence ) if @first_header
|
|
165
|
+
xml['w'].footerReference( 'w:type' => "default", 'r:id' => @footer.sequence ) if @footer
|
|
166
|
+
xml['w'].footerReference( 'w:type' => "first", 'r:id' => @first_footer.sequence ) if @first_footer
|
|
127
167
|
xml['w'].titlePg
|
|
128
168
|
xml['w'].pgSz( 'w:w' => 12240, 'w:h' => 15840 )
|
|
129
|
-
xml['w'].pgMar( 'w:top' =>
|
|
169
|
+
xml['w'].pgMar( 'w:top' => @options[:top], 'w:right' => @options[:right], 'w:bottom' => @options[:bottom], 'w:left' => @options[:left], 'w:header' => @options[:header].present? ? @options[:header] : 190, 'w:footer' => @options[:footer].present? ? @options[:footer] : 200 , 'w:gutter' => 0)
|
|
130
170
|
xml['w'].cols( 'w:space' => 720)
|
|
131
171
|
xml['w'].docGrid( 'w:linePitch' => "360")
|
|
132
172
|
end
|
|
@@ -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
|
|
@@ -45,12 +51,18 @@ module Docxi
|
|
|
45
51
|
element
|
|
46
52
|
end
|
|
47
53
|
|
|
48
|
-
def page_numbers
|
|
49
|
-
numbers = PageNumbers.new
|
|
54
|
+
def page_numbers(options={})
|
|
55
|
+
numbers = PageNumbers.new(options)
|
|
50
56
|
@content << numbers
|
|
51
57
|
numbers
|
|
52
58
|
end
|
|
53
59
|
|
|
60
|
+
def table(options={}, &block)
|
|
61
|
+
table = Docxi::Word::Contents::Table.new(options, &block)
|
|
62
|
+
@content << table
|
|
63
|
+
table
|
|
64
|
+
end
|
|
65
|
+
|
|
54
66
|
class PageNumbers
|
|
55
67
|
|
|
56
68
|
attr_accessor :options
|
|
@@ -72,6 +84,14 @@ module Docxi
|
|
|
72
84
|
xml['w'].pPr do
|
|
73
85
|
xml['w'].jc( 'w:val' => @options[:align] || 'right' )
|
|
74
86
|
end
|
|
87
|
+
xml['w'].r do
|
|
88
|
+
xml['w'].rPr do
|
|
89
|
+
xml['w'].rFonts( 'w:cs'=> 'Arial', 'w:ascii'=> 'Arial', 'w:hAnsi' => 'Arial' )
|
|
90
|
+
xml['w'].color( 'w:val' => '404040')
|
|
91
|
+
xml['w'].sz( 'w:val' => '20' )
|
|
92
|
+
end
|
|
93
|
+
xml['w'].t @options[:name].to_s+' '
|
|
94
|
+
end
|
|
75
95
|
xml['w'].r do
|
|
76
96
|
xml['w'].fldChar( 'w:fldCharType' => "begin" )
|
|
77
97
|
end
|
|
@@ -43,11 +43,38 @@ module Docxi
|
|
|
43
43
|
img
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
+
def text(text, options={})
|
|
47
|
+
options = @options.merge(options)
|
|
48
|
+
element = Docxi::Word::Contents::Paragraph.new(options) do |p|
|
|
49
|
+
p.text(text)
|
|
50
|
+
end
|
|
51
|
+
@content << element
|
|
52
|
+
element
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def page_numbers
|
|
56
|
+
numbers = PageNumbers.new
|
|
57
|
+
@content << numbers
|
|
58
|
+
numbers
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def br(options={})
|
|
62
|
+
br = Docxi::Word::Contents::Break.new(options)
|
|
63
|
+
@content << br
|
|
64
|
+
br
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def table(options={}, &block)
|
|
68
|
+
table = Docxi::Word::Contents::Table.new(options, &block)
|
|
69
|
+
@content << table
|
|
70
|
+
table
|
|
71
|
+
end
|
|
72
|
+
|
|
46
73
|
class Image
|
|
47
74
|
attr_accessor :media, :options
|
|
48
75
|
def initialize(media, options={})
|
|
49
76
|
@media = media
|
|
50
|
-
@media.file.rewind
|
|
77
|
+
# @media.file.rewind
|
|
51
78
|
@options = options
|
|
52
79
|
end
|
|
53
80
|
|
|
@@ -69,23 +96,35 @@ module Docxi
|
|
|
69
96
|
xml['w'].noProof
|
|
70
97
|
end
|
|
71
98
|
xml['w'].drawing do
|
|
72
|
-
xml['wp'].
|
|
73
|
-
xml['wp'].
|
|
74
|
-
xml['wp'].
|
|
99
|
+
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
|
|
100
|
+
xml['wp'].simplePos('x'=> 0 , 'y' => 0 )
|
|
101
|
+
xml['wp'].positionH("relativeFrom" => "column") do
|
|
102
|
+
xml['wp'].posOffset options[:pH]
|
|
103
|
+
end
|
|
104
|
+
xml['wp'].positionV("relativeFrom" => "paragraph") do
|
|
105
|
+
xml['wp'].posOffset options[:pV]
|
|
106
|
+
end
|
|
107
|
+
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]
|
|
108
|
+
xml['wp'].effectExtent( 'l' => 0, 't' => 0, 'r' => 0, 'b' => 0 )
|
|
109
|
+
if options[:wrap] == "none"
|
|
110
|
+
xml['wp'].wrapNone
|
|
111
|
+
else
|
|
112
|
+
xml['wp'].wrapSquare("wrapText"=> "bothSides")
|
|
113
|
+
end
|
|
75
114
|
xml['wp'].docPr( 'id' => 1, 'name'=> "Image", 'descr' => "image")
|
|
76
115
|
xml['wp'].cNvGraphicFramePr do
|
|
77
|
-
xml.graphicFrameLocks( 'xmlns:a' => "http://schemas.openxmlformats.org/drawingml/2006/main", 'noChangeAspect' => 1 ) do
|
|
116
|
+
xml.graphicFrameLocks( 'xmlns:a' => "http://schemas.openxmlformats.org/drawingml/2006/main", 'noChangeAspect' => "1" ) do
|
|
78
117
|
xml.parent.namespace = xml.parent.namespace_definitions.find{|ns| ns.prefix == "a" }
|
|
79
118
|
end
|
|
80
119
|
end
|
|
81
120
|
xml.graphic( 'xmlns:a' => "http://schemas.openxmlformats.org/drawingml/2006/main" ) do
|
|
82
121
|
xml.parent.namespace = xml.parent.namespace_definitions.find{|ns| ns.prefix == "a" }
|
|
83
122
|
xml['a'].graphicData( 'uri' => "http://schemas.openxmlformats.org/drawingml/2006/picture") do
|
|
84
|
-
xml.pic( 'xmlns:pic' => "http://schemas.openxmlformats.org/drawingml/2006/picture"
|
|
123
|
+
xml.pic( 'xmlns:pic' => "http://schemas.openxmlformats.org/drawingml/2006/picture") do
|
|
85
124
|
xml.parent.namespace = xml.parent.namespace_definitions.find{|ns| ns.prefix == "pic" }
|
|
86
125
|
xml['pic'].nvPicPr do
|
|
87
126
|
xml['pic'].cNvPr( 'id' => 0, 'name' => "Image" )
|
|
88
|
-
xml['pic'].cNvPicPr
|
|
127
|
+
xml['pic'].cNvPicPr
|
|
89
128
|
end
|
|
90
129
|
xml['pic'].blipFill do
|
|
91
130
|
xml['a'].blip( 'r:embed' => @media.sequence ) do
|
|
@@ -95,14 +134,21 @@ module Docxi
|
|
|
95
134
|
xml['a'].fillRect
|
|
96
135
|
end
|
|
97
136
|
end
|
|
98
|
-
xml['pic'].spPr do
|
|
137
|
+
xml['pic'].spPr( 'bwMode' => "auto" ) do
|
|
99
138
|
xml['a'].xfrm do
|
|
100
139
|
xml['a'].off( 'x' => 0, 'y' => 0 )
|
|
101
|
-
xml['a'].ext( 'cx' => ( width *
|
|
140
|
+
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
141
|
end
|
|
103
142
|
xml['a'].prstGeom( 'prst' => "rect" ) do
|
|
104
143
|
xml['a'].avLst
|
|
105
144
|
end
|
|
145
|
+
# xml['a'].noFill
|
|
146
|
+
# xml['a'].ln('w' => "9525") do
|
|
147
|
+
# xml['a'].noFill
|
|
148
|
+
# xml['a'].miter('lim'=>"800000")
|
|
149
|
+
# xml['a'].headEnd
|
|
150
|
+
# xml['a'].tailEnd
|
|
151
|
+
# end
|
|
106
152
|
end
|
|
107
153
|
end
|
|
108
154
|
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 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,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
|
|
@@ -0,0 +1,96 @@
|
|
|
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
|
+
zip.put_next_entry("word/#{target}")
|
|
35
|
+
zip.write(Docxi.to_xml(document))
|
|
36
|
+
if !@relationships.empty?
|
|
37
|
+
zip.put_next_entry("word/_rels/#{target}.rels")
|
|
38
|
+
zip.write(Docxi.to_xml(relationships))
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def hyperlink(text,link)
|
|
43
|
+
text = Hyperlink.new(text, link, id)
|
|
44
|
+
@content << text
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
class Hyperlink
|
|
48
|
+
attr_accessor :text, :link
|
|
49
|
+
def initialize(text, link )
|
|
50
|
+
@text = text
|
|
51
|
+
@link = link
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def content_type
|
|
55
|
+
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def render(xml)
|
|
59
|
+
xml['w'].hyperlink('w:id' => '1') do
|
|
60
|
+
xml['w'].r do
|
|
61
|
+
xml['w'].pPr do
|
|
62
|
+
xml['w'].rStyle( 'w:val' => "InternetLink")
|
|
63
|
+
end
|
|
64
|
+
xml['w'].t @text
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
private
|
|
72
|
+
def document
|
|
73
|
+
Nokogiri::XML::Builder.with(Nokogiri::XML('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>')) do |xml|
|
|
74
|
+
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
|
|
75
|
+
xml.parent.namespace = xml.parent.namespace_definitions.find{|ns| ns.prefix == "w" }
|
|
76
|
+
@content.each do |element|
|
|
77
|
+
element.render(xml)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def relationships
|
|
84
|
+
Nokogiri::XML::Builder.with(Nokogiri::XML('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>')) do |xml|
|
|
85
|
+
xml.Relationships(xmlns: 'http://schemas.openxmlformats.org/package/2006/relationships') do
|
|
86
|
+
@relationships.each do |relationship|
|
|
87
|
+
xml.Relationship('Id' => relationship.sequence, 'Type' => relationship.content_type, 'Target' => relationship.target)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
data/lib/docxi/word/medias.rb
CHANGED
|
@@ -22,7 +22,13 @@ module Docxi
|
|
|
22
22
|
def render(zip)
|
|
23
23
|
@medias.each do |media|
|
|
24
24
|
zip.put_next_entry("word/#{media.target}")
|
|
25
|
-
|
|
25
|
+
if media.file.class == String
|
|
26
|
+
file = open(media.file)
|
|
27
|
+
zip.write(file.read)
|
|
28
|
+
file.close
|
|
29
|
+
else
|
|
30
|
+
zip.write(media.file.read)
|
|
31
|
+
end
|
|
26
32
|
end
|
|
27
33
|
end
|
|
28
34
|
|
|
@@ -21,8 +21,8 @@ module Docxi
|
|
|
21
21
|
add("http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering", "numbering.xml")
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
def add(type, target)
|
|
25
|
-
relationship = create_relationship(sequence, type, target)
|
|
24
|
+
def add(type, target, tm = '')
|
|
25
|
+
relationship = create_relationship(sequence, type, target,tm)
|
|
26
26
|
@relationships << relationship if relationship
|
|
27
27
|
relationship
|
|
28
28
|
end
|
|
@@ -43,8 +43,8 @@ module Docxi
|
|
|
43
43
|
end
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
-
def create_relationship(id, type, target)
|
|
47
|
-
Relationship.new(id, type, target)
|
|
46
|
+
def create_relationship(id, type, target, tm = '')
|
|
47
|
+
Relationship.new(id, type, target, tm)
|
|
48
48
|
end
|
|
49
49
|
|
|
50
50
|
def sequence
|
|
@@ -3,16 +3,21 @@ module Docxi
|
|
|
3
3
|
class Relationships
|
|
4
4
|
class Relationship
|
|
5
5
|
|
|
6
|
-
attr_accessor :id, :type, :target
|
|
6
|
+
attr_accessor :id, :type, :target, :tm
|
|
7
7
|
|
|
8
|
-
def initialize(id, type, target)
|
|
8
|
+
def initialize(id, type, target, tm = '')
|
|
9
9
|
@id = id
|
|
10
10
|
@type = type
|
|
11
11
|
@target = target
|
|
12
|
+
@tm = tm
|
|
12
13
|
end
|
|
13
14
|
|
|
14
15
|
def build(xml)
|
|
15
|
-
|
|
16
|
+
if @tm.blank?
|
|
17
|
+
xml.Relationship('Id' => @id, 'Type' => @type, 'Target' => @target)
|
|
18
|
+
else
|
|
19
|
+
xml.Relationship('Id' => @id, 'Type' => @type, 'Target' => @target, 'TargetMode' => @tm)
|
|
20
|
+
end
|
|
16
21
|
end
|
|
17
22
|
|
|
18
23
|
end
|
data/lib/docxi/word/styles.rb
CHANGED
|
@@ -20,15 +20,16 @@ module Docxi
|
|
|
20
20
|
xml['w'].docDefaults do
|
|
21
21
|
xml['w'].rPrDefault do
|
|
22
22
|
xml['w'].rPr do
|
|
23
|
-
xml['w'].rFonts('w:asciiTheme' => "minorHAnsi", 'w:eastAsiaTheme' => "minorHAnsi", 'w:hAnsiTheme' => "minorHAnsi", 'w:cstheme' => "minorBidi")
|
|
24
|
-
xml['w'].
|
|
25
|
-
xml['w'].
|
|
23
|
+
# xml['w'].rFonts('w:asciiTheme' => "minorHAnsi", 'w:eastAsiaTheme' => "minorHAnsi", 'w:hAnsiTheme' => "minorHAnsi", 'w:cstheme' => "minorBidi")
|
|
24
|
+
xml['w'].rFonts( 'w:cs'=> 'Arial', 'w:ascii'=> 'Arial', 'w:hAnsi' => 'Arial' )
|
|
25
|
+
xml['w'].sz('w:val' => 24)
|
|
26
|
+
xml['w'].szCs('w:val' => 24)
|
|
26
27
|
xml['w'].lang('w:val' => "en-US", 'w:eastAsia' => "en-US", 'w:bidi' => "ar-SA")
|
|
27
28
|
end
|
|
28
29
|
end
|
|
29
30
|
xml['w'].pPrDefault do
|
|
30
31
|
xml['w'].pPr do
|
|
31
|
-
xml['w'].spacing(
|
|
32
|
+
xml['w'].spacing("w:lineRule"=>"atLeast", "w:line"=>"240")
|
|
32
33
|
end
|
|
33
34
|
end
|
|
34
35
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: docxi
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Irfan Babar
|
|
@@ -67,8 +67,10 @@ files:
|
|
|
67
67
|
- lib/docxi/word.rb
|
|
68
68
|
- lib/docxi/word/contents.rb
|
|
69
69
|
- lib/docxi/word/contents/break.rb
|
|
70
|
+
- lib/docxi/word/contents/frame.rb
|
|
70
71
|
- lib/docxi/word/contents/image.rb
|
|
71
72
|
- lib/docxi/word/contents/paragraph.rb
|
|
73
|
+
- lib/docxi/word/contents/tab.rb
|
|
72
74
|
- lib/docxi/word/contents/table.rb
|
|
73
75
|
- lib/docxi/word/contents/table_of_content.rb
|
|
74
76
|
- lib/docxi/word/contents/text.rb
|
|
@@ -83,6 +85,8 @@ files:
|
|
|
83
85
|
- lib/docxi/word/headers.rb
|
|
84
86
|
- lib/docxi/word/headers/header.rb
|
|
85
87
|
- lib/docxi/word/helpers.rb
|
|
88
|
+
- lib/docxi/word/hyperlinks.rb
|
|
89
|
+
- lib/docxi/word/hyperlinks/hyperlink.rb
|
|
86
90
|
- lib/docxi/word/medias.rb
|
|
87
91
|
- lib/docxi/word/medias/media.rb
|
|
88
92
|
- lib/docxi/word/numbering.rb
|