axlsx 1.1.7 → 1.1.8
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +41 -5
- data/Rakefile +3 -2
- data/examples/chart_colors.rb +18 -3
- data/examples/example.rb +100 -46
- data/examples/extractive.pdf +0 -0
- data/lib/axlsx.rb +7 -6
- 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 +47 -37
- data/lib/axlsx/drawing/bar_series.rb +1 -0
- data/lib/axlsx/drawing/cat_axis.rb +42 -38
- data/lib/axlsx/drawing/chart.rb +34 -27
- data/lib/axlsx/drawing/drawing.rb +5 -4
- data/lib/axlsx/drawing/line_3D_chart.rb +1 -1
- data/lib/axlsx/drawing/num_data_source.rb +1 -1
- data/lib/axlsx/drawing/pie_3D_chart.rb +7 -7
- data/lib/axlsx/drawing/two_cell_anchor.rb +3 -8
- 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 +2 -2
- data/lib/axlsx/util/validators.rb +2 -2
- data/lib/axlsx/version.rb +1 -1
- data/lib/axlsx/workbook/workbook.rb +1 -2
- data/lib/axlsx/workbook/worksheet/cell.rb +1 -1
- data/lib/axlsx/workbook/worksheet/data_bar.rb +1 -1
- 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/worksheet.rb +180 -56
- 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 +0 -1
- data/test/drawing/tc_chart.rb +1 -5
- data/test/drawing/tc_pie_3D_chart.rb +3 -7
- data/test/drawing/tc_view_3D.rb +18 -18
- data/test/tc_package.rb +2 -0
- data/test/workbook/worksheet/tc_page_setup.rb +20 -3
- data/test/workbook/worksheet/tc_protected_range.rb +18 -0
- data/test/workbook/worksheet/tc_selection.rb +1 -1
- data/test/workbook/worksheet/tc_worksheet.rb +39 -18
- metadata +54 -103
- 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/example.xlsx +0 -0
- data/examples/example_streamed.xlsx +0 -0
- data/examples/examples_saved.xlsx +0 -0
- data/examples/extractive.xlsx +0 -0
- data/examples/fish.xlsx +0 -0
- data/examples/no-use_autowidth.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/shared_strings_example.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
data/lib/axlsx/package.rb
CHANGED
@@ -156,18 +156,18 @@ module Axlsx
|
|
156
156
|
# @return [Zip::ZipOutputStream]
|
157
157
|
def write_parts(zip)
|
158
158
|
p = parts
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
end
|
165
|
-
unless part[:path].nil?
|
166
|
-
zip.put_next_entry(part[:entry]);
|
167
|
-
# binread for 1.9.3
|
168
|
-
zip.write IO.respond_to?(:binread) ? IO.binread(part[:path]) : IO.read(part[:path])
|
169
|
-
end
|
159
|
+
p.each do |part|
|
160
|
+
unless part[:doc].nil?
|
161
|
+
zip.put_next_entry(part[:entry])
|
162
|
+
entry = ['1.9.2', '1.9.3'].include?(RUBY_VERSION) ? part[:doc].force_encoding('BINARY') : part[:doc]
|
163
|
+
zip.puts(entry)
|
170
164
|
end
|
165
|
+
unless part[:path].nil?
|
166
|
+
zip.put_next_entry(part[:entry]);
|
167
|
+
# binread for 1.9.3
|
168
|
+
zip.write IO.respond_to?(:binread) ? IO.binread(part[:path]) : IO.read(part[:path])
|
169
|
+
end
|
170
|
+
end
|
171
171
|
zip
|
172
172
|
end
|
173
173
|
|
@@ -30,9 +30,9 @@ module Axlsx
|
|
30
30
|
attr_reader :TargetMode
|
31
31
|
|
32
32
|
# creates a new relationship
|
33
|
-
# @param [String]
|
34
|
-
# @param [String]
|
35
|
-
# @option [Symbol] target_mode only accepts :external.
|
33
|
+
# @param [String] type The type of the relationship
|
34
|
+
# @param [String] target The target for the relationship
|
35
|
+
# @option [Symbol] :target_mode only accepts :external.
|
36
36
|
def initialize(type, target, options={})
|
37
37
|
self.Target=target
|
38
38
|
self.Type=type
|
@@ -133,7 +133,7 @@ module Axlsx
|
|
133
133
|
# @option options [Integer] family The font family to use.
|
134
134
|
# @option options [String] font_name The name of the font to use
|
135
135
|
# @option options [Integer] num_fmt The number format to apply
|
136
|
-
# @option options [String] format_code The formatting to apply.
|
136
|
+
# @option options [String] format_code The formatting to apply.
|
137
137
|
# @option options [Integer|Hash] border The border style to use.
|
138
138
|
# @option options [String] bg_color The background color to apply to the cell
|
139
139
|
# @option options [Boolean] hidden Indicates if the cell should be hidden
|
data/lib/axlsx/util/constants.rb
CHANGED
@@ -249,6 +249,10 @@ module Axlsx
|
|
249
249
|
|
250
250
|
# error message for sheets that use a name which is longer than 31 bytes
|
251
251
|
ERR_SHEET_NAME_TOO_LONG = "Your worksheet name '%s' is too long. Worksheet names must be 31 characters (bytes) or less"
|
252
|
+
|
253
|
+
# error message for sheets that use a name which includes a colon
|
254
|
+
|
255
|
+
ERR_SHEET_NAME_COLON_FORBIDDEN = "Your worksheet name '%s' contains a colon, which is not allowed by MS Excel and will cause repair warnings. Please change the name of your sheet."
|
252
256
|
|
253
257
|
# error message for duplicate sheet names
|
254
258
|
ERR_DUPLICATE_SHEET_NAME = "There is already a worksheet in this workbook named '%s'. Please use a unique name"
|
@@ -18,7 +18,7 @@ module Axlsx
|
|
18
18
|
|
19
19
|
# Creats a new typed list
|
20
20
|
# @param [Array, Class] type An array of Class objects or a single Class object
|
21
|
-
# @param [String]
|
21
|
+
# @param [String] serialize_as The tag name to use in serialization
|
22
22
|
# @raise [ArgumentError] if all members of type are not Class objects
|
23
23
|
def initialize type, serialize_as=nil
|
24
24
|
if type.is_a? Array
|
@@ -149,7 +149,7 @@ module Axlsx
|
|
149
149
|
|
150
150
|
def to_xml_string(str = '')
|
151
151
|
classname = @allowed_types[0].name.split('::').last
|
152
|
-
el_name = serialize_as || (classname[0,1].downcase + classname[1..-1])
|
152
|
+
el_name = serialize_as.to_s || (classname[0,1].downcase + classname[1..-1])
|
153
153
|
str << '<' << el_name << ' count="' << @list.size.to_s << '">'
|
154
154
|
@list.each { |item| item.to_xml_string(str) }
|
155
155
|
str << '</' << el_name << '>'
|
@@ -181,7 +181,7 @@ module Axlsx
|
|
181
181
|
# Requires that the value is a valid scatterStyle
|
182
182
|
# must be one of :none | :line | :lineMarker | :marker | :smooth | :smoothMarker
|
183
183
|
# must be one of "none" | "line" | "lineMarker" | "marker" | "smooth" | "smoothMarker"
|
184
|
-
# @param [Symbol|String] the value to validate
|
184
|
+
# @param [Symbol|String] v the value to validate
|
185
185
|
def self.validate_scatter_style(v)
|
186
186
|
Axlsx::RestrictionValidator.validate "ScatterChart.scatterStyle", [:none, :line, :lineMarker, :marker, :smooth, :smoothMarker], v.to_sym
|
187
187
|
end
|
@@ -262,4 +262,4 @@ module Axlsx
|
|
262
262
|
def self.validate_split_state_type(v)
|
263
263
|
RestrictionValidator.validate :split_state_type, [:frozen, :frozen_split, :split], v
|
264
264
|
end
|
265
|
-
end
|
265
|
+
end
|
data/lib/axlsx/version.rb
CHANGED
@@ -5,6 +5,6 @@ module Axlsx
|
|
5
5
|
# When using bunle exec rake and referencing the gem on github or locally
|
6
6
|
# it will use the gemspec, which preloads this constant for the gem's version.
|
7
7
|
# We check to make sure that it has not already been loaded
|
8
|
-
VERSION="1.1.
|
8
|
+
VERSION="1.1.8" unless defined? Axlsx::VERSION
|
9
9
|
|
10
10
|
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
module Axlsx
|
3
3
|
|
4
4
|
require 'axlsx/workbook/worksheet/date_time_converter.rb'
|
5
|
+
require 'axlsx/workbook/worksheet/protected_range.rb'
|
5
6
|
require 'axlsx/workbook/worksheet/cell.rb'
|
6
7
|
require 'axlsx/workbook/worksheet/page_margins.rb'
|
7
8
|
require 'axlsx/workbook/worksheet/page_setup.rb'
|
@@ -100,7 +101,6 @@ require 'axlsx/workbook/worksheet/selection.rb'
|
|
100
101
|
# @return [SimpleTypedList]
|
101
102
|
attr_reader :tables
|
102
103
|
|
103
|
-
|
104
104
|
# A colllection of comments associated with this workbook
|
105
105
|
# @note The recommended way to manage comments is Worksheet#add_comment
|
106
106
|
# @see Worksheet#add_comment
|
@@ -143,7 +143,6 @@ require 'axlsx/workbook/worksheet/selection.rb'
|
|
143
143
|
@drawings = SimpleTypedList.new Drawing
|
144
144
|
@charts = SimpleTypedList.new Chart
|
145
145
|
@images = SimpleTypedList.new Pic
|
146
|
-
|
147
146
|
# Are these even used????? Check package serialization parts
|
148
147
|
@tables = SimpleTypedList.new Table
|
149
148
|
@comments = SimpleTypedList.new Comments
|
@@ -142,7 +142,7 @@ module Axlsx
|
|
142
142
|
# The inline color property for the cell
|
143
143
|
# @return [Color]
|
144
144
|
attr_reader :color
|
145
|
-
# @param [String] The 8 character representation for an rgb color #FFFFFFFF"
|
145
|
+
# @param [String] v The 8 character representation for an rgb color #FFFFFFFF"
|
146
146
|
def color=(v)
|
147
147
|
@color = v.is_a?(Color) ? v : Color.new(:rgb=>v)
|
148
148
|
@is_text_run = true
|
@@ -65,7 +65,7 @@ module Axlsx
|
|
65
65
|
def showValue=(v); Axlsx.validate_boolean(v); @showValue = v end
|
66
66
|
|
67
67
|
# Sets the color for the data bars.
|
68
|
-
# @param [Color|String] The color object, or rgb string value to apply
|
68
|
+
# @param [Color|String] v The color object, or rgb string value to apply
|
69
69
|
def color=(v)
|
70
70
|
@color = v if v.is_a? Color
|
71
71
|
self.color.rgb = v if v.is_a? String
|
@@ -92,6 +92,15 @@ module Axlsx
|
|
92
92
|
[@fit_to_width, @fit_to_height]
|
93
93
|
end
|
94
94
|
|
95
|
+
|
96
|
+
# helper method for worksheet to determine if the page setup is configured for fit to page printing
|
97
|
+
# We treat any page set up that has a value set for fit_to_width or fit_to_height value as fit_to_page.
|
98
|
+
# @return [Boolean]
|
99
|
+
def fit_to_page?
|
100
|
+
# is there some better what to express this?
|
101
|
+
(fit_to_width != nil || fit_to_height != nil)
|
102
|
+
end
|
103
|
+
|
95
104
|
# Serializes the page settings element.
|
96
105
|
# @param [String] str
|
97
106
|
# @return [String]
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Axlsx
|
2
|
+
# The Protected Range class represents a set of cells in the worksheet
|
3
|
+
# @note the recommended way to manage protected ranges with via Worksheet#protect_range
|
4
|
+
# @see Worksheet#protect_range
|
5
|
+
class ProtectedRange
|
6
|
+
|
7
|
+
# The reference for the protected range
|
8
|
+
# @return [String]
|
9
|
+
attr_reader :sqref
|
10
|
+
|
11
|
+
# The name of the protected range
|
12
|
+
# @return [String]
|
13
|
+
attr_reader :name
|
14
|
+
|
15
|
+
# Initializes a new protected range object
|
16
|
+
# @option [String] sqref The cell range reference to protect. This can be an absolute or a relateve range however, it only applies to the current sheet.
|
17
|
+
# @option [String] name An optional name for the protected name.
|
18
|
+
def initialize(options={})
|
19
|
+
options.each do |o|
|
20
|
+
self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
|
21
|
+
end
|
22
|
+
yield self if block_given?
|
23
|
+
end
|
24
|
+
|
25
|
+
# @see sqref
|
26
|
+
def sqref=(v)
|
27
|
+
Axlsx.validate_string(v)
|
28
|
+
@sqref = v
|
29
|
+
end
|
30
|
+
|
31
|
+
# @see name
|
32
|
+
def name=(v)
|
33
|
+
Axlsx.validate_string(v)
|
34
|
+
@name = v
|
35
|
+
end
|
36
|
+
|
37
|
+
# serializes the proteted range
|
38
|
+
# @param [String] str if this string object is provided we append
|
39
|
+
# our output to that object. Use this - it helps limit the number of
|
40
|
+
# objects created during serialization
|
41
|
+
def to_xml_string(str="")
|
42
|
+
attrs = self.instance_values.reject{ |key, value| value == nil }
|
43
|
+
str << '<protectedRange ' << attrs.map { |key, value| '' << key << '="' << value.to_s << '"' }.join(' ') << '/>'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -16,7 +16,13 @@ module Axlsx
|
|
16
16
|
yield @sheet_protection if block_given?
|
17
17
|
@sheet_protection
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
|
+
# A collection of protected ranges in the worksheet
|
21
|
+
# @note The recommended way to manage protected ranges is with Worksheet#protect_range
|
22
|
+
# @see Worksheet#protect_range
|
23
|
+
# @return [SimpleTypedList] The protected ranges for this worksheet
|
24
|
+
attr_reader :protected_ranges
|
25
|
+
|
20
26
|
# The sheet view object for this worksheet
|
21
27
|
# @return [SheetView]
|
22
28
|
# @see [SheetView]
|
@@ -34,6 +40,8 @@ module Axlsx
|
|
34
40
|
# @return [Array] of Table
|
35
41
|
attr_reader :tables
|
36
42
|
|
43
|
+
# The comments associated with this worksheet
|
44
|
+
# @return [SimpleTypedList]
|
37
45
|
attr_reader :comments
|
38
46
|
|
39
47
|
# The rows in this worksheet
|
@@ -81,8 +89,9 @@ module Axlsx
|
|
81
89
|
# If you want the worksheet to fit on more pages (e.g. 2x2), set {PageSetup#fit_to_width} and {PageSetup#fit_to_height} accordingly.
|
82
90
|
# @return Boolean
|
83
91
|
# @see #page_setup
|
84
|
-
def fit_to_page
|
85
|
-
|
92
|
+
def fit_to_page?
|
93
|
+
return false unless @page_setup
|
94
|
+
@page_setup.fit_to_page?
|
86
95
|
end
|
87
96
|
|
88
97
|
|
@@ -110,7 +119,6 @@ module Axlsx
|
|
110
119
|
@page_margins ||= PageMargins.new
|
111
120
|
yield @page_margins if block_given?
|
112
121
|
@page_margins
|
113
|
-
|
114
122
|
end
|
115
123
|
|
116
124
|
# Page setup settings for printing the worksheet.
|
@@ -188,7 +196,7 @@ module Axlsx
|
|
188
196
|
@print_options = PrintOptions.new options[:print_options] if options[:print_options]
|
189
197
|
@rows = SimpleTypedList.new Row
|
190
198
|
@column_info = SimpleTypedList.new Col
|
191
|
-
|
199
|
+
@protected_ranges = SimpleTypedList.new ProtectedRange
|
192
200
|
@tables = SimpleTypedList.new Table
|
193
201
|
|
194
202
|
options.each do |o|
|
@@ -217,7 +225,7 @@ module Axlsx
|
|
217
225
|
cf.add_rules rules
|
218
226
|
@conditional_formattings << cf
|
219
227
|
end
|
220
|
-
|
228
|
+
|
221
229
|
# Add data validation to this worksheet.
|
222
230
|
#
|
223
231
|
# @param [String] cells The cells the validation will apply to.
|
@@ -237,23 +245,37 @@ module Axlsx
|
|
237
245
|
# worksheet.merge_cells worksheet.rows.first.cells[(2..4)]
|
238
246
|
# #alternatively you can do it from a single cell
|
239
247
|
# worksheet["C1"].merge worksheet["E1"]
|
240
|
-
# @param [Array, string]
|
248
|
+
# @param [Array, string] cells
|
241
249
|
def merge_cells(cells)
|
242
250
|
@merged_cells << if cells.is_a?(String)
|
243
251
|
cells
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
252
|
+
elsif cells.is_a?(Array)
|
253
|
+
cells = cells.sort { |x, y| [x.index, x.row.index] <=> [y.index, y.row.index] }
|
254
|
+
"#{cells.first.r}:#{cells.last.r}"
|
255
|
+
end
|
248
256
|
end
|
249
257
|
|
258
|
+
# Adds a new protected cell range to the worksheet. Note that protected ranges are only in effect when sheet protection is enabled.
|
259
|
+
# @param [String|Array] cells The string reference for the cells to protect or an array of cells.
|
260
|
+
# @return [ProtectedRange]
|
261
|
+
# @note When using an array of cells, a contiguous range is created from the minimum top left to the maximum top bottom of the cells provided.
|
262
|
+
def protect_range(cells)
|
263
|
+
sqref = if cells.is_a?(String)
|
264
|
+
cells
|
265
|
+
elsif cells.is_a?(SimpleTypedList)
|
266
|
+
cells = cells.sort { |x, y| [x.index, x.row.index] <=> [y.index, y.row.index] }
|
267
|
+
"#{cells.first.r}:#{cells.last.r}"
|
268
|
+
end
|
269
|
+
@protected_ranges << ProtectedRange.new(:sqref => sqref, :name => 'Range#{@protected_ranges.size}')
|
270
|
+
@protected_ranges.last
|
271
|
+
end
|
250
272
|
|
251
273
|
# The demensions of a worksheet. This is not actually a required element by the spec,
|
252
274
|
# but at least a few other document readers expect this for conversion
|
253
275
|
# @return [String] the A1:B2 style reference for the first and last row column intersection in the workbook
|
254
276
|
def dimension
|
255
277
|
dim_start = rows.first.cells.first == nil ? 'A1' : rows.first.cells.first.r
|
256
|
-
dim_end = rows.last.cells.last == nil ? '
|
278
|
+
dim_end = rows.last.cells.last == nil ? 'AA200' : rows.last.cells.last.r
|
257
279
|
"#{dim_start}:#{dim_end}"
|
258
280
|
end
|
259
281
|
|
@@ -281,7 +303,7 @@ module Axlsx
|
|
281
303
|
# @return [Boolean]
|
282
304
|
def fit_to_page=(v)
|
283
305
|
warn('axlsx::DEPRECIATED: Worksheet#fit_to_page has been depreciated. This value will automatically be set for you when you use PageSetup#fit_to.')
|
284
|
-
fit_to_page
|
306
|
+
fit_to_page?
|
285
307
|
end
|
286
308
|
|
287
309
|
|
@@ -300,6 +322,8 @@ module Axlsx
|
|
300
322
|
def name=(v)
|
301
323
|
DataTypeValidator.validate "Worksheet.name", String, v
|
302
324
|
raise ArgumentError, (ERR_SHEET_NAME_TOO_LONG % v) if v.size > 31
|
325
|
+
raise ArgumentError, (ERR_SHEET_NAME_COLON_FORBIDDEN % v) if v.include? ':'
|
326
|
+
v = Axlsx::coder.encode(v)
|
303
327
|
sheet_names = @workbook.worksheets.map { |s| s.name }
|
304
328
|
raise ArgumentError, (ERR_DUPLICATE_SHEET_NAME % v) if sheet_names.include?(v)
|
305
329
|
@name=v
|
@@ -402,8 +426,9 @@ module Axlsx
|
|
402
426
|
|
403
427
|
# Set the style for cells in a specific row
|
404
428
|
# @param [Integer] index or range of indexes in the table
|
405
|
-
# @param [Integer] the cellXfs index
|
406
|
-
# @
|
429
|
+
# @param [Integer] style the cellXfs index
|
430
|
+
# @param [Hash] options the options used when applying the style
|
431
|
+
# @option [Integer] :col_offset only cells after this column will be updated.
|
407
432
|
# @note You can also specify the style in the add_row call
|
408
433
|
# @see Worksheet#add_row
|
409
434
|
# @see README.md for an example
|
@@ -425,8 +450,9 @@ module Axlsx
|
|
425
450
|
|
426
451
|
# Set the style for cells in a specific column
|
427
452
|
# @param [Integer] index the index of the column
|
428
|
-
# @param [Integer] the cellXfs index
|
429
|
-
# @
|
453
|
+
# @param [Integer] style the cellXfs index
|
454
|
+
# @param [Hash] options
|
455
|
+
# @option [Integer] :row_offset only cells after this column will be updated.
|
430
456
|
# @note You can also specify the style for specific columns in the call to add_row by using an array for the :styles option
|
431
457
|
# @see Worksheet#add_row
|
432
458
|
# @see README.md for an example
|
@@ -449,9 +475,9 @@ module Axlsx
|
|
449
475
|
# @example This would set the first and third column widhts but leave the second column in autofit state.
|
450
476
|
# ws.column_widths 7.2, nil, 3
|
451
477
|
# @note For updating only a single column it is probably easier to just set the width of the ws.column_info[col_index].width directly
|
452
|
-
# @param [Integer|Float|Fixnum|nil]
|
453
|
-
def column_widths(*
|
454
|
-
|
478
|
+
# @param [Integer|Float|Fixnum|nil] widths
|
479
|
+
def column_widths(*widths)
|
480
|
+
widths.each_with_index do |value, index|
|
455
481
|
next if value == nil
|
456
482
|
Axlsx::validate_unsigned_numeric(value) unless value == nil
|
457
483
|
@column_info[index] ||= Col.new index+1, index+1
|
@@ -493,55 +519,49 @@ module Axlsx
|
|
493
519
|
end
|
494
520
|
|
495
521
|
# Adds a media item to the worksheets drawing
|
496
|
-
# @
|
497
|
-
# @option options [] unknown
|
522
|
+
# @option [Hash] options options passed to drawing.add_image
|
498
523
|
def add_image(options={})
|
499
524
|
image = drawing.add_image(options)
|
500
525
|
yield image if block_given?
|
501
526
|
image
|
502
527
|
end
|
503
528
|
|
504
|
-
# Serializes the object
|
505
|
-
#
|
529
|
+
# Serializes the worksheet object to an xml string
|
530
|
+
# This intentionally does not use nokogiri for performance reasons
|
506
531
|
# @return [String]
|
507
532
|
def to_xml_string
|
508
|
-
rels = relationships
|
509
533
|
str = '<?xml version="1.0" encoding="UTF-8"?>'
|
510
|
-
str
|
511
|
-
str
|
512
|
-
str
|
534
|
+
str << worksheet_node
|
535
|
+
str << sheet_pr_node
|
536
|
+
str << dimension_node
|
513
537
|
@sheet_view.to_xml_string(str) if @sheet_view
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
end
|
519
|
-
str.concat '<sheetData>'
|
520
|
-
@rows.each_with_index { |row, index| row.to_xml_string(index, str) }
|
521
|
-
str.concat '</sheetData>'
|
522
|
-
str.concat "<autoFilter ref='%s'></autoFilter>" % @auto_filter if @auto_filter
|
538
|
+
str << cols_node
|
539
|
+
str << sheet_data_node
|
540
|
+
|
541
|
+
str << auto_filter_node
|
523
542
|
@sheet_protection.to_xml_string(str) if @sheet_protection
|
524
|
-
str
|
525
|
-
|
543
|
+
str << protected_ranges_node
|
544
|
+
str << merged_cells_node
|
545
|
+
@print_options.to_xml_string(str) if @print_options
|
526
546
|
page_margins.to_xml_string(str) if @page_margins
|
527
547
|
page_setup.to_xml_string(str) if @page_setup
|
528
|
-
str <<
|
529
|
-
str <<
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
548
|
+
str << drawing_node
|
549
|
+
str << legacy_drawing_node
|
550
|
+
str << table_parts_node
|
551
|
+
str << conditional_formattings_node
|
552
|
+
str << data_validations_node
|
553
|
+
str << '</worksheet>'
|
554
|
+
# User reported that when parsing some old data that had control characters excel chokes.
|
555
|
+
# All of the following are defined as illegal xml characters in the xml spec, but for now I am only dealing with control
|
556
|
+
# characters. Thanks to asakusarb and @hsbt's flash of code on the screen!
|
557
|
+
# [#x1-#x8], [#xB-#xC], [#xE-#x1F], [#x7F-#x84], [#x86-#x9F], [#xFDD0-#xFDDF],
|
558
|
+
# [#x1FFFE-#x1FFFF], [#x2FFFE-#x2FFFF], [#x3FFFE-#x3FFFF],
|
559
|
+
# [#x4FFFE-#x4FFFF], [#x5FFFE-#x5FFFF], [#x6FFFE-#x6FFFF],
|
560
|
+
# [#x7FFFE-#x7FFFF], [#x8FFFE-#x8FFFF], [#x9FFFE-#x9FFFF],
|
561
|
+
# [#xAFFFE-#xAFFFF], [#xBFFFE-#xBFFFF], [#xCFFFE-#xCFFFF],
|
562
|
+
# [#xDFFFE-#xDFFFF], [#xEFFFE-#xEFFFF], [#xFFFFE-#xFFFFF],
|
563
|
+
# [#x10FFFE-#x10FFFF].
|
564
|
+
str.gsub(/[[:cntrl:]]/,'')
|
545
565
|
end
|
546
566
|
|
547
567
|
# The worksheet relationships. This is managed automatically by the worksheet
|
@@ -584,6 +604,110 @@ module Axlsx
|
|
584
604
|
|
585
605
|
private
|
586
606
|
|
607
|
+
# Helper method for parsingout the root node for worksheet
|
608
|
+
# @return [String]
|
609
|
+
def worksheet_node
|
610
|
+
"<worksheet xmlns=\"%s\" xmlns:r=\"%s\">" % [XML_NS, XML_NS_R]
|
611
|
+
end
|
612
|
+
|
613
|
+
# Helper method fo parsing out the sheetPr node
|
614
|
+
# @return [String]
|
615
|
+
def sheet_pr_node
|
616
|
+
return '' unless fit_to_page?
|
617
|
+
"<sheetPr><pageSetUpPr fitToPage=\"%s\"></pageSetUpPr></sheetPr>" % fit_to_page?
|
618
|
+
end
|
619
|
+
|
620
|
+
# Helper method for parsing out the demension node
|
621
|
+
# @return [String]
|
622
|
+
def dimension_node
|
623
|
+
return '' if rows.size == 0
|
624
|
+
"<dimension ref=\"%s\"></dimension>" % dimension
|
625
|
+
end
|
626
|
+
|
627
|
+
# Helper method for parsing out the sheetData node
|
628
|
+
# @return [String]
|
629
|
+
def sheet_data_node
|
630
|
+
str = '<sheetData>'
|
631
|
+
@rows.each_with_index { |row, index| row.to_xml_string(index, str) }
|
632
|
+
str << '</sheetData>'
|
633
|
+
end
|
634
|
+
|
635
|
+
# Helper method for parsing out the autoFilter node
|
636
|
+
# @return [String]
|
637
|
+
def auto_filter_node
|
638
|
+
return '' unless @auto_filter
|
639
|
+
"<autoFilter ref='%s'></autoFilter>" % @auto_filter
|
640
|
+
end
|
641
|
+
|
642
|
+
# Helper method for parsing out the cols node
|
643
|
+
# @return [String]
|
644
|
+
def cols_node
|
645
|
+
return '' if @column_info.empty?
|
646
|
+
str = "<cols>"
|
647
|
+
@column_info.each { |col| col.to_xml_string(str) }
|
648
|
+
str << '</cols>'
|
649
|
+
end
|
650
|
+
|
651
|
+
# Helper method for parsing out the protectedRanges node
|
652
|
+
# @return [String]
|
653
|
+
def protected_ranges_node
|
654
|
+
return '' if @protected_ranges.empty?
|
655
|
+
str = '<protectedRanges>'
|
656
|
+
@protected_ranges.each { |pr| pr.to_xml_string(str) }
|
657
|
+
str << '</protectedRanges>'
|
658
|
+
end
|
659
|
+
|
660
|
+
# Helper method for parsing out the mergedCells node
|
661
|
+
# @return [String]
|
662
|
+
def merged_cells_node
|
663
|
+
return '' if @merged_cells.size == 0
|
664
|
+
str = "<mergeCells count='#{@merged_cells.size}'>"
|
665
|
+
@merged_cells.each { |merged_cell| str << "<mergeCell ref='#{merged_cell}'></mergeCell>" }
|
666
|
+
str << '</mergeCells>'
|
667
|
+
end
|
668
|
+
|
669
|
+
# Helper method for parsing out the drawing node
|
670
|
+
# @return [String]
|
671
|
+
def drawing_node
|
672
|
+
return '' unless @drawing
|
673
|
+
"<drawing r:id='rId" << (relationships.index{ |r| r.Type == DRAWING_R } + 1).to_s << "'/>"
|
674
|
+
end
|
675
|
+
|
676
|
+
# Helper method for parsing out the legacyDrawing node required for comments
|
677
|
+
# @return [String]
|
678
|
+
def legacy_drawing_node
|
679
|
+
return '' if @comments.empty?
|
680
|
+
"<legacyDrawing r:id='rId" << (relationships.index{ |r| r.Type == VML_DRAWING_R } + 1).to_s << "'/>"
|
681
|
+
end
|
682
|
+
|
683
|
+
# Helper method for parsing out the tableParts node
|
684
|
+
# @return [String]
|
685
|
+
def table_parts_node
|
686
|
+
return '' if @tables.empty?
|
687
|
+
str = "<tableParts count='#{@tables.size}'>"
|
688
|
+
@tables.each { |table| str << "<tablePart r:id='#{table.rId}'/>" }
|
689
|
+
str << '</tableParts>'
|
690
|
+
end
|
691
|
+
|
692
|
+
# Helper method for parsing out the conditional formattings
|
693
|
+
# @return [String]
|
694
|
+
def conditional_formattings_node
|
695
|
+
return '' if @conditional_formattings.size == 0
|
696
|
+
str = ''
|
697
|
+
@conditional_formattings.each { |conditional_formatting| str << conditional_formatting.to_xml_string }
|
698
|
+
str
|
699
|
+
end
|
700
|
+
|
701
|
+
# Helper method for parsing out the dataValidations node
|
702
|
+
# @return [String]
|
703
|
+
def data_validations_node
|
704
|
+
return '' if @data_validations.size == 0
|
705
|
+
str = "<dataValidations count='#{@data_validations.size}'>"
|
706
|
+
@data_validations.each { |data_validation| str << data_validation.to_xml_string }
|
707
|
+
str << '</dataValidations>'
|
708
|
+
end
|
709
|
+
|
710
|
+
|
587
711
|
# assigns the owner workbook for this worksheet
|
588
712
|
def workbook=(v) DataTypeValidator.validate "Worksheet.workbook", Workbook, v; @workbook = v; end
|
589
713
|
|