axlsx 1.1.7 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.yardopts +5 -2
- data/CHANGELOG.md +39 -0
- data/README.md +84 -46
- data/Rakefile +3 -2
- data/examples/basic_charts.rb +8 -0
- data/examples/chart_colors.rb +18 -3
- data/examples/example.rb +106 -46
- data/examples/example.xlsx +0 -0
- data/examples/example_streamed.xlsx +0 -0
- data/examples/extractive.pdf +0 -0
- data/examples/no-use_autowidth.xlsx +0 -0
- data/examples/scraping_html.rb +91 -0
- data/examples/shared_strings_example.xlsx +0 -0
- data/lib/axlsx/content_type/content_type.rb +2 -0
- data/lib/axlsx/content_type/default.rb +21 -12
- data/lib/axlsx/content_type/override.rb +22 -11
- data/lib/axlsx/doc_props/app.rb +36 -32
- data/lib/axlsx/doc_props/core.rb +9 -5
- data/lib/axlsx/drawing/ax_data_source.rb +7 -6
- data/lib/axlsx/drawing/axis.rb +48 -27
- data/lib/axlsx/drawing/bar_3D_chart.rb +49 -45
- data/lib/axlsx/drawing/bar_series.rb +1 -0
- data/lib/axlsx/drawing/cat_axis.rb +42 -38
- data/lib/axlsx/drawing/chart.rb +63 -52
- data/lib/axlsx/drawing/d_lbls.rb +100 -0
- data/lib/axlsx/drawing/drawing.rb +7 -4
- data/lib/axlsx/drawing/line_3D_chart.rb +3 -10
- data/lib/axlsx/drawing/num_data_source.rb +1 -1
- data/lib/axlsx/drawing/pie_3D_chart.rb +10 -7
- data/lib/axlsx/drawing/scatter_chart.rb +2 -8
- data/lib/axlsx/drawing/two_cell_anchor.rb +41 -9
- data/lib/axlsx/drawing/view_3D.rb +41 -31
- data/lib/axlsx/drawing/vml_drawing.rb +1 -1
- data/lib/axlsx/package.rb +11 -11
- data/lib/axlsx/rels/relationship.rb +3 -3
- data/lib/axlsx/stylesheet/styles.rb +1 -1
- data/lib/axlsx/util/constants.rb +4 -0
- data/lib/axlsx/util/simple_typed_list.rb +15 -8
- data/lib/axlsx/util/validators.rb +2 -2
- data/lib/axlsx/version.rb +2 -7
- data/lib/axlsx/workbook/defined_name.rb +174 -0
- data/lib/axlsx/workbook/defined_names.rb +21 -0
- data/lib/axlsx/workbook/workbook.rb +39 -14
- data/lib/axlsx/workbook/worksheet/auto_filter.rb +34 -0
- data/lib/axlsx/workbook/worksheet/cell.rb +25 -2
- data/lib/axlsx/workbook/worksheet/col.rb +15 -0
- data/lib/axlsx/workbook/worksheet/cols.rb +20 -0
- data/lib/axlsx/workbook/worksheet/comments.rb +8 -0
- data/lib/axlsx/workbook/worksheet/conditional_formattings.rb +25 -0
- data/lib/axlsx/workbook/worksheet/data_bar.rb +1 -1
- data/lib/axlsx/workbook/worksheet/data_validations.rb +28 -0
- data/lib/axlsx/workbook/worksheet/dimension.rb +65 -0
- data/lib/axlsx/workbook/worksheet/merged_cells.rb +35 -0
- data/lib/axlsx/workbook/worksheet/page_setup.rb +9 -0
- data/lib/axlsx/workbook/worksheet/protected_range.rb +46 -0
- data/lib/axlsx/workbook/worksheet/protected_ranges.rb +34 -0
- data/lib/axlsx/workbook/worksheet/row.rb +1 -1
- data/lib/axlsx/workbook/worksheet/sheet_data.rb +25 -0
- data/lib/axlsx/workbook/worksheet/sheet_pr.rb +24 -0
- data/lib/axlsx/workbook/worksheet/tables.rb +31 -0
- data/lib/axlsx/workbook/worksheet/worksheet.rb +300 -293
- data/lib/axlsx/workbook/worksheet/worksheet_comments.rb +57 -0
- data/lib/axlsx/workbook/worksheet/worksheet_drawing.rb +64 -0
- data/lib/axlsx.rb +21 -14
- data/test/content_type/tc_content_type.rb +1 -6
- data/test/doc_props/tc_core.rb +1 -1
- data/test/drawing/tc_axis.rb +8 -0
- data/test/drawing/tc_bar_3D_chart.rb +12 -12
- data/test/drawing/tc_bar_series.rb +1 -2
- data/test/drawing/tc_chart.rb +8 -6
- data/test/drawing/tc_d_lbls.rb +47 -0
- data/test/drawing/tc_drawing.rb +5 -4
- data/test/drawing/tc_line_series.rb +1 -1
- data/test/drawing/tc_pie_3D_chart.rb +4 -8
- data/test/drawing/tc_pie_series.rb +1 -1
- data/test/drawing/tc_scatter_series.rb +1 -1
- data/test/drawing/tc_series.rb +1 -1
- data/test/drawing/tc_view_3D.rb +18 -18
- data/test/tc_package.rb +18 -1
- data/test/workbook/tc_defined_name.rb +41 -0
- data/test/workbook/tc_workbook.rb +5 -3
- data/test/workbook/worksheet/table/tc_table.rb +0 -8
- data/test/workbook/worksheet/tc_cell.rb +2 -4
- data/test/workbook/worksheet/tc_page_setup.rb +20 -3
- data/test/workbook/worksheet/tc_protected_range.rb +17 -0
- data/test/workbook/worksheet/tc_row.rb +2 -2
- data/test/workbook/worksheet/tc_selection.rb +1 -1
- data/test/workbook/worksheet/tc_worksheet.rb +53 -34
- metadata +93 -101
- data/examples/axis-titles.xlsx +0 -0
- data/examples/basic_charts.xlsx +0 -0
- data/examples/chart_colors.xlsx +0 -0
- data/examples/charts.xlsx +0 -0
- data/examples/conditional_formatting/getting_barred.xlsx +0 -0
- data/examples/doc/_index.html +0 -84
- data/examples/doc/class_list.html +0 -47
- data/examples/doc/css/common.css +0 -1
- data/examples/doc/css/full_list.css +0 -55
- data/examples/doc/css/style.css +0 -322
- data/examples/doc/file_list.html +0 -46
- data/examples/doc/frames.html +0 -13
- data/examples/doc/index.html +0 -84
- data/examples/doc/js/app.js +0 -205
- data/examples/doc/js/full_list.js +0 -173
- data/examples/doc/js/jquery.js +0 -16
- data/examples/doc/method_list.html +0 -46
- data/examples/doc/top-level-namespace.html +0 -95
- data/examples/examples_saved.xlsx +0 -0
- data/examples/extractive.xlsx +0 -0
- data/examples/fish.xlsx +0 -0
- data/examples/pareto.rb +0 -28
- data/examples/pareto.xlsx +0 -0
- data/examples/pie_chart_excel.xlsx +0 -0
- data/examples/pie_chart_saved.xlsx +0 -0
- data/examples/sheet_protection.xlsx +0 -0
- data/examples/sheet_view.xlsx +0 -0
- data/examples/two_cell_anchor_image.xlsx +0 -0
- data/examples/~$example.xlsx +0 -0
- data/lib/axlsx/drawing/ax_data_source.rb~ +0 -55
- data/lib/axlsx/drawing/data_source.rb~ +0 -51
- data/lib/axlsx/drawing/hlink_click.rb~ +0 -0
- data/lib/axlsx/drawing/hyperlink.rb~ +0 -64
- data/lib/axlsx/drawing/num_data.rb~ +0 -51
- data/lib/axlsx/drawing/num_data_source.rb~ +0 -54
- data/lib/axlsx/drawing/num_val.rb~ +0 -40
- data/lib/axlsx/drawing/picture_locking.rb~ +0 -36
- data/lib/axlsx/drawing/ref.rb~ +0 -41
- data/lib/axlsx/drawing/str_data.rb~ +0 -58
- data/lib/axlsx/drawing/str_val.rb~ +0 -35
- data/lib/axlsx/drawing/vml_drawing.rb~ +0 -6
- data/lib/axlsx/drawing/vml_shape.rb~ +0 -61
- data/lib/axlsx/util/cbf.rb +0 -333
- data/lib/axlsx/util/cfb.rb~ +0 -201
- data/lib/axlsx/util/font_tables.rb~ +0 -0
- data/lib/axlsx/util/ms_off_crypto.rb +0 -189
- data/lib/axlsx/util/ms_off_crypto.rb~ +0 -3
- data/lib/axlsx/util/ms_offcrypto.rb~ +0 -0
- data/lib/axlsx/util/parser.rb~ +0 -6
- data/lib/axlsx/util/storage.rb~ +0 -0
- data/lib/axlsx/workbook/shared_strings_table.rb~ +0 -69
- data/lib/axlsx/workbook/worksheet/cfvo.rb~ +0 -0
- data/lib/axlsx/workbook/worksheet/col.rb~ +0 -0
- data/lib/axlsx/workbook/worksheet/color_scale.rb~ +0 -46
- data/lib/axlsx/workbook/worksheet/comment.rb~ +0 -91
- data/lib/axlsx/workbook/worksheet/comments.rb~ +0 -86
- data/lib/axlsx/workbook/worksheet/data_bar.rb~ +0 -0
- data/lib/axlsx/workbook/worksheet/icon_set.rb~ +0 -95
- data/lib/axlsx/workbook/worksheet/shared_strings_table.rb~ +0 -0
- data/lib/axlsx/workbook/worksheet/table.rb~ +0 -97
- data/lib/schema/dc.xsd~ +0 -118
- data/lib/schema/dcterms.xsd~ +0 -331
- data/lib/schema/opc-coreProperties.xsd~ +0 -50
- data/test/drawing/tc_data_source.rb~ +0 -30
- data/test/drawing/tc_num_data.rb~ +0 -35
- data/test/drawing/tc_num_val.rb~ +0 -29
- data/test/drawing/tc_str_data.rb~ +0 -30
- data/test/drawing/tc_str_val.rb~ +0 -26
- data/test/drawing/tc_vml_drawing.rb~ +0 -0
- data/test/workbook/worksheet/table/tc_table.rb~ +0 -72
- data/test/workbook/worksheet/tc_cfvo.rb~ +0 -20
- data/test/workbook/worksheet/tc_col.rb~ +0 -10
- data/test/workbook/worksheet/tc_color_scale.rb~ +0 -0
- data/test/workbook/worksheet/tc_data_bar.rb~ +0 -0
- data/test/workbook/worksheet/tc_icon_set.rb~ +0 -0
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
# encoding: UTF-8
|
|
2
|
-
require 'digest'
|
|
3
|
-
require 'base64'
|
|
4
|
-
require 'openssl'
|
|
5
|
-
|
|
6
|
-
module Axlsx
|
|
7
|
-
|
|
8
|
-
# The MsOffCrypto class implements ECMA-367 encryption based on the MS-OFF-CRYPTO specification
|
|
9
|
-
class MsOffCrypto
|
|
10
|
-
|
|
11
|
-
# Creates a new MsOffCrypto Object
|
|
12
|
-
# @param [String] file_name the location of the file you want to encrypt
|
|
13
|
-
# @param [String] pwd the password to use when encrypting the file
|
|
14
|
-
def initialize(file_name, pwd)
|
|
15
|
-
self.password = pwd
|
|
16
|
-
self.file_name = file_name
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
# Generates a new CBF file based on this instance of ms-off-crypto and overwrites the unencrypted file.
|
|
20
|
-
def save
|
|
21
|
-
cfb = Cbf.new(self)
|
|
22
|
-
cfb.save
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
# returns the raw password used in encryption
|
|
26
|
-
# @return [String]
|
|
27
|
-
attr_reader :password
|
|
28
|
-
|
|
29
|
-
# sets the password to be used for encryption
|
|
30
|
-
# @param [String] v the password, @default 'password'
|
|
31
|
-
# @return [String]
|
|
32
|
-
def password=(v)
|
|
33
|
-
@password = v || 'password'
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
# retruns the file name of the archive to be encrypted
|
|
37
|
-
# @return [String]
|
|
38
|
-
attr_reader :file_name
|
|
39
|
-
|
|
40
|
-
# sets the filename
|
|
41
|
-
# @return [String]
|
|
42
|
-
def file_name=(v)
|
|
43
|
-
#TODO verfify that the file specified exists and is an unencrypted xlsx archive
|
|
44
|
-
@file_name = v
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
# encrypts and returns the package specified by the file name
|
|
49
|
-
# @return [String]
|
|
50
|
-
def encrypted_package
|
|
51
|
-
@encrypted_package ||= encrypt_package(file_name)
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
# returns the encryption info for this instance of ms-off-crypto
|
|
55
|
-
# @return [String]
|
|
56
|
-
def encryption_info
|
|
57
|
-
@encryption_info ||= create_encryption_info
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
# returns a random salt
|
|
61
|
-
# @return [String]
|
|
62
|
-
def salt
|
|
63
|
-
@salt ||= Digest::SHA1.digest(rand(16**16).to_s)
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
# returns a random verifier
|
|
67
|
-
# @return [String]
|
|
68
|
-
def verifier
|
|
69
|
-
@verifier ||= rand(16**16).to_s
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
# returns the verifier encrytped
|
|
73
|
-
# @return [String]
|
|
74
|
-
def encrypted_verifier
|
|
75
|
-
@encrypted_verifier ||= encrypt(verifier)
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
# returns the verifier hash encrypted
|
|
79
|
-
# @return [String]
|
|
80
|
-
def encrypted_verifier_hash
|
|
81
|
-
@encrypted_verifier_hash ||= encrypt(verifier_hash)
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
# returns a verifier hash
|
|
85
|
-
# @return [String]
|
|
86
|
-
def verifier_hash
|
|
87
|
-
@verifier_hash ||= create_verifier_hash
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
# returns an encryption key
|
|
91
|
-
# @return [String]
|
|
92
|
-
def key
|
|
93
|
-
@key ||= create_key
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
# size of unencrypted package? concated with encrypted package
|
|
97
|
-
def encrypt_package(file_name)
|
|
98
|
-
package = File.open(file_name, 'r')
|
|
99
|
-
crypt_pack = encrypt(package.read)
|
|
100
|
-
[crypt_pack.size].pack('q') + crypt_pack
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
# Generates an encryption info structure
|
|
104
|
-
# @return [String]
|
|
105
|
-
def create_encryption_info
|
|
106
|
-
header = [3, 0, 2, 0] # version
|
|
107
|
-
# Header flags copy
|
|
108
|
-
header.concat [0x24, 0, 0, 0] #flags -- VERY UNSURE ABOUT THIS STILL
|
|
109
|
-
# header.concat [0, 0, 0, 0] #unused
|
|
110
|
-
header.concat [0xA4, 0, 0, 0] #length
|
|
111
|
-
# Header
|
|
112
|
-
header.concat [0x24, 0, 0, 0] #flags again
|
|
113
|
-
# header.concat [0, 0, 0, 0] #unused again,
|
|
114
|
-
header.concat [0x0E, 0x66, 0, 0] #alg id
|
|
115
|
-
header.concat [0x04, 0x80, 0, 0] #alg hash id
|
|
116
|
-
header.concat [key.size, 0, 0, 0] #key size
|
|
117
|
-
header.concat [0x18, 0, 0, 0] #provider type
|
|
118
|
-
# header.concat [0, 0, 0, 0] #reserved 1
|
|
119
|
-
# header.concat [0, 0, 0, 0] #reserved 2
|
|
120
|
-
header.concat [0xA0, 0xC7, 0xDC, 0x2, 0, 0, 0, 0]
|
|
121
|
-
header.concat "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)".bytes.to_a.pack('s*').bytes.to_a
|
|
122
|
-
header.concat [0, 0] #null terminator
|
|
123
|
-
|
|
124
|
-
#Salt Size
|
|
125
|
-
header.concat [salt.bytes.to_a.size].pack('l').bytes.to_a
|
|
126
|
-
#Salt
|
|
127
|
-
header.concat salt.bytes.to_a.pack('c*').bytes.to_a
|
|
128
|
-
# encryption verifier
|
|
129
|
-
header.concat encrypted_verifier.bytes.to_a.pack('c*').bytes.to_a
|
|
130
|
-
|
|
131
|
-
# verifier hash size -- MUST BE 32 bytes
|
|
132
|
-
header.concat [verifier_hash.bytes.to_a.size].pack('l').bytes.to_a
|
|
133
|
-
|
|
134
|
-
#encryption verifier hash
|
|
135
|
-
header.concat encrypted_verifier_hash.bytes.to_a.pack('c*').bytes.to_a
|
|
136
|
-
|
|
137
|
-
header.flatten!
|
|
138
|
-
header.pack('c*')
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
# 2.3.3
|
|
142
|
-
def create_verifier_hash
|
|
143
|
-
vh = Digest::SHA1.digest(verifier)
|
|
144
|
-
vh << Array.new(32 - vh.size, 0).join('')
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
# 2.3.4.7 ECMA-376 Document Encryption Key Generation (Standard Encryption)
|
|
148
|
-
def create_key
|
|
149
|
-
sha = Digest::SHA1.new() << (salt + @password)
|
|
150
|
-
(0..49999).each { |i| sha.update(i.to_s+sha.to_s) }
|
|
151
|
-
key = sha.update(sha.to_s+'0').digest
|
|
152
|
-
a = key.bytes.each_with_index.map { |item, i| 0x36 ^ item }
|
|
153
|
-
x1 = Digest::SHA1.digest((a.concat Array.new(64 - key.size, 0x36)).to_s)
|
|
154
|
-
a = key.bytes.each_with_index.map { |item, i| 0x5C ^ item }
|
|
155
|
-
x2 = Digest::SHA1.digest( (a.concat Array.new(64 - key.size, 0x5C) ).to_s)
|
|
156
|
-
x3 = x1 + x2
|
|
157
|
-
x3.bytes.to_a[(0..31)].pack('c*')
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
# ensures that the a hashed decryption of the encryption verifier matches the decrypted verifier hash.
|
|
161
|
-
# @return [Boolean]
|
|
162
|
-
def verify_password
|
|
163
|
-
v = Digest::SHA1.digest decrypt(@encrypted_verifier)
|
|
164
|
-
vh = decrypt(@encrypted_verifier_hash)
|
|
165
|
-
vh[0..15] == v[0..15]
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
# encrypts the data proved
|
|
169
|
-
# @param [String] data
|
|
170
|
-
# @return [String] the encrypted data
|
|
171
|
-
def encrypt(data)
|
|
172
|
-
aes = OpenSSL::Cipher.new("AES-128-ECB")
|
|
173
|
-
aes.encrypt
|
|
174
|
-
aes.key = key
|
|
175
|
-
aes.update(data) << aes.final
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
# dencrypts the data proved
|
|
179
|
-
# @param [String] data
|
|
180
|
-
# @return [String] the dencrypted data
|
|
181
|
-
def decrypt(data)
|
|
182
|
-
aes = OpenSSL::Cipher.new("AES-128-ECB")
|
|
183
|
-
aes.decrypt
|
|
184
|
-
aes.key = key
|
|
185
|
-
aes.update(data) << aes.final
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
end
|
|
189
|
-
end
|
|
File without changes
|
data/lib/axlsx/util/parser.rb~
DELETED
data/lib/axlsx/util/storage.rb~
DELETED
|
File without changes
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
# encoding: UTF--8
|
|
2
|
-
module Axlsx
|
|
3
|
-
|
|
4
|
-
# The Shared String Table class is responsible for managing and serializing common strings in a workbook.
|
|
5
|
-
# While the ECMA-376 spec allows for both inline and shared strings it seems that at least some applications like Numbers (Mac)
|
|
6
|
-
# and Google Docs require that the shared string table is populated in order to interoperate properly.
|
|
7
|
-
# As a developer, you should never need to directly work against this class. Simply set 'use_shared_strings'
|
|
8
|
-
# on the package or workbook to generate a package that uses the shared strings table instead of inline strings.
|
|
9
|
-
# @note Serialization performance is affected by using this serialization method so if you do not need interoperability
|
|
10
|
-
# it is recomended that you use the default inline string method of serialization.
|
|
11
|
-
class SharedStringsTable
|
|
12
|
-
|
|
13
|
-
# The total number of strings in the workbook including duplicates
|
|
14
|
-
# Empty cells are treated as blank strings
|
|
15
|
-
# @return [Integer]
|
|
16
|
-
attr_reader :count
|
|
17
|
-
|
|
18
|
-
# The total number of unique strings in the workbook.
|
|
19
|
-
# @return [Integer]
|
|
20
|
-
def unique_count
|
|
21
|
-
@unique_cells.size
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
# An array of unique cells. Multiple attributes of the cell are used in comparison
|
|
25
|
-
# each of these unique cells is parsed into the shared string table.
|
|
26
|
-
# @see Cell#sharable
|
|
27
|
-
attr_reader :unique_cells
|
|
28
|
-
|
|
29
|
-
# Creates a new Shared Strings Table agains an array of cells
|
|
30
|
-
# @param [Array] cells This is an array of all of the cells in the workbook
|
|
31
|
-
def initialize(cells)
|
|
32
|
-
cells = cells.reject { |c| c.type != :string }
|
|
33
|
-
@count = cells.size
|
|
34
|
-
@unique_cells = []
|
|
35
|
-
resolve cells
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
# Interate over all of the cells in the array.
|
|
39
|
-
# if our unique cells array does not contain a sharable cell,
|
|
40
|
-
# add the cell to our unique cells array and set the ssti attribute on the index of this cell in the shared strings table
|
|
41
|
-
# if a sharable cell already exists in our unique_cells array, set the ssti attribute of the cell and move on.
|
|
42
|
-
# @return [Array] unique cells
|
|
43
|
-
def resolve(cells)
|
|
44
|
-
cells.each do |cell|
|
|
45
|
-
index = @unique_cells.index { |item| item.sharable(cell) }
|
|
46
|
-
if index == nil
|
|
47
|
-
cell.ssti = @unique_cells.size
|
|
48
|
-
@unique_cells << cell
|
|
49
|
-
else
|
|
50
|
-
cell.ssti = index
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# Generate the xml document for the Shared Strings Table
|
|
56
|
-
# @return [String]
|
|
57
|
-
def to_xml
|
|
58
|
-
builder = Nokogiri::XML::Builder.new(:encoding => ENCODING) do |xml|
|
|
59
|
-
xml.sst(:xmlns => Axlsx::XML_NS, :count => count, :uniqueCount => unique_count) {
|
|
60
|
-
@unique_cells.each do |cell|
|
|
61
|
-
xml.si { xml.t cell.value.to_s }
|
|
62
|
-
end
|
|
63
|
-
}
|
|
64
|
-
end
|
|
65
|
-
builder.to_xml(:save_with => 0)
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
end
|
|
File without changes
|
|
File without changes
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
module Axlsx
|
|
2
|
-
# Conditional Format Rule color scale object
|
|
3
|
-
# Describes a gradated color scale in this conditional formatting rule.
|
|
4
|
-
|
|
5
|
-
# @note The recommended way to manage these rules is via Worksheet#add_conditional_formatting
|
|
6
|
-
# @see Worksheet#add_conditional_formatting
|
|
7
|
-
# @see ConditionalFormattingRule#initialize
|
|
8
|
-
class ColorScale
|
|
9
|
-
|
|
10
|
-
# A simple typed list of cfvos
|
|
11
|
-
# @return [SimpleTypedList]
|
|
12
|
-
# @see cfvo
|
|
13
|
-
attr_reader :cfvos
|
|
14
|
-
|
|
15
|
-
# A simple types list of colors
|
|
16
|
-
# @return [SimpleTypedList]
|
|
17
|
-
# @see Color
|
|
18
|
-
attr_reader :colors
|
|
19
|
-
|
|
20
|
-
def initializer
|
|
21
|
-
initialize_cfvos
|
|
22
|
-
initialize_colors
|
|
23
|
-
yield self if block_given?
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def add
|
|
27
|
-
@cfvos << Cfvo.new(:type => :min, :val => 0)
|
|
28
|
-
@colors << Color.new :rgb => "FF000000"
|
|
29
|
-
{:cfvo => @cfvos.last, :color => @colors.last}
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
protected
|
|
33
|
-
|
|
34
|
-
def initialize_cfvos
|
|
35
|
-
@cfvos = SimpleTypedList.new Cfvo
|
|
36
|
-
@cfvos.concat [Cfvo.new(:type => :min, :val => 0), Cfvo.new(:type => :max, :val => 0)]
|
|
37
|
-
@cfvos.lock
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def initialize_colors
|
|
41
|
-
@colors = SimpleTypedList.new Color
|
|
42
|
-
@colors.concat [Color.new(:rgb => "FFFF0000", Color.new(:rgb => "FF0000FF")]
|
|
43
|
-
@colors.lock
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
end
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
module Axlsx
|
|
2
|
-
|
|
3
|
-
# A comment is the text data for a comment
|
|
4
|
-
class Comment
|
|
5
|
-
|
|
6
|
-
# The text to render
|
|
7
|
-
# @return [String]
|
|
8
|
-
attr_reader :text
|
|
9
|
-
|
|
10
|
-
# The index of the the author for this comment in the owning Comments object
|
|
11
|
-
# @see Comments
|
|
12
|
-
# @return [Integer]
|
|
13
|
-
attr_reader :author_index
|
|
14
|
-
|
|
15
|
-
# The owning Comments object
|
|
16
|
-
# @return [Comments]
|
|
17
|
-
attr_reader :comments
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
# The string based cell position reference (e.g. 'A1') that determines the positioning of this comment
|
|
21
|
-
attr_reader :ref
|
|
22
|
-
|
|
23
|
-
# TODO
|
|
24
|
-
# r (Rich Text Run)
|
|
25
|
-
# rPh (Phonetic Text Run)
|
|
26
|
-
# phoneticPr (Phonetic Properties)
|
|
27
|
-
|
|
28
|
-
def initialize(comments, options={})
|
|
29
|
-
raise ArgumentError, "A comment needs a parent comments object" unless comments.is_a?(Comments)
|
|
30
|
-
@comments = comments
|
|
31
|
-
options.each do |o|
|
|
32
|
-
self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
|
|
33
|
-
end
|
|
34
|
-
yield self if block_given?
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def pn
|
|
38
|
-
"#{COMMENT_PN % (index+1)}"
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def vml_shape
|
|
42
|
-
@vml_shape ||= initialize_vml_shape
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def initialize_vml_shape
|
|
46
|
-
ws = self.comments.worksheet
|
|
47
|
-
@vml_shape = VmlShape.new(self, :row => ws[ref].row.index, :column => ws[ref].index) do |vml|
|
|
48
|
-
vml.left_column = vml.row + 1
|
|
49
|
-
vml.right_column = vml.column + 4
|
|
50
|
-
vml.top_row = vml.row
|
|
51
|
-
vml.bottom_row = vml.row + 4
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# The index of this comment
|
|
56
|
-
# @return [Integer]
|
|
57
|
-
def index
|
|
58
|
-
@comments.comment_list.index(self)
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def ref=(v)
|
|
62
|
-
Axlsx::DataTypeValidator.validate "Comment.ref", [String, Cell], v
|
|
63
|
-
@ref = v if v.is_a?(String)
|
|
64
|
-
@ref = v.r if v.is_a?(Cell)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def text=(v)
|
|
68
|
-
Axlsx::validate_string(v)
|
|
69
|
-
@text = v
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def author_index=(v)
|
|
73
|
-
Axlsx::validate_unsigned_int(v)
|
|
74
|
-
@author_index = v
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def to_xml_string(str = "")
|
|
78
|
-
author = @comments.authors[author_index]
|
|
79
|
-
str << '<comment ref="' << ref << '" authorId="' << author_index.to_s << '">'
|
|
80
|
-
str << '<text><r>'
|
|
81
|
-
str << '<rPr> <b/><color indexed="81"/></rPr>'
|
|
82
|
-
str << '<t>' << author.to_s << ':
|
|
83
|
-
</t></r>'
|
|
84
|
-
str << '<r>'
|
|
85
|
-
str << '<rPr><color indexed="81"/></rPr>'
|
|
86
|
-
str << '<t>' << text << '</t></r></text>'
|
|
87
|
-
str << '</comment>'
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
end
|
|
91
|
-
end
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
module Axlsx
|
|
2
|
-
|
|
3
|
-
class Comments
|
|
4
|
-
|
|
5
|
-
# a collection of the comment authors
|
|
6
|
-
# @return [SimpleTypedList]
|
|
7
|
-
attr_reader :authors
|
|
8
|
-
|
|
9
|
-
# a collection of comment objects
|
|
10
|
-
# @return [SimpleTypedList]
|
|
11
|
-
attr_reader :comment_list
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
# The worksheet that these comments belong to
|
|
15
|
-
# @return [Worksheet]
|
|
16
|
-
attr_reader :worksheet
|
|
17
|
-
|
|
18
|
-
# Creates a new Comments object
|
|
19
|
-
def initialize(worksheet)
|
|
20
|
-
raise ArgumentError, "you must provide a worksheet" unless worksheet.is_a?(Worksheet)
|
|
21
|
-
@worksheet = worksheet
|
|
22
|
-
@authors = SimpleTypedList.new String
|
|
23
|
-
@comment_list = SimpleTypedList.new Comment
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def add_comment(options={})
|
|
27
|
-
raise ArgumentError, "Comment require an author" unless options[:author]
|
|
28
|
-
raise ArgumentError, "Comment requires text" unless options[:text]
|
|
29
|
-
options[:author_index] = @authors.index(options[:author]) || @authors << options[:author]
|
|
30
|
-
@comment_list << Comment.new(self, options)
|
|
31
|
-
@comment_list.last
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def to_xml_string(str="")
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
class Comment
|
|
40
|
-
|
|
41
|
-
attr_reader :text
|
|
42
|
-
|
|
43
|
-
attr_reader :author_index
|
|
44
|
-
|
|
45
|
-
attr_reader :comments
|
|
46
|
-
|
|
47
|
-
# TODO
|
|
48
|
-
# r (Rich Text Run)
|
|
49
|
-
# rPh (Phonetic Text Run)
|
|
50
|
-
# phoneticPr (Phonetic Properties)
|
|
51
|
-
def initialize(comments, options={})
|
|
52
|
-
raise ArgumentError, "A comment needs a parent comments object" unless comments.is_a?(Comments)
|
|
53
|
-
@comments = comments
|
|
54
|
-
options.each do |o|
|
|
55
|
-
self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
|
|
56
|
-
end
|
|
57
|
-
yield self if block_given?
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def pn
|
|
61
|
-
"#{COMMENT_PN % (index+1)}"
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
# The index of this comment
|
|
65
|
-
# @return [Integer]
|
|
66
|
-
def index
|
|
67
|
-
@comments.comment_list.index(self)
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
def text=(v)
|
|
72
|
-
Axlsx::validate_string(v)
|
|
73
|
-
@text = v
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def author_index=(v)
|
|
77
|
-
Axlsx::validate_unsigned_int(v)
|
|
78
|
-
@author_index = v
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def to_xml_string(str = "")
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
end
|
|
File without changes
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
module Axlsx
|
|
2
|
-
# Conditional Format Rule data bar object
|
|
3
|
-
# Describes a data bar conditional formatting rule.
|
|
4
|
-
|
|
5
|
-
# @note The recommended way to manage these rules is via Worksheet#add_conditional_formatting
|
|
6
|
-
# @see Worksheet#add_conditional_formatting
|
|
7
|
-
# @see ConditionalFormattingRule#initialize
|
|
8
|
-
class DataBar
|
|
9
|
-
CHILD_ELEMENTS = [:value_objects]
|
|
10
|
-
|
|
11
|
-
# minLength attribute
|
|
12
|
-
# The minimum length of the data bar, as a percentage of the cell width.
|
|
13
|
-
# The default value is 10
|
|
14
|
-
# @return [Integer]
|
|
15
|
-
attr_reader :minLength
|
|
16
|
-
|
|
17
|
-
# maxLength attribute
|
|
18
|
-
# The maximum length of the data bar, as a percentage of the cell width.
|
|
19
|
-
# The default value is 90
|
|
20
|
-
# @return [Integer]
|
|
21
|
-
attr_reader :maxLength
|
|
22
|
-
|
|
23
|
-
# maxLength attribute
|
|
24
|
-
# Indicates whether to show the values of the cells on which this data bar is applied.
|
|
25
|
-
# The default value is true
|
|
26
|
-
# @return [Boolean]
|
|
27
|
-
attr_reader :showValue
|
|
28
|
-
|
|
29
|
-
# A simple typed list of cfvos
|
|
30
|
-
# @return [SimpleTypedList]
|
|
31
|
-
# @see Cfvo
|
|
32
|
-
attr_reader :value_objects
|
|
33
|
-
|
|
34
|
-
# color
|
|
35
|
-
# the color object used in the data bar formatting
|
|
36
|
-
# @return [Color]
|
|
37
|
-
def color
|
|
38
|
-
@color ||= Color.new :rgb => "FF0000FF"
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
# Creates a new data bar conditional formatting object
|
|
42
|
-
# @option options [Integer] minLength
|
|
43
|
-
# @option options [Integer] maxLength
|
|
44
|
-
# @option options [Boolean] showValue
|
|
45
|
-
# @option options [String] color - the rbg value used to color the bars
|
|
46
|
-
def initialize(options = {})
|
|
47
|
-
@minLength = 10
|
|
48
|
-
@maxLength = 90
|
|
49
|
-
@showValue = true
|
|
50
|
-
initialize_value_objects
|
|
51
|
-
options.each do |o|
|
|
52
|
-
self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
|
|
53
|
-
end
|
|
54
|
-
yield self if block_given?
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
# @see minLength
|
|
58
|
-
def minLength=(v); Axlsx.validate_unsigned_int(v); @minLength = v end
|
|
59
|
-
# @see maxLength
|
|
60
|
-
def maxLength=(v); Axlsx.validate_unsigned_int(v); @maxLength = v end
|
|
61
|
-
|
|
62
|
-
# @see showValue
|
|
63
|
-
def showValue=(v); Axlsx.validate_boolean(v); @showValue = v end
|
|
64
|
-
|
|
65
|
-
# Sets the color for the data bars.
|
|
66
|
-
# @param [Color|String] The color object, or rgb string value to apply
|
|
67
|
-
def color=(v)
|
|
68
|
-
@color = v if v.is_a? Color
|
|
69
|
-
self.color.rgb = v if v.is_a? String
|
|
70
|
-
@color
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
# Serialize this object to an xml string
|
|
74
|
-
# @param [String] str
|
|
75
|
-
# @return [String]
|
|
76
|
-
def to_xml_string(str="")
|
|
77
|
-
str << '<dataBar '
|
|
78
|
-
str << instance_values.map { |key, value| '' << key << '="' << value.to_s << '"' unless CHILD_ELEMENTS.include?(key.to_sym) }.join(' ')
|
|
79
|
-
str << '>'
|
|
80
|
-
@value_objects.each { |cfvo| cfvo.to_xml_string(str) }
|
|
81
|
-
self.color.to_xml_string(str)
|
|
82
|
-
str << '</dataBar>'
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
private
|
|
86
|
-
|
|
87
|
-
# Initalize the simple typed list of value objects
|
|
88
|
-
# I am keeping this private for now as I am not sure what impact changes to the required two cfvo objects will do.
|
|
89
|
-
def initialize_value_objects
|
|
90
|
-
@value_objects = SimpleTypedList.new Cfvo
|
|
91
|
-
@value_objects.concat [Cfvo.new(:type => :min, :val => 0), Cfvo.new(:type => :max, :val => 0)]
|
|
92
|
-
@value_objects.lock
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
end
|
|
File without changes
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
# encoding: UTF-8
|
|
2
|
-
module Axlsx
|
|
3
|
-
# Table
|
|
4
|
-
# @note Worksheet#add_table is the recommended way to create charts for your worksheets.
|
|
5
|
-
# @see README for examples
|
|
6
|
-
class Table
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
# The reference to the table data
|
|
10
|
-
# @return [String]
|
|
11
|
-
attr_reader :ref
|
|
12
|
-
|
|
13
|
-
# The name of the table.
|
|
14
|
-
# @return [String]
|
|
15
|
-
attr_reader :name
|
|
16
|
-
|
|
17
|
-
# The style for the table.
|
|
18
|
-
# @return [TableStyle]
|
|
19
|
-
attr_reader :style
|
|
20
|
-
|
|
21
|
-
# Creates a new Table object
|
|
22
|
-
# @param [String] ref The reference to the table data.
|
|
23
|
-
# @param [Sheet] ref The sheet containing the table data.
|
|
24
|
-
# @option options [Cell, String] name
|
|
25
|
-
# @option options [TableStyle] style
|
|
26
|
-
def initialize(ref, sheet, options={})
|
|
27
|
-
@ref = ref
|
|
28
|
-
@sheet = sheet
|
|
29
|
-
@style = nil
|
|
30
|
-
@sheet.workbook.tables << self
|
|
31
|
-
@name = "Table#{index+1}"
|
|
32
|
-
options.each do |o|
|
|
33
|
-
self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
|
|
34
|
-
end
|
|
35
|
-
yield self if block_given?
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
# The index of this chart in the workbooks charts collection
|
|
39
|
-
# @return [Integer]
|
|
40
|
-
def index
|
|
41
|
-
@sheet.workbook.tables.index(self)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
# The part name for this table
|
|
45
|
-
# @return [String]
|
|
46
|
-
def pn
|
|
47
|
-
"#{TABLE_PN % (index+1)}"
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
# The relation reference id for this table
|
|
51
|
-
# @return [String]
|
|
52
|
-
def rId
|
|
53
|
-
"rId#{index+1}"
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
# The name of the Table.
|
|
57
|
-
# @param [String, Cell] v
|
|
58
|
-
# @return [Title]
|
|
59
|
-
def name=(v)
|
|
60
|
-
DataTypeValidator.validate "#{self.class}.name", [String], v
|
|
61
|
-
if v.is_a?(String)
|
|
62
|
-
@name = v
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
# The style for the table.
|
|
68
|
-
# TODO
|
|
69
|
-
# def style=(v) DataTypeValidator.validate "Chart.style", Integer, v, lambda { |arg| arg >= 1 && arg <= 48 }; @style = v; end
|
|
70
|
-
|
|
71
|
-
# Table Serialization
|
|
72
|
-
# serializes the table
|
|
73
|
-
def to_xml
|
|
74
|
-
builder = Nokogiri::XML::Builder.new(:encoding => ENCODING) do |xml|
|
|
75
|
-
xml.table(:xmlns => XML_NS, :id => index+1, :name => @name, :displayName => @name.gsub(/\s/,'_'), :ref => @ref, :totalsRowShown => 0) {
|
|
76
|
-
xml.autoFilter :ref=>@ref
|
|
77
|
-
xml.tableColumns(:count => header_cells.length) {
|
|
78
|
-
header_cells.each_with_index do |cell,index|
|
|
79
|
-
xml.tableColumn :id => index+1, :name => cell.value
|
|
80
|
-
end
|
|
81
|
-
}
|
|
82
|
-
xml.tableStyleInfo :showFirstColumn=>"0", :showLastColumn=>"0", :showRowStripes=>"1", :showColumnStripes=>"0", :name=>"TableStyleMedium9"
|
|
83
|
-
#TODO implement tableStyleInfo
|
|
84
|
-
}
|
|
85
|
-
end
|
|
86
|
-
builder.to_xml(:save_with => 0)
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
private
|
|
90
|
-
|
|
91
|
-
# get the header cells (hackish)
|
|
92
|
-
def header_cells
|
|
93
|
-
header = @ref.gsub(/^(\w+)(\d+)\:(\w+)\d+$/, '\1\2:\3\2')
|
|
94
|
-
@sheet[header]
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
end
|