axlsx 1.2.3 → 1.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +3 -2
- data/CHANGELOG.md +34 -1
- data/README.md +26 -37
- data/Rakefile +1 -1
- data/examples/auto_filter.rb +16 -0
- data/examples/auto_filter.xlsx +0 -0
- data/examples/example.rb +3 -2
- data/examples/example.xlsx +0 -0
- data/examples/example_streamed.xlsx +0 -0
- data/examples/no-use_autowidth.xlsx +0 -0
- data/examples/shared_strings_example.xlsx +0 -0
- data/examples/skydrive/real_example.rb +6 -6
- data/examples/sprk2012/Screen Shot 2012-09-11 at 10.42.06 PM.png +0 -0
- data/examples/sprk2012/Screen Shot 2012-09-11 at 11.07.48 PM.png +0 -0
- data/examples/sprk2012/Screen Shot 2012-09-11 at 8.31.50 PM.png +0 -0
- data/examples/sprk2012/Screen Shot 2012-09-11 at 9.23.27 PM.png +0 -0
- data/examples/sprk2012/Screen Shot 2012-09-11 at 9.32.06 PM.png +0 -0
- data/examples/sprk2012/Screen Shot 2012-09-11 at 9.33.35 PM.png +0 -0
- data/examples/sprk2012/Screen Shot 2012-09-11 at 9.46.44 PM.png +0 -0
- data/examples/sprk2012/Screen Shot 2012-09-12 at 5.07.23 PM.png +0 -0
- data/examples/sprk2012/basics.rb +1 -0
- data/examples/sprk2012/basics.xlsx +0 -0
- data/examples/sprk2012/gravatar.jpeg +0 -0
- data/examples/sprk2012/hair_club.jpg +0 -0
- data/examples/sprk2012/images.rb +7 -12
- data/examples/sprk2012/images.xlsx +0 -0
- data/examples/sprk2012/line_chart.rb +56 -0
- data/examples/sprk2012/line_chart.xlsx +0 -0
- data/examples/sprk2012/sprk2012.key +0 -0
- data/examples/sprk2012/styles.rb +13 -12
- data/examples/sprk2012/styles.xlsx +0 -0
- data/examples/styles.rb +62 -0
- data/examples/styles.xlsx +0 -0
- data/lib/axlsx.rb +8 -1
- data/lib/axlsx/stylesheet/styles.rb +4 -0
- data/lib/axlsx/util/constants.rb +90 -5
- data/lib/axlsx/util/validators.rb +26 -8
- data/lib/axlsx/version.rb +2 -2
- data/lib/axlsx/workbook/workbook.rb +4 -1
- data/lib/axlsx/workbook/worksheet/auto_filter/auto_filter.rb +77 -0
- data/lib/axlsx/workbook/worksheet/auto_filter/filter_column.rb +102 -0
- data/lib/axlsx/workbook/worksheet/auto_filter/filters.rb +253 -0
- data/lib/axlsx/workbook/worksheet/cell.rb +9 -4
- data/lib/axlsx/workbook/worksheet/date_time_converter.rb +1 -1
- data/lib/axlsx/workbook/worksheet/page_set_up_pr.rb +47 -0
- data/lib/axlsx/workbook/worksheet/sheet_calc_pr.rb +49 -0
- data/lib/axlsx/workbook/worksheet/sheet_pr.rb +87 -4
- data/lib/axlsx/workbook/worksheet/table.rb +8 -1
- data/lib/axlsx/workbook/worksheet/table_style_info.rb +68 -0
- data/lib/axlsx/workbook/worksheet/worksheet.rb +18 -3
- data/test/stylesheet/tc_styles.rb +13 -0
- data/test/util/tc_validators.rb +8 -1
- data/test/workbook/worksheet/auto_filter/tc_auto_filter.rb +38 -0
- data/test/workbook/worksheet/auto_filter/tc_filter_column.rb +76 -0
- data/test/workbook/worksheet/auto_filter/tc_filters.rb +50 -0
- data/test/workbook/worksheet/tc_cell.rb +5 -0
- data/test/workbook/worksheet/tc_page_set_up_pr.rb +15 -0
- data/test/workbook/worksheet/tc_sheet_calc_pr.rb +18 -0
- data/test/workbook/worksheet/tc_sheet_pr.rb +27 -0
- data/test/workbook/worksheet/{table/tc_table.rb → tc_table.rb} +6 -1
- data/test/workbook/worksheet/tc_table_style_info.rb +53 -0
- data/test/workbook/worksheet/tc_worksheet.rb +17 -3
- metadata +45 -7
- data/examples/~$extractive.xlsx +0 -0
- data/lib/axlsx/workbook/worksheet/auto_filter.rb +0 -35
Binary file
|
data/lib/axlsx.rb
CHANGED
@@ -37,7 +37,12 @@ if !Object.respond_to?(:instance_values)
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
-
# xlsx generation with charts, images, automated column width, customizable styles
|
40
|
+
# xlsx generation with charts, images, automated column width, customizable styles
|
41
|
+
# and full schema validation. Axlsx excels at helping you generate beautiful
|
42
|
+
# Office Open XML Spreadsheet documents without having to understand the entire
|
43
|
+
# ECMA specification. Check out the README for some examples of how easy it is.
|
44
|
+
# Best of all, you can validate your xlsx file before serialization so you know
|
45
|
+
# for sure that anything generated is going to load on your client's machine.
|
41
46
|
module Axlsx
|
42
47
|
|
43
48
|
# determines the cell range for the items provided
|
@@ -65,6 +70,7 @@ module Axlsx
|
|
65
70
|
# returns the x, y position of a cell
|
66
71
|
def self.name_to_indices(name)
|
67
72
|
raise ArgumentError, 'invalid cell name' unless name.size > 1
|
73
|
+
# capitalization?!?
|
68
74
|
v = name[/[A-Z]+/].reverse.chars.reduce({:base=>1, :i=>0}) do |val, c|
|
69
75
|
val[:i] += ((c.bytes.first - 64) * val[:base]); val[:base] *= 26; val
|
70
76
|
end
|
@@ -95,6 +101,7 @@ module Axlsx
|
|
95
101
|
# @param [String] s The snake case string to camelize
|
96
102
|
# @return [String]
|
97
103
|
def self.camel(s="", all_caps = true)
|
104
|
+
s = s.to_s
|
98
105
|
s = s.capitalize if all_caps
|
99
106
|
s.gsub(/_(.)/){ $1.upcase }
|
100
107
|
end
|
@@ -279,6 +279,10 @@ module Axlsx
|
|
279
279
|
# @return [Font|Integer]
|
280
280
|
def parse_font_options(options={})
|
281
281
|
return if (options.keys & [:fg_color, :sz, :b, :i, :u, :strike, :outline, :shadow, :charset, :family, :font_name]).empty?
|
282
|
+
fonts.first.instance_values.each do |key, value|
|
283
|
+
# Thanks for that 1.8.7 - cant do a simple merge...
|
284
|
+
options[key.to_sym] = value unless options.keys.include?(key.to_sym)
|
285
|
+
end
|
282
286
|
font = Font.new(options)
|
283
287
|
font.color = Color.new(:rgb => options[:fg_color]) if options[:fg_color]
|
284
288
|
font.name = options[:font_name] if options[:font_name]
|
data/lib/axlsx/util/constants.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# encoding: UTF-8
|
2
1
|
module Axlsx
|
3
2
|
|
4
3
|
# XML Encoding
|
@@ -129,7 +128,7 @@ module Axlsx
|
|
129
128
|
|
130
129
|
# digital signature origin content type
|
131
130
|
DIGITAL_SIGNATURE_ORIGIN_CT = "application/vnd.openxmlformats-package.digital-signature-origin"
|
132
|
-
|
131
|
+
|
133
132
|
# digital signature certificate content type
|
134
133
|
DIGITAL_SIGNATURE_CERTIFICATE_CT = "application/vnd.openxmlformats-package.digital-signature-certificate"
|
135
134
|
|
@@ -151,7 +150,7 @@ module Axlsx
|
|
151
150
|
#drawing content type
|
152
151
|
DRAWING_CT = "application/vnd.openxmlformats-officedocument.drawing+xml"
|
153
152
|
|
154
|
-
|
153
|
+
|
155
154
|
# xml content type extensions
|
156
155
|
XML_EX = "xml"
|
157
156
|
|
@@ -263,11 +262,14 @@ module Axlsx
|
|
263
262
|
# error message for RegexValidator
|
264
263
|
ERR_REGEX = "Invalid Data. %s does not match %s."
|
265
264
|
|
265
|
+
# error message for RangeValidator
|
266
|
+
ERR_RANGE = "Invalid Data. %s must be between %s and %s, (inclusive:%s) you gave: %s"
|
267
|
+
|
266
268
|
# error message for sheets that use a name which is longer than 31 bytes
|
267
269
|
ERR_SHEET_NAME_TOO_LONG = "Your worksheet name '%s' is too long. Worksheet names must be 31 characters (bytes) or less"
|
268
|
-
|
270
|
+
|
269
271
|
# error message for sheets that use a name which includes a colon
|
270
|
-
|
272
|
+
|
271
273
|
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."
|
272
274
|
|
273
275
|
# error message for duplicate sheet names
|
@@ -284,4 +286,87 @@ module Axlsx
|
|
284
286
|
|
285
287
|
# error message for non 'integerish' value
|
286
288
|
ERR_INTEGERISH = "You value must be, or be castable via to_i, an Integer. You provided %s"
|
289
|
+
|
290
|
+
# Regex to match forbidden control characters
|
291
|
+
# The following will be automatically stripped from worksheets.
|
292
|
+
#
|
293
|
+
# x00 Null
|
294
|
+
# x01 Start Of Heading
|
295
|
+
# x02 Start Of Text
|
296
|
+
# x03End Of Text
|
297
|
+
# x04 End Of Transmission
|
298
|
+
# x05 Enquiry
|
299
|
+
# x06 Acknowledge
|
300
|
+
# x07 Bell
|
301
|
+
# x08 Backspace
|
302
|
+
# x0B Line Tabulation
|
303
|
+
# x0C Form Feed
|
304
|
+
# x0E Shift Out
|
305
|
+
# x0F Shift In
|
306
|
+
# x10 Data Link Escape
|
307
|
+
# x11 Device Control One
|
308
|
+
# x12 Device Control Two
|
309
|
+
# x13 Device Control Three
|
310
|
+
# x14 Device Control Four
|
311
|
+
# x15 Negative Acknowledge
|
312
|
+
# x16 Synchronous Idle
|
313
|
+
# x17 End Of Transmission Block
|
314
|
+
# x18 Cancel
|
315
|
+
# x19 End Of Medium
|
316
|
+
# x1A Substitute
|
317
|
+
# x1B Escape
|
318
|
+
# x1C Information Separator Four
|
319
|
+
# x1D Information Separator Three
|
320
|
+
# x1E Information Separator Two
|
321
|
+
# x1F Information Separator One
|
322
|
+
#
|
323
|
+
# The following are not dealt with.
|
324
|
+
# If you have this in your data, expect excel to blow up!
|
325
|
+
#
|
326
|
+
# x7F Delete
|
327
|
+
# x80 Control 0080
|
328
|
+
# x81 Control 0081
|
329
|
+
# x82 Break Permitted Here
|
330
|
+
# x83 No Break Here
|
331
|
+
# x84 Control 0084
|
332
|
+
# x85 Next Line (Nel)
|
333
|
+
# x86 Start Of Selected Area
|
334
|
+
# x87 End Of Selected Area
|
335
|
+
# x88 Character Tabulation Set
|
336
|
+
# x89 Character Tabulation With Justification
|
337
|
+
# x8A Line Tabulation Set
|
338
|
+
# x8B Partial Line Forward
|
339
|
+
# x8C Partial Line Backward
|
340
|
+
# x8D Reverse Line Feed
|
341
|
+
# x8E Single Shift Two
|
342
|
+
# x8F Single Shift Three
|
343
|
+
# x90 Device Control String
|
344
|
+
# x91 Private Use One
|
345
|
+
# x92 Private Use Two
|
346
|
+
# x93 Set Transmit State
|
347
|
+
# x94 Cancel Character
|
348
|
+
# x95 Message Waiting
|
349
|
+
# x96 Start Of Guarded Area
|
350
|
+
# x97 End Of Guarded Area
|
351
|
+
# x98 Start Of String
|
352
|
+
# x99 Control 0099
|
353
|
+
# x9A Single Character Introducer
|
354
|
+
# x9B Control Sequence Introducer
|
355
|
+
# x9C String Terminator
|
356
|
+
# x9D Operating System Command
|
357
|
+
# x9E Privacy Message
|
358
|
+
# x9F Application Program Command
|
359
|
+
#
|
360
|
+
# The following are allowed:
|
361
|
+
#
|
362
|
+
# x0A Line Feed (Lf)
|
363
|
+
# x0D Carriage Return (Cr)
|
364
|
+
# x09 Character Tabulation
|
365
|
+
# @see http://www.codetable.net/asciikeycodes
|
366
|
+
pattern = "[\x0-\x08\x0B\x0C\x0E-\x1F]"
|
367
|
+
pattern= pattern.respond_to?(:encode) ? pattern.encode('UTF-8') : pattern
|
368
|
+
|
369
|
+
# The regular expression used to remove control characters from worksheets
|
370
|
+
CONTROL_CHAR_REGEX = Regexp.new(pattern, 'n')
|
371
|
+
|
287
372
|
end
|
@@ -14,6 +14,24 @@ module Axlsx
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
+
# Validate that the value provided is between a specific range
|
18
|
+
# Note that no data conversions will be done for you!
|
19
|
+
# Comparisons will be made using < and > or <= and <= when the inclusive parameter is true
|
20
|
+
class RangeValidator
|
21
|
+
# @param [String] name The name of what is being validated
|
22
|
+
# @param [Any] min The minimum allowed value
|
23
|
+
# @param [Any] max The maximum allowed value
|
24
|
+
# @param [Any] value The value to be validated
|
25
|
+
# @param [Boolean] inclusive Flag indicating if the comparison should be inclusive.
|
26
|
+
def self.validate(name, min, max, value, inclusive = true)
|
27
|
+
passes = if inclusive
|
28
|
+
min <= value && value <= max
|
29
|
+
else
|
30
|
+
min < value && value < max
|
31
|
+
end
|
32
|
+
raise ArgumentError, (ERR_RANGE % [value.inspect, min.to_s, max.to_s, inclusive]) unless passes
|
33
|
+
end
|
34
|
+
end
|
17
35
|
# Validates the value against the regular expression provided.
|
18
36
|
class RegexValidator
|
19
37
|
# @param [String] name The name of what is being validated. This is included in the output when the value is invalid
|
@@ -73,7 +91,7 @@ module Axlsx
|
|
73
91
|
# @raise [ArgumentError] raised if the value is not a Fixnun, Integer, Float value greater or equal to 0
|
74
92
|
# @return [Boolean] true if the data is valid
|
75
93
|
def self.validate_unsigned_numeric(v)
|
76
|
-
DataTypeValidator.validate("Invalid column width", [Fixnum, Integer, Float], v, lambda { |arg| arg.respond_to?(:>=) && arg >= 0 })
|
94
|
+
DataTypeValidator.validate("Invalid column width", [Fixnum, Integer, Float], v, lambda { |arg| arg.respond_to?(:>=) && arg.to_i >= 0 })
|
77
95
|
end
|
78
96
|
|
79
97
|
# Requires that the value is a Fixnum or Integer
|
@@ -112,7 +130,7 @@ module Axlsx
|
|
112
130
|
def self.validate_scale_10_400(v)
|
113
131
|
DataTypeValidator.validate "page_scale", [Fixnum, Integer], v, lambda { |arg| arg >= 10 && arg <= 400 }
|
114
132
|
end
|
115
|
-
|
133
|
+
|
116
134
|
# Requires that the value is an integer ranging from 10 to 400 or 0.
|
117
135
|
def self.validate_scale_0_10_400(v)
|
118
136
|
DataTypeValidator.validate "page_scale", [Fixnum, Integer], v, lambda { |arg| arg == 0 || (arg >= 10 && arg <= 400) }
|
@@ -129,7 +147,7 @@ module Axlsx
|
|
129
147
|
# @param [Any] v The value validated
|
130
148
|
def self.validate_pattern_type(v)
|
131
149
|
RestrictionValidator.validate :pattern_type, [:none, :solid, :mediumGray, :darkGray, :lightGray, :darkHorizontal, :darkVertical, :darkDown, :darkUp, :darkGrid,
|
132
|
-
|
150
|
+
:darkTrellis, :lightHorizontal, :lightVertical, :lightDown, :lightUp, :lightGrid, :lightTrellis, :gray125, :gray0625], v
|
133
151
|
end
|
134
152
|
|
135
153
|
# Requires that the value is one of the ST_TimePeriod types
|
@@ -226,7 +244,7 @@ module Axlsx
|
|
226
244
|
def self.validate_data_validation_error_style(v)
|
227
245
|
RestrictionValidator.validate :validate_data_validation_error_style, [:information, :stop, :warning], v
|
228
246
|
end
|
229
|
-
|
247
|
+
|
230
248
|
# Requires that the value is valid data validation operator.
|
231
249
|
# valid operators must be one of lessThan, lessThanOrEqual, equal,
|
232
250
|
# notEqual, greaterThanOrEqual, greaterThan, between, notBetween
|
@@ -234,28 +252,28 @@ module Axlsx
|
|
234
252
|
def self.validate_data_validation_operator(v)
|
235
253
|
RestrictionValidator.validate :data_validation_operator, [:lessThan, :lessThanOrEqual, :equal, :notEqual, :greaterThanOrEqual, :greaterThan, :between, :notBetween], v
|
236
254
|
end
|
237
|
-
|
255
|
+
|
238
256
|
# Requires that the value is valid data validation type.
|
239
257
|
# valid types must be one of custom, data, decimal, list, none, textLength, time, whole
|
240
258
|
# @param [Any] v The value validated
|
241
259
|
def self.validate_data_validation_type(v)
|
242
260
|
RestrictionValidator.validate :data_validation_type, [:custom, :data, :decimal, :list, :none, :textLength, :time, :whole], v
|
243
261
|
end
|
244
|
-
|
262
|
+
|
245
263
|
# Requires that the value is a valid sheet view type.
|
246
264
|
# valid types must be one of normal, page_break_preview, page_layout
|
247
265
|
# @param [Any] v The value validated
|
248
266
|
def self.validate_sheet_view_type(v)
|
249
267
|
RestrictionValidator.validate :sheet_view_type, [:normal, :page_break_preview, :page_layout], v
|
250
268
|
end
|
251
|
-
|
269
|
+
|
252
270
|
# Requires that the value is a valid active pane type.
|
253
271
|
# valid types must be one of bottom_left, bottom_right, top_left, top_right
|
254
272
|
# @param [Any] v The value validated
|
255
273
|
def self.validate_pane_type(v)
|
256
274
|
RestrictionValidator.validate :active_pane_type, [:bottom_left, :bottom_right, :top_left, :top_right], v
|
257
275
|
end
|
258
|
-
|
276
|
+
|
259
277
|
# Requires that the value is a valid split state type.
|
260
278
|
# valid types must be one of frozen, frozen_split, split
|
261
279
|
# @param [Any] v The value validated
|
data/lib/axlsx/version.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
module Axlsx
|
3
|
-
require 'axlsx/workbook/worksheet/
|
3
|
+
require 'axlsx/workbook/worksheet/sheet_calc_pr.rb'
|
4
|
+
require 'axlsx/workbook/worksheet/auto_filter/auto_filter.rb'
|
4
5
|
require 'axlsx/workbook/worksheet/date_time_converter.rb'
|
5
6
|
require 'axlsx/workbook/worksheet/protected_range.rb'
|
6
7
|
require 'axlsx/workbook/worksheet/protected_ranges.rb'
|
7
8
|
require 'axlsx/workbook/worksheet/cell.rb'
|
8
9
|
require 'axlsx/workbook/worksheet/page_margins.rb'
|
10
|
+
require 'axlsx/workbook/worksheet/page_set_up_pr.rb'
|
9
11
|
require 'axlsx/workbook/worksheet/page_setup.rb'
|
10
12
|
require 'axlsx/workbook/worksheet/print_options.rb'
|
11
13
|
require 'axlsx/workbook/worksheet/cfvo.rb'
|
@@ -33,6 +35,7 @@ require 'axlsx/workbook/worksheet/worksheet.rb'
|
|
33
35
|
require 'axlsx/workbook/shared_strings_table.rb'
|
34
36
|
require 'axlsx/workbook/defined_name.rb'
|
35
37
|
require 'axlsx/workbook/defined_names.rb'
|
38
|
+
require 'axlsx/workbook/worksheet/table_style_info.rb'
|
36
39
|
require 'axlsx/workbook/worksheet/table.rb'
|
37
40
|
require 'axlsx/workbook/worksheet/tables.rb'
|
38
41
|
require 'axlsx/workbook/worksheet/data_validation.rb'
|
@@ -0,0 +1,77 @@
|
|
1
|
+
|
2
|
+
require 'axlsx/workbook/worksheet/auto_filter/filter_column.rb'
|
3
|
+
require 'axlsx/workbook/worksheet/auto_filter/filters.rb'
|
4
|
+
|
5
|
+
module Axlsx
|
6
|
+
|
7
|
+
#This class represents an auto filter range in a worksheet
|
8
|
+
class AutoFilter
|
9
|
+
|
10
|
+
# creates a new Autofilter object
|
11
|
+
# @param [Worksheet] worksheet
|
12
|
+
def initialize(worksheet)
|
13
|
+
raise ArgumentError, 'you must provide a worksheet' unless worksheet.is_a?(Worksheet)
|
14
|
+
@worksheet = worksheet
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :worksheet
|
18
|
+
|
19
|
+
# The range the autofilter should be applied to.
|
20
|
+
# This should be a string like 'A1:B8'
|
21
|
+
# @return [String]
|
22
|
+
attr_accessor :range
|
23
|
+
|
24
|
+
# the formula for the defined name required for this auto filter
|
25
|
+
# This prepends the worksheet name to the absolute cell reference
|
26
|
+
# e.g. A1:B2 -> 'Sheet1'!$A$1:$B$2
|
27
|
+
# @return [String]
|
28
|
+
def defined_name
|
29
|
+
return unless range
|
30
|
+
Axlsx.cell_range(range.split(':').collect { |name| worksheet.name_to_cell(name)})
|
31
|
+
end
|
32
|
+
|
33
|
+
# A collection of filterColumns for this auto_filter
|
34
|
+
# @return [SimpleTypedList]
|
35
|
+
def columns
|
36
|
+
@columns ||= SimpleTypedList.new FilterColumn
|
37
|
+
end
|
38
|
+
|
39
|
+
# Adds a filter column. This is the recommended way to create and manage filter columns for your autofilter.
|
40
|
+
# In addition to the require id and type parameters, options will be passed to the filter column during instantiation.
|
41
|
+
# @param [String] col_id Zero-based index indicating the AutoFilter column to which this filter information applies.
|
42
|
+
# @param [Symbol] filter_type A symbol representing one of the supported filter types.
|
43
|
+
# @param [Hash] options a hash of options to pass into the generated filter
|
44
|
+
# @return [FilterColumn]
|
45
|
+
def add_column(col_id, filter_type, options = {})
|
46
|
+
columns << FilterColumn.new(col_id, filter_type, options)
|
47
|
+
columns.last
|
48
|
+
end
|
49
|
+
|
50
|
+
# actually performs the filtering of rows who's cells do not
|
51
|
+
# match the filter.
|
52
|
+
def apply
|
53
|
+
first_cell, last_cell = range.split(':')
|
54
|
+
start_point = Axlsx::name_to_indices(first_cell)
|
55
|
+
end_point = Axlsx::name_to_indices(last_cell)
|
56
|
+
# The +1 is so we skip the header row with the filter drop downs
|
57
|
+
rows = worksheet.rows[(start_point.last+1)..end_point.last] || []
|
58
|
+
|
59
|
+
column_offset = start_point.first
|
60
|
+
columns.each do |column|
|
61
|
+
rows.each do |row|
|
62
|
+
next if row.hidden
|
63
|
+
column.apply(row, column_offset)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
# serialize the object
|
68
|
+
# @return [String]
|
69
|
+
def to_xml_string(str='')
|
70
|
+
return unless range
|
71
|
+
str << "<autoFilter ref='#{range}'>"
|
72
|
+
columns.each { |filter_column| filter_column.to_xml_string(str) }
|
73
|
+
str << "</autoFilter>"
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module Axlsx
|
2
|
+
# The filterColumn collection identifies a particular column in the AutoFilter
|
3
|
+
# range and specifies filter information that has been applied to this column.
|
4
|
+
# If a column in the AutoFilter range has no criteria specified,
|
5
|
+
# then there is no corresponding filterColumn collection expressed for that column.
|
6
|
+
class FilterColumn
|
7
|
+
|
8
|
+
# Allowed filters
|
9
|
+
FILTERS = [:filters] #, :top10, :custom_filters, :dynamic_filters, :color_filters, :icon_filters]
|
10
|
+
|
11
|
+
# Creates a new FilterColumn object
|
12
|
+
# @note This class yeilds its filter object as that is where the vast majority of processing will be done
|
13
|
+
# @param [Integer|Cell] col_id The zero based index for the column to which this filter will be applied
|
14
|
+
# @param [Symbol] filter_type The symbolized class name of the filter to apply to this column.
|
15
|
+
# @param [Hash] options options for this object and the filter
|
16
|
+
# @option [Boolean] hidden_button @see hidden_button
|
17
|
+
# @option [Boolean] show_button @see show_button
|
18
|
+
def initialize(col_id, filter_type, options = {})
|
19
|
+
RestrictionValidator.validate 'FilterColumn.filter', FILTERS, filter_type
|
20
|
+
#Axlsx::validate_unsigned_int(col_id)
|
21
|
+
self.col_id = col_id
|
22
|
+
options.each do |o|
|
23
|
+
self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
|
24
|
+
end
|
25
|
+
@filter = Axlsx.const_get(Axlsx.camel(filter_type)).new(options)
|
26
|
+
yield @filter if block_given?
|
27
|
+
end
|
28
|
+
|
29
|
+
# Zero-based index indicating the AutoFilter column to which this filter information applies.
|
30
|
+
# @return [Integer]
|
31
|
+
attr_reader :col_id
|
32
|
+
|
33
|
+
# The actual filter being dealt with here
|
34
|
+
# This could be any one of the allowed filter types
|
35
|
+
attr_reader :filter
|
36
|
+
|
37
|
+
# Flag indicating whether the filter button is visible.
|
38
|
+
# When the cell containing the filter button is merged with another cell,
|
39
|
+
# the filter button can be hidden, and not drawn.
|
40
|
+
# @return [Boolean]
|
41
|
+
def show_button
|
42
|
+
@show_button ||= true
|
43
|
+
end
|
44
|
+
|
45
|
+
# Flag indicating whether the AutoFilter button for this column is hidden.
|
46
|
+
# @return [Boolean]
|
47
|
+
def hidden_button
|
48
|
+
@hidden_button ||= false
|
49
|
+
end
|
50
|
+
|
51
|
+
# Sets the col_id attribute for this filter column.
|
52
|
+
# @param [Integer | Cell] column_index The zero based index of the column to which this filter applies.
|
53
|
+
# When you specify a cell, the column index will be read off the cell
|
54
|
+
# @return [Integer]
|
55
|
+
def col_id=(column_index)
|
56
|
+
column_index = column_index.col if column_index.is_a?(Cell)
|
57
|
+
Axlsx.validate_unsigned_int column_index
|
58
|
+
@col_id = column_index
|
59
|
+
end
|
60
|
+
|
61
|
+
# Apply the filters for this column
|
62
|
+
# @param [Array] row A row from a worksheet that needs to be
|
63
|
+
# filtered.
|
64
|
+
def apply(row, offset)
|
65
|
+
row.hidden = @filter.apply(row.cells[offset+col_id.to_i])
|
66
|
+
end
|
67
|
+
# @param [Boolean] hidden Flag indicating whether the AutoFilter button for this column is hidden.
|
68
|
+
# @return [Boolean]
|
69
|
+
def hidden_button=(hidden)
|
70
|
+
Axlsx.validate_boolean hidden
|
71
|
+
@hidden_button = hidden
|
72
|
+
end
|
73
|
+
|
74
|
+
# Flag indicating whether the AutoFilter button is show. This is
|
75
|
+
# undocumented in the spec, but exists in the schema file as an
|
76
|
+
# optional attribute.
|
77
|
+
# @param [Boolean] show Show or hide the button
|
78
|
+
# @return [Boolean]
|
79
|
+
def show_button=(show)
|
80
|
+
Axlsx.validate_boolean show
|
81
|
+
@show_botton = show
|
82
|
+
end
|
83
|
+
|
84
|
+
# Serialize the object to xml
|
85
|
+
def to_xml_string(str='')
|
86
|
+
str << "<filterColumn #{serialized_attributes}>"
|
87
|
+
@filter.to_xml_string(str)
|
88
|
+
str << "</filterColumn>"
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
def serialized_attributes(str='')
|
94
|
+
instance_values.each do |key, value|
|
95
|
+
if %(show_button hidden_button col_id).include? key.to_s
|
96
|
+
str << "#{Axlsx.camel(key, false)}='#{value}' "
|
97
|
+
end
|
98
|
+
end
|
99
|
+
str
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|