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
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 92d0e49fe9e1a189dc7d1cb7dccb3c7e7a3f4877f4b4c56f5cfb2cc779a944de
|
|
4
|
+
data.tar.gz: 8a0192d020e0471216c6224de46478a7b2ac4a71a04c4a05569f6774ae3c0b76
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1060898ce0f6fe2a1122a98cce52b2220460c96969ea78ebeb576e32f20fadefed3b8b6bd741c623cdc9ae0d4721189fa649ef7e0d04fbf5767852001ac0392f
|
|
7
|
+
data.tar.gz: 266f7794a16fbad300b520f5d49bf70e6fd15407143e8a3bc54f6b8fff91a32ed7358a498a76ddaca98be92df6a87310c55612da45c5ece198130ad64e9fe63f
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 (unreleased)
|
|
4
|
+
|
|
5
|
+
docxi installs and runs again in current apps, with or without Rails. No code changes are needed, and the generated documents are the same as 0.0.6's (the tests compare them against 0.0.6's output).
|
|
6
|
+
|
|
7
|
+
### Compatibility
|
|
8
|
+
|
|
9
|
+
- Requires Ruby 2.5 or newer. Apps on older Rubies stay on 0.0.6.
|
|
10
|
+
- Works with or without Rails, and is tested alongside Rails 5.2 through 8.1.
|
|
11
|
+
- nokogiri `>= 1.8, < 2` instead of `>= 1.6.3, < 1.7`, which conflicted with every Rails version since 6.0.
|
|
12
|
+
- rubyzip `>= 1.3, < 4` instead of `~> 0.9.9`.
|
|
13
|
+
- No longer calls ActiveSupport's `blank?` and `present?`, which only worked when Rails had loaded them.
|
|
14
|
+
|
|
15
|
+
### Fixes
|
|
16
|
+
|
|
17
|
+
- Documents written with rubyzip 3 no longer contain Zip64 records, which Google Docs and older LibreOffice versions reject.
|
|
18
|
+
- `add_media` with an image URL works on Ruby 3 again.
|
|
19
|
+
- `add_media` no longer runs a string that starts with `|` as a shell command.
|
|
20
|
+
- `tab` and `frame` no longer raise `NameError`.
|
|
21
|
+
- `document.frame("text")` no longer raises `TypeError`.
|
|
22
|
+
- `page_numbers` in a header no longer raises `NameError`.
|
|
23
|
+
|
|
24
|
+
### Gem
|
|
25
|
+
|
|
26
|
+
- New maintainer, homepage and changelog links.
|
|
27
|
+
- Releases require MFA.
|
|
28
|
+
|
|
29
|
+
## 0.0.6 (2016-10-18)
|
|
30
|
+
|
|
31
|
+
Last release before the 0.1.0 update.
|
data/README.md
CHANGED
|
@@ -11,11 +11,36 @@ 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
|
+
## NOTE
|
|
15
|
+
Use Latest version of Gem. Old Version has bugs.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```ruby
|
|
20
|
+
gem "docxi", "~> 0.1"
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Supported versions
|
|
24
|
+
|
|
25
|
+
| Dependency | Supported versions |
|
|
26
|
+
|---|---|
|
|
27
|
+
| Ruby | 2.5 or newer |
|
|
28
|
+
| Rails | Not required. Tested alongside Rails 5.2, 6.0, 6.1, 7.0, 7.1, 7.2, 8.0 and 8.1 |
|
|
29
|
+
| nokogiri | 1.8 or newer |
|
|
30
|
+
| rubyzip | 1.3 or newer, including 3.x |
|
|
31
|
+
|
|
32
|
+
### Upgrading from 0.0.x
|
|
33
|
+
|
|
34
|
+
Run `bundle update docxi`. The API is unchanged and 0.1.0 generates the same documents as 0.0.6. Apps on a Ruby older than 2.5 stay on 0.0.6 automatically.
|
|
14
35
|
|
|
15
36
|
## Usage
|
|
16
37
|
|
|
17
38
|
```ruby
|
|
18
|
-
|
|
39
|
+
# default attributes (top: 720,right: 1440,left: 1440,bottom: 720,footer: 200, header: 190)
|
|
40
|
+
word = Docxi::Document.new
|
|
41
|
+
# or change margins
|
|
42
|
+
# word = Docxi::Document.new(top: 0,right: 0,left: 0,bottom: 0)
|
|
43
|
+
|
|
19
44
|
document = word.document
|
|
20
45
|
|
|
21
46
|
# Creates Header
|
|
@@ -39,8 +64,8 @@ end
|
|
|
39
64
|
document.add_footer(footer)
|
|
40
65
|
|
|
41
66
|
# Creates paragraph
|
|
42
|
-
document.p(size:
|
|
43
|
-
p.text "Title"
|
|
67
|
+
document.p(size: 12, bold: true, align: "center", color: "000000", fill: "AAAAAA") do |p|
|
|
68
|
+
p.text "Title", size: 12, bold: true, align: "center", color: "000000"
|
|
44
69
|
# Adds 3 break lines
|
|
45
70
|
p.br times: 3
|
|
46
71
|
end
|
|
@@ -103,17 +128,67 @@ document.table( columns_width: [ 316, 160, 135 ] ) do |table|
|
|
|
103
128
|
end
|
|
104
129
|
end
|
|
105
130
|
|
|
131
|
+
# Adds table with row height and column indentation
|
|
132
|
+
document.table( columns_width: [ 316, 160, 135 ], height: 268, iwidth: 108) do |table|
|
|
133
|
+
# Adds row with specific styles
|
|
134
|
+
table.tr(fill: "FBD4B4", bold: true, align: 'center' ) do |tr|
|
|
135
|
+
# Adds cells
|
|
136
|
+
tr.tc(borders: { top: 1, right: nil, bottom: 1, left: 1 }) do |tc|
|
|
137
|
+
tc.text "Header 1"
|
|
138
|
+
end
|
|
139
|
+
tr.tc(borders: { top: 1, right: nil, bottom: 1, left: nil }) do |tc|
|
|
140
|
+
tc.text "Header 2"
|
|
141
|
+
end
|
|
142
|
+
tr.tc(borders: { top: 1, right: 1, bottom: 1, left: nil }) do |tc|
|
|
143
|
+
tc.text "Header 3"
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
|
|
106
149
|
# Adds image
|
|
107
150
|
document.p do |p|
|
|
108
151
|
p.text "Image Example", size: 16, bold: true, italic: true, underline: true, br: true
|
|
109
152
|
|
|
110
153
|
# Adds image to container
|
|
111
154
|
media = document.add_media File.open('image.png')
|
|
155
|
+
# Or add image URL
|
|
156
|
+
# media = document.add_media image_url
|
|
112
157
|
# Insert media into paragraph
|
|
113
158
|
p.image media, style: { width: '200pt', height: '200pt' }
|
|
159
|
+
|
|
160
|
+
# Add Hyperlink
|
|
161
|
+
hyper = document.add_hyperlink("http://google.com")
|
|
162
|
+
p.hyperlink "Go to Google", "http://google.com", hyper
|
|
163
|
+
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Add Underline
|
|
167
|
+
document.p(bottom: true) do |p|
|
|
168
|
+
p.text "Example text"
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Set position of Paragraph
|
|
172
|
+
document.p(fill: "d7d7d7",align: "center", right: -1000, left: -1000) do |p|
|
|
173
|
+
p.text "Example Text 2"
|
|
174
|
+
p.br
|
|
114
175
|
end
|
|
115
176
|
|
|
116
177
|
# Creates Word Document
|
|
117
178
|
io = word.render
|
|
118
179
|
File.open('doc_1.docx', 'wb'){|f| f.write(io.string) }
|
|
119
|
-
```
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Development
|
|
183
|
+
|
|
184
|
+
```sh
|
|
185
|
+
bundle install
|
|
186
|
+
bundle exec rake test # run the tests
|
|
187
|
+
bundle exec rake samples # write tmp/samples/*.docx to open in Word, LibreOffice or Google Docs
|
|
188
|
+
|
|
189
|
+
# run the tests with a specific Rails version loaded
|
|
190
|
+
BUNDLE_GEMFILE=gemfiles/rails_8.1.gemfile bundle install
|
|
191
|
+
BUNDLE_GEMFILE=gemfiles/rails_8.1.gemfile DOCXI_WITH_RAILS=1 bundle exec rake test
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
`test/golden` holds the XML that 0.0.6 generated for the sample documents in `test/support/sample_documents.rb`, and the tests check every release against it. After an intentional change to the generated XML, update it with `bundle exec rake golden` and review the diff.
|
data/Rakefile
CHANGED
|
@@ -4,6 +4,34 @@ require 'rake/testtask'
|
|
|
4
4
|
|
|
5
5
|
Rake::TestTask.new do |t|
|
|
6
6
|
t.libs << 'test'
|
|
7
|
+
t.pattern = 'test/**/test_*.rb'
|
|
8
|
+
t.warning = false
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
desc 'Rewrite test/golden from the current code (only after an intentional output change)'
|
|
12
|
+
task :golden do
|
|
13
|
+
$LOAD_PATH.unshift File.expand_path('lib', __dir__)
|
|
14
|
+
require 'docxi'
|
|
15
|
+
require_relative 'test/support/package'
|
|
16
|
+
require_relative 'test/support/sample_documents'
|
|
17
|
+
|
|
18
|
+
SampleDocuments.all.each do |name, word|
|
|
19
|
+
Package.write_golden(File.join(__dir__, 'test', 'golden', name), word.render.string)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
desc 'Write the sample documents to tmp/samples for opening in Word, LibreOffice or Google Docs'
|
|
24
|
+
task :samples do
|
|
25
|
+
$LOAD_PATH.unshift File.expand_path('lib', __dir__)
|
|
26
|
+
require 'docxi'
|
|
27
|
+
require 'fileutils'
|
|
28
|
+
require_relative 'test/support/sample_documents'
|
|
29
|
+
|
|
30
|
+
FileUtils.mkdir_p('tmp/samples')
|
|
31
|
+
SampleDocuments.all.each do |name, word|
|
|
32
|
+
File.binwrite("tmp/samples/#{name}.docx", word.render.string)
|
|
33
|
+
puts "tmp/samples/#{name}.docx"
|
|
34
|
+
end
|
|
7
35
|
end
|
|
8
36
|
|
|
9
37
|
desc "Run tests"
|
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)
|
|
@@ -34,8 +39,7 @@ module Docxi
|
|
|
34
39
|
end
|
|
35
40
|
|
|
36
41
|
def render(zip)
|
|
37
|
-
|
|
38
|
-
zip.write(Docxi.to_xml(document))
|
|
42
|
+
Docxi.write_entry(zip, '[Content_Types].xml', Docxi.to_xml(document))
|
|
39
43
|
end
|
|
40
44
|
|
|
41
45
|
private
|
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,11 +20,11 @@ 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
|
|
27
|
-
Zip::
|
|
27
|
+
Zip::OutputStream.write_buffer do |zip|
|
|
28
28
|
document.render(zip)
|
|
29
29
|
properties.render(zip)
|
|
30
30
|
relationships.render(zip)
|
data/lib/docxi/properties.rb
CHANGED
|
@@ -18,11 +18,9 @@ module Docxi
|
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def render(zip)
|
|
21
|
-
|
|
22
|
-
zip.write(Docxi.to_xml(app.document))
|
|
21
|
+
Docxi.write_entry(zip, 'docProps/app.xml', Docxi.to_xml(app.document))
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
zip.write(Docxi.to_xml(core.document))
|
|
23
|
+
Docxi.write_entry(zip, 'docProps/core.xml', Docxi.to_xml(core.document))
|
|
26
24
|
end
|
|
27
25
|
|
|
28
26
|
end
|
data/lib/docxi/relationships.rb
CHANGED
data/lib/docxi/util.rb
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Docxi
|
|
2
|
+
module Util
|
|
3
|
+
|
|
4
|
+
# Same rules as ActiveSupport's Object#blank?, which older versions of this
|
|
5
|
+
# gem called without depending on ActiveSupport.
|
|
6
|
+
def self.blank?(value)
|
|
7
|
+
case value
|
|
8
|
+
when nil, false then true
|
|
9
|
+
when String then /\A[[:space:]]*\z/ === value
|
|
10
|
+
else value.respond_to?(:empty?) ? !!value.empty? : false
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.present?(value)
|
|
15
|
+
!blank?(value)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
end
|
|
19
|
+
end
|
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 Docxi::Util.present?(options[:opacity])
|
|
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
|