caxlsx 3.1.1 → 3.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +43 -1
- data/README.md +4 -11
- data/lib/axlsx/content_type/abstract_content_type.rb +1 -1
- data/lib/axlsx/doc_props/app.rb +1 -1
- data/lib/axlsx/drawing/chart.rb +25 -2
- data/lib/axlsx/drawing/d_lbls.rb +3 -2
- data/lib/axlsx/drawing/scatter_series.rb +31 -0
- data/lib/axlsx/drawing/title.rb +11 -1
- data/lib/axlsx/drawing/view_3D.rb +1 -1
- data/lib/axlsx/package.rb +15 -5
- data/lib/axlsx/rels/relationship.rb +1 -1
- data/lib/axlsx/stylesheet/border.rb +2 -0
- data/lib/axlsx/stylesheet/font.rb +1 -1
- data/lib/axlsx/stylesheet/styles.rb +139 -24
- data/lib/axlsx/util/constants.rb +16 -1
- data/lib/axlsx/util/serialized_attributes.rb +2 -2
- data/lib/axlsx/util/storage.rb +9 -9
- data/lib/axlsx/version.rb +1 -1
- data/lib/axlsx/workbook/workbook.rb +55 -0
- data/lib/axlsx/workbook/worksheet/border_creator.rb +76 -0
- data/lib/axlsx/workbook/worksheet/cell.rb +29 -2
- data/lib/axlsx/workbook/worksheet/cell_serializer.rb +1 -1
- data/lib/axlsx/workbook/worksheet/col.rb +4 -4
- data/lib/axlsx/workbook/worksheet/data_validation.rb +26 -5
- data/lib/axlsx/workbook/worksheet/pivot_table.rb +55 -14
- data/lib/axlsx/workbook/worksheet/rich_text_run.rb +1 -1
- data/lib/axlsx/workbook/worksheet/worksheet.rb +68 -7
- data/lib/axlsx.rb +43 -10
- metadata +6 -253
- data/test/benchmark.rb +0 -72
- data/test/content_type/tc_content_type.rb +0 -76
- data/test/content_type/tc_default.rb +0 -16
- data/test/content_type/tc_override.rb +0 -14
- data/test/doc_props/tc_app.rb +0 -43
- data/test/doc_props/tc_core.rb +0 -42
- data/test/drawing/tc_area_chart.rb +0 -39
- data/test/drawing/tc_area_series.rb +0 -71
- data/test/drawing/tc_axes.rb +0 -8
- data/test/drawing/tc_axis.rb +0 -112
- data/test/drawing/tc_bar_3D_chart.rb +0 -86
- data/test/drawing/tc_bar_chart.rb +0 -86
- data/test/drawing/tc_bar_series.rb +0 -46
- data/test/drawing/tc_bubble_chart.rb +0 -44
- data/test/drawing/tc_bubble_series.rb +0 -21
- data/test/drawing/tc_cat_axis.rb +0 -31
- data/test/drawing/tc_cat_axis_data.rb +0 -27
- data/test/drawing/tc_chart.rb +0 -123
- data/test/drawing/tc_d_lbls.rb +0 -57
- data/test/drawing/tc_data_source.rb +0 -23
- data/test/drawing/tc_drawing.rb +0 -80
- data/test/drawing/tc_graphic_frame.rb +0 -27
- data/test/drawing/tc_hyperlink.rb +0 -64
- data/test/drawing/tc_line_3d_chart.rb +0 -47
- data/test/drawing/tc_line_chart.rb +0 -39
- data/test/drawing/tc_line_series.rb +0 -71
- data/test/drawing/tc_marker.rb +0 -44
- data/test/drawing/tc_named_axis_data.rb +0 -27
- data/test/drawing/tc_num_data.rb +0 -31
- data/test/drawing/tc_num_val.rb +0 -29
- data/test/drawing/tc_one_cell_anchor.rb +0 -66
- data/test/drawing/tc_pic.rb +0 -103
- data/test/drawing/tc_picture_locking.rb +0 -72
- data/test/drawing/tc_pie_3D_chart.rb +0 -28
- data/test/drawing/tc_pie_series.rb +0 -33
- data/test/drawing/tc_scaling.rb +0 -36
- data/test/drawing/tc_scatter_chart.rb +0 -48
- data/test/drawing/tc_scatter_series.rb +0 -56
- data/test/drawing/tc_ser_axis.rb +0 -31
- data/test/drawing/tc_series.rb +0 -23
- data/test/drawing/tc_series_title.rb +0 -54
- data/test/drawing/tc_str_data.rb +0 -18
- data/test/drawing/tc_str_val.rb +0 -30
- data/test/drawing/tc_title.rb +0 -70
- data/test/drawing/tc_two_cell_anchor.rb +0 -36
- data/test/drawing/tc_val_axis.rb +0 -24
- data/test/drawing/tc_view_3D.rb +0 -54
- data/test/drawing/tc_vml_drawing.rb +0 -25
- data/test/drawing/tc_vml_shape.rb +0 -106
- data/test/fixtures/image1.gif +0 -0
- data/test/fixtures/image1.jpeg +0 -0
- data/test/fixtures/image1.jpg +0 -0
- data/test/fixtures/image1.png +0 -0
- data/test/fixtures/image1_fake.jpg +0 -0
- data/test/profile.rb +0 -24
- data/test/rels/tc_relationship.rb +0 -52
- data/test/rels/tc_relationships.rb +0 -37
- data/test/stylesheet/tc_border.rb +0 -37
- data/test/stylesheet/tc_border_pr.rb +0 -32
- data/test/stylesheet/tc_cell_alignment.rb +0 -81
- data/test/stylesheet/tc_cell_protection.rb +0 -29
- data/test/stylesheet/tc_cell_style.rb +0 -57
- data/test/stylesheet/tc_color.rb +0 -43
- data/test/stylesheet/tc_dxf.rb +0 -81
- data/test/stylesheet/tc_fill.rb +0 -18
- data/test/stylesheet/tc_font.rb +0 -133
- data/test/stylesheet/tc_gradient_fill.rb +0 -72
- data/test/stylesheet/tc_gradient_stop.rb +0 -31
- data/test/stylesheet/tc_num_fmt.rb +0 -30
- data/test/stylesheet/tc_pattern_fill.rb +0 -43
- data/test/stylesheet/tc_styles.rb +0 -261
- data/test/stylesheet/tc_table_style.rb +0 -44
- data/test/stylesheet/tc_table_style_element.rb +0 -45
- data/test/stylesheet/tc_table_styles.rb +0 -29
- data/test/stylesheet/tc_xf.rb +0 -120
- data/test/tc_axlsx.rb +0 -109
- data/test/tc_helper.rb +0 -10
- data/test/tc_package.rb +0 -314
- data/test/util/tc_mime_type_utils.rb +0 -13
- data/test/util/tc_serialized_attributes.rb +0 -19
- data/test/util/tc_simple_typed_list.rb +0 -77
- data/test/util/tc_validators.rb +0 -210
- data/test/workbook/tc_defined_name.rb +0 -49
- data/test/workbook/tc_shared_strings_table.rb +0 -59
- data/test/workbook/tc_workbook.rb +0 -160
- data/test/workbook/tc_workbook_view.rb +0 -50
- data/test/workbook/worksheet/auto_filter/tc_auto_filter.rb +0 -38
- data/test/workbook/worksheet/auto_filter/tc_filter_column.rb +0 -76
- data/test/workbook/worksheet/auto_filter/tc_filters.rb +0 -50
- data/test/workbook/worksheet/tc_break.rb +0 -49
- data/test/workbook/worksheet/tc_cell.rb +0 -453
- data/test/workbook/worksheet/tc_cfvo.rb +0 -31
- data/test/workbook/worksheet/tc_col.rb +0 -93
- data/test/workbook/worksheet/tc_color_scale.rb +0 -58
- data/test/workbook/worksheet/tc_comment.rb +0 -72
- data/test/workbook/worksheet/tc_comments.rb +0 -57
- data/test/workbook/worksheet/tc_conditional_formatting.rb +0 -224
- data/test/workbook/worksheet/tc_data_bar.rb +0 -46
- data/test/workbook/worksheet/tc_data_validation.rb +0 -265
- data/test/workbook/worksheet/tc_date_time_converter.rb +0 -124
- data/test/workbook/worksheet/tc_header_footer.rb +0 -151
- data/test/workbook/worksheet/tc_icon_set.rb +0 -45
- data/test/workbook/worksheet/tc_outline_pr.rb +0 -19
- data/test/workbook/worksheet/tc_page_margins.rb +0 -97
- data/test/workbook/worksheet/tc_page_set_up_pr.rb +0 -15
- data/test/workbook/worksheet/tc_page_setup.rb +0 -143
- data/test/workbook/worksheet/tc_pane.rb +0 -54
- data/test/workbook/worksheet/tc_pivot_table.rb +0 -143
- data/test/workbook/worksheet/tc_pivot_table_cache_definition.rb +0 -62
- data/test/workbook/worksheet/tc_print_options.rb +0 -72
- data/test/workbook/worksheet/tc_protected_range.rb +0 -17
- data/test/workbook/worksheet/tc_rich_text.rb +0 -44
- data/test/workbook/worksheet/tc_rich_text_run.rb +0 -173
- data/test/workbook/worksheet/tc_row.rb +0 -160
- data/test/workbook/worksheet/tc_selection.rb +0 -55
- data/test/workbook/worksheet/tc_sheet_calc_pr.rb +0 -18
- data/test/workbook/worksheet/tc_sheet_format_pr.rb +0 -88
- data/test/workbook/worksheet/tc_sheet_pr.rb +0 -49
- data/test/workbook/worksheet/tc_sheet_protection.rb +0 -117
- data/test/workbook/worksheet/tc_sheet_view.rb +0 -214
- data/test/workbook/worksheet/tc_table.rb +0 -77
- data/test/workbook/worksheet/tc_table_style_info.rb +0 -53
- data/test/workbook/worksheet/tc_worksheet.rb +0 -601
- data/test/workbook/worksheet/tc_worksheet_hyperlink.rb +0 -55
data/lib/axlsx/util/constants.rb
CHANGED
@@ -274,6 +274,12 @@ module Axlsx
|
|
274
274
|
# cellXfs id for default date styling
|
275
275
|
STYLE_DATE = 2
|
276
276
|
|
277
|
+
# worksheet maximum name length
|
278
|
+
WORKSHEET_MAX_NAME_LENGTH = 31
|
279
|
+
|
280
|
+
# worksheet name forbidden characters
|
281
|
+
WORKSHEET_NAME_FORBIDDEN_CHARS = '[]*/\?:'.chars.freeze
|
282
|
+
|
277
283
|
# error messages RestrictionValidor
|
278
284
|
ERR_RESTRICTION = "Invalid Data: %s. %s must be one of %s.".freeze
|
279
285
|
|
@@ -286,8 +292,11 @@ module Axlsx
|
|
286
292
|
# error message for RangeValidator
|
287
293
|
ERR_RANGE = "Invalid Data. %s must be between %s and %s, (inclusive:%s) you gave: %s".freeze
|
288
294
|
|
295
|
+
# error message for sheets that use explicit empty string name
|
296
|
+
ERR_SHEET_NAME_EMPTY = "Your worksheet name is empty. Worksheet name can't be empty. Please assign name of your sheet or don't use name option at all.".freeze
|
297
|
+
|
289
298
|
# error message for sheets that use a name which is longer than 31 bytes
|
290
|
-
ERR_SHEET_NAME_TOO_LONG = "Your worksheet name '%s' is too long. Worksheet names must be
|
299
|
+
ERR_SHEET_NAME_TOO_LONG = "Your worksheet name '%s' is too long. Worksheet names must be #{WORKSHEET_MAX_NAME_LENGTH} characters (bytes) or less".freeze
|
291
300
|
|
292
301
|
# error message for sheets that use a name which include invalid characters
|
293
302
|
ERR_SHEET_NAME_CHARACTER_FORBIDDEN = "Your worksheet name '%s' contains a character which is not allowed by MS Excel and will cause repair warnings. Please change the name of your sheet.".freeze
|
@@ -307,6 +316,12 @@ module Axlsx
|
|
307
316
|
# error message for non 'integerish' value
|
308
317
|
ERR_INTEGERISH = "You value must be, or be castable via to_i, an Integer. You provided %s".freeze
|
309
318
|
|
319
|
+
# error message for invalid cell reference
|
320
|
+
ERR_CELL_REFERENCE_INVALID = "Invalid cell definition `%s`".freeze
|
321
|
+
|
322
|
+
# error message for cell reference with last cell missing
|
323
|
+
ERR_CELL_REFERENCE_MISSING_CELL = "Missing cell `%s` for the specified range `%s`".freeze
|
324
|
+
|
310
325
|
# Regex to match forbidden control characters
|
311
326
|
# The following will be automatically stripped from worksheets.
|
312
327
|
#
|
@@ -61,7 +61,7 @@ module Axlsx
|
|
61
61
|
# seraialized_attributes and are not nil.
|
62
62
|
# This requires ruby 1.9.3 or higher
|
63
63
|
def declared_attributes
|
64
|
-
|
64
|
+
Axlsx.instance_values_for(self).select do |key, value|
|
65
65
|
value != nil && self.class.xml_attributes.include?(key.to_sym)
|
66
66
|
end
|
67
67
|
end
|
@@ -75,7 +75,7 @@ module Axlsx
|
|
75
75
|
# @return [String] The serialized output.
|
76
76
|
def serialized_element_attributes(str='', additional_attributes=[], &block)
|
77
77
|
attrs = self.class.xml_element_attributes + additional_attributes
|
78
|
-
values =
|
78
|
+
values = Axlsx.instance_values_for(self)
|
79
79
|
attrs.each do |attribute_name|
|
80
80
|
value = values[attribute_name.to_s]
|
81
81
|
next if value.nil?
|
data/lib/axlsx/util/storage.rb
CHANGED
@@ -122,15 +122,15 @@ module Axlsx
|
|
122
122
|
|
123
123
|
# Creates a new storage object.
|
124
124
|
# @param [String] name the name of the storage
|
125
|
-
# @option options [Integer] color
|
126
|
-
# @option options [Integer] type
|
127
|
-
# @option options [String] data
|
128
|
-
# @option options [Integer] left
|
129
|
-
# @option options [Integer] right
|
130
|
-
# @option options [Integer] child
|
131
|
-
# @option options [Integer] created
|
132
|
-
# @option options [Integer] modified
|
133
|
-
# @option options [Integer] sector
|
125
|
+
# @option options [Integer] color (black)
|
126
|
+
# @option options [Integer] type (storage)
|
127
|
+
# @option options [String] data
|
128
|
+
# @option options [Integer] left (-1)
|
129
|
+
# @option options [Integer] right (-1)
|
130
|
+
# @option options [Integer] child (-1)
|
131
|
+
# @option options [Integer] created (0)
|
132
|
+
# @option options [Integer] modified (0)
|
133
|
+
# @option options [Integer] sector (0)
|
134
134
|
def initialize(name, options= {})
|
135
135
|
@left = @right = @child = -1
|
136
136
|
@sector = @size = @created = @modified = 0
|
data/lib/axlsx/version.rb
CHANGED
@@ -85,6 +85,9 @@ require 'axlsx/workbook/worksheet/selection.rb'
|
|
85
85
|
# *workbookPr is only supported to the extend of date1904
|
86
86
|
class Workbook
|
87
87
|
|
88
|
+
BOLD_FONT_MULTIPLIER = 1.5
|
89
|
+
FONT_SCALE_DIVISOR = 10.0
|
90
|
+
|
88
91
|
# When true, the Package will be generated with a shared string table. This may be required by some OOXML processors that do not
|
89
92
|
# adhere to the ECMA specification that dictates string may be inline in the sheet.
|
90
93
|
# Using this option will increase the time required to serialize the document as every string in every cell must be analzed and referenced.
|
@@ -184,6 +187,36 @@ require 'axlsx/workbook/worksheet/selection.rb'
|
|
184
187
|
@styles
|
185
188
|
end
|
186
189
|
|
190
|
+
# An array that holds all cells with styles
|
191
|
+
# @return Set
|
192
|
+
def styled_cells
|
193
|
+
@styled_cells ||= Set.new
|
194
|
+
end
|
195
|
+
|
196
|
+
# Are the styles added with workbook.add_styles applied yet
|
197
|
+
# @return Boolean
|
198
|
+
attr_accessor :styles_applied
|
199
|
+
|
200
|
+
# A helper to apply styles that were added using `worksheet.add_style`
|
201
|
+
# @return [Boolean]
|
202
|
+
def apply_styles
|
203
|
+
return false if !styled_cells
|
204
|
+
|
205
|
+
styled_cells.each do |cell|
|
206
|
+
current_style = styles.style_index[cell.style]
|
207
|
+
|
208
|
+
if current_style
|
209
|
+
new_style = Axlsx.hash_deep_merge(current_style, cell.raw_style)
|
210
|
+
else
|
211
|
+
new_style = cell.raw_style
|
212
|
+
end
|
213
|
+
|
214
|
+
cell.style = styles.add_style(new_style)
|
215
|
+
end
|
216
|
+
|
217
|
+
self.styles_applied = true
|
218
|
+
end
|
219
|
+
|
187
220
|
|
188
221
|
# Indicates if the epoc date for serialization should be 1904. If false, 1900 is used.
|
189
222
|
@@date1904 = false
|
@@ -213,6 +246,8 @@ require 'axlsx/workbook/worksheet/selection.rb'
|
|
213
246
|
|
214
247
|
|
215
248
|
@use_autowidth = true
|
249
|
+
@bold_font_multiplier = BOLD_FONT_MULTIPLIER
|
250
|
+
@font_scale_divisor = FONT_SCALE_DIVISOR
|
216
251
|
|
217
252
|
self.date1904= !options[:date1904].nil? && options[:date1904]
|
218
253
|
yield self if block_given?
|
@@ -243,6 +278,26 @@ require 'axlsx/workbook/worksheet/selection.rb'
|
|
243
278
|
# see @use_autowidth
|
244
279
|
def use_autowidth=(v=true) Axlsx::validate_boolean v; @use_autowidth = v; end
|
245
280
|
|
281
|
+
# Font size of bold fonts is multiplied with this
|
282
|
+
# Used for automatic calculation of cell widths with bold text
|
283
|
+
# @return [Float]
|
284
|
+
attr_reader :bold_font_multiplier
|
285
|
+
|
286
|
+
def bold_font_multiplier=(v)
|
287
|
+
Axlsx::validate_float v
|
288
|
+
@bold_font_multiplier = v
|
289
|
+
end
|
290
|
+
|
291
|
+
# Font scale is calculated with this value (font_size / font_scale_divisor)
|
292
|
+
# Used for automatic calculation of cell widths
|
293
|
+
# @return [Float]
|
294
|
+
attr_reader :font_scale_divisor
|
295
|
+
|
296
|
+
def font_scale_divisor=(v)
|
297
|
+
Axlsx::validate_float v
|
298
|
+
@font_scale_divisor = v
|
299
|
+
end
|
300
|
+
|
246
301
|
# inserts a worksheet into this workbook at the position specified.
|
247
302
|
# It the index specified is out of range, the worksheet will be added to the end of the
|
248
303
|
# worksheets collection
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Axlsx
|
4
|
+
class BorderCreator
|
5
|
+
attr_reader :worksheet, :cells, :edges, :width, :color
|
6
|
+
|
7
|
+
def initialize(worksheet, cells, args)
|
8
|
+
@worksheet = worksheet
|
9
|
+
@cells = cells
|
10
|
+
if args.is_a?(Hash)
|
11
|
+
@edges = args[:edges] || Axlsx::Border::EDGES
|
12
|
+
@width = args[:style] || :thin
|
13
|
+
@color = args[:color] || '000000'
|
14
|
+
else
|
15
|
+
@edges = args || Axlsx::Border::Edges
|
16
|
+
@width = :thin
|
17
|
+
@color = '000000'
|
18
|
+
end
|
19
|
+
|
20
|
+
if @edges == :all
|
21
|
+
@edges = Axlsx::Border::EDGES
|
22
|
+
elsif @edges.is_a?(Array)
|
23
|
+
@edges = (@edges.map(&:to_sym).uniq & Axlsx::Border::EDGES)
|
24
|
+
else
|
25
|
+
@edges = []
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def draw
|
30
|
+
@edges.each do |edge|
|
31
|
+
worksheet.add_style(
|
32
|
+
border_cells[edge],
|
33
|
+
{
|
34
|
+
border: {style: @width, color: @color, edges: [edge]}
|
35
|
+
}
|
36
|
+
)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def border_cells
|
43
|
+
{
|
44
|
+
top: "#{first_cell}:#{last_col}#{first_row}",
|
45
|
+
right: "#{last_col}#{first_row}:#{last_cell}",
|
46
|
+
bottom: "#{first_col}#{last_row}:#{last_cell}",
|
47
|
+
left: "#{first_cell}:#{first_col}#{last_row}",
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
def first_cell
|
52
|
+
@first_cell ||= cells.first.r
|
53
|
+
end
|
54
|
+
|
55
|
+
def last_cell
|
56
|
+
@last_cell ||= cells.last.r
|
57
|
+
end
|
58
|
+
|
59
|
+
def first_row
|
60
|
+
@first_row ||= first_cell.scan(/\d+/).first
|
61
|
+
end
|
62
|
+
|
63
|
+
def first_col
|
64
|
+
@first_col ||= first_cell.scan(/\D+/).first
|
65
|
+
end
|
66
|
+
|
67
|
+
def last_row
|
68
|
+
@last_row ||= last_cell.scan(/\d+/).first
|
69
|
+
end
|
70
|
+
|
71
|
+
def last_col
|
72
|
+
@last_col ||= last_cell.scan(/\D+/).first
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
@@ -82,6 +82,32 @@ module Axlsx
|
|
82
82
|
defined?(@style) ? @style : 0
|
83
83
|
end
|
84
84
|
|
85
|
+
attr_accessor :raw_style
|
86
|
+
|
87
|
+
# The index of the cellXfs item to be applied to this cell.
|
88
|
+
# @param [Hash] styles
|
89
|
+
# @see Axlsx::Styles
|
90
|
+
def add_style(style)
|
91
|
+
self.raw_style ||= {}
|
92
|
+
|
93
|
+
new_style = Axlsx.hash_deep_merge(raw_style, style)
|
94
|
+
|
95
|
+
all_edges = [:top, :right, :bottom, :left]
|
96
|
+
|
97
|
+
if !raw_style[:border].nil? && !style[:border].nil?
|
98
|
+
border_at = (raw_style[:border][:edges] || all_edges) + (style[:border][:edges] || all_edges)
|
99
|
+
new_style[:border][:edges] = border_at.uniq.sort
|
100
|
+
elsif !style[:border].nil?
|
101
|
+
new_style[:border] = style[:border]
|
102
|
+
end
|
103
|
+
|
104
|
+
self.raw_style = new_style
|
105
|
+
|
106
|
+
wb = row.worksheet.workbook
|
107
|
+
|
108
|
+
wb.styled_cells << self
|
109
|
+
end
|
110
|
+
|
85
111
|
# The row this cell belongs to.
|
86
112
|
# @return [Row]
|
87
113
|
attr_reader :row
|
@@ -409,7 +435,7 @@ module Axlsx
|
|
409
435
|
# This is still not perfect...
|
410
436
|
# - scaling is not linear as font sizes increase
|
411
437
|
def string_width(string, font_size)
|
412
|
-
font_scale = font_size /
|
438
|
+
font_scale = font_size / row.worksheet.workbook.font_scale_divisor
|
413
439
|
(string.to_s.size + 3) * font_scale
|
414
440
|
end
|
415
441
|
|
@@ -418,8 +444,9 @@ module Axlsx
|
|
418
444
|
# imagemagick and loading metrics for every character.
|
419
445
|
def font_size
|
420
446
|
return sz if sz
|
447
|
+
|
421
448
|
font = styles.fonts[styles.cellXfs[style].fontId] || styles.fonts[0]
|
422
|
-
|
449
|
+
font.b || (defined?(@b) && @b) ? (font.sz * row.worksheet.workbook.bold_font_multiplier) : font.sz
|
423
450
|
end
|
424
451
|
|
425
452
|
# Utility method for setting inline style attributes
|
@@ -22,7 +22,7 @@ module Axlsx
|
|
22
22
|
def run_xml_string(cell, str = '')
|
23
23
|
if cell.is_text_run?
|
24
24
|
valid = RichTextRun::INLINE_STYLES - [:value, :type]
|
25
|
-
data = Hash[cell.
|
25
|
+
data = Hash[Axlsx.instance_values_for(cell).map{ |k, v| [k.to_sym, v] }]
|
26
26
|
data = data.select { |key, value| valid.include?(key) && !value.nil? }
|
27
27
|
RichText.new(cell.value.to_s, data).to_xml_string(str)
|
28
28
|
elsif cell.contains_rich_text?
|
@@ -125,12 +125,12 @@ module Axlsx
|
|
125
125
|
# to this value and the cell's attributes are ignored.
|
126
126
|
# @param [Boolean] use_autowidth If this is false, the cell's
|
127
127
|
# autowidth value will be ignored.
|
128
|
-
def update_width(cell, fixed_width=nil, use_autowidth=true)
|
128
|
+
def update_width(cell, fixed_width = nil, use_autowidth = true)
|
129
129
|
if fixed_width.is_a? Numeric
|
130
|
-
|
130
|
+
self.width = fixed_width
|
131
131
|
elsif use_autowidth
|
132
|
-
|
133
|
-
|
132
|
+
cell_width = cell.autowidth
|
133
|
+
self.width = cell_width unless (width || 0) > (cell_width || 0)
|
134
134
|
end
|
135
135
|
end
|
136
136
|
|
@@ -13,11 +13,12 @@ module Axlsx
|
|
13
13
|
# @option options [Boolean] allowBlank - A boolean value indicating whether the data validation allows the use of empty or blank entries.
|
14
14
|
# @option options [String] error - Message text of error alert.
|
15
15
|
# @option options [Symbol] errorStyle - The style of error alert used for this data validation.
|
16
|
-
# @option options [String] errorTitle -
|
16
|
+
# @option options [String] errorTitle - Title bar text of error alert.
|
17
17
|
# @option options [Symbol] operator - The relational operator used with this data validation.
|
18
18
|
# @option options [String] prompt - Message text of input prompt.
|
19
19
|
# @option options [String] promptTitle - Title bar text of input prompt.
|
20
|
-
# @option options [Boolean] showDropDown - A boolean value indicating whether to display a dropdown combo box for a list type data validation
|
20
|
+
# @option options [Boolean] showDropDown - A boolean value indicating whether to display a dropdown combo box for a list type data validation. Be careful: It has an inverted logic, false shows the dropdown list! You should use hideDropDown instead.
|
21
|
+
# @option options [Boolean] hideDropDown - A boolean value indicating whether to hide the dropdown combo box for a list type data validation. Defaults to `false` (meaning the dropdown is visible by default).
|
21
22
|
# @option options [Boolean] showErrorMessage - A boolean value indicating whether to display the error alert message when an invalid value has been entered, according to the criteria specified.
|
22
23
|
# @option options [Boolean] showInputMessage - A boolean value indicating whether to display the input prompt message.
|
23
24
|
# @option options [String] sqref - Range over which data validation is applied, in "A1:B2" format.
|
@@ -121,13 +122,22 @@ module Axlsx
|
|
121
122
|
|
122
123
|
# Show drop down
|
123
124
|
# A boolean value indicating whether to display a dropdown combo box for a list type data
|
124
|
-
# validation. Be careful: false shows the dropdown list!
|
125
|
+
# validation. Be careful: It has an inverted logic, false shows the dropdown list!
|
125
126
|
# Available for type list
|
126
127
|
# @see type
|
127
128
|
# @return [Boolean]
|
128
129
|
# default false
|
129
130
|
attr_reader :showDropDown
|
130
131
|
|
132
|
+
# Hide drop down
|
133
|
+
# A boolean value indicating whether to hide a dropdown combo box for a list type data
|
134
|
+
# validation. Defaults to `false` (meaning the dropdown is visible by default).
|
135
|
+
# Available for type list
|
136
|
+
# @see type
|
137
|
+
# @return [Boolean]
|
138
|
+
# default false
|
139
|
+
alias :hideDropDown :showDropDown
|
140
|
+
|
131
141
|
# Show error message
|
132
142
|
# A boolean value indicating whether to display the error alert message when an invalid
|
133
143
|
# value has been entered, according to the criteria specified.
|
@@ -195,7 +205,18 @@ module Axlsx
|
|
195
205
|
def promptTitle=(v); Axlsx::validate_string(v); @promptTitle = v end
|
196
206
|
|
197
207
|
# @see showDropDown
|
198
|
-
def showDropDown=(v)
|
208
|
+
def showDropDown=(v)
|
209
|
+
warn 'The `showDropDown` has an inverted logic, false shows the dropdown list! You should use `hideDropDown` instead.'
|
210
|
+
Axlsx::validate_boolean(v)
|
211
|
+
@showDropDown = v
|
212
|
+
end
|
213
|
+
|
214
|
+
# @see hideDropDown
|
215
|
+
def hideDropDown=(v)
|
216
|
+
Axlsx::validate_boolean(v)
|
217
|
+
# It's just an alias for the showDropDown attribute, hideDropDown should set the value of the original showDropDown.
|
218
|
+
@showDropDown = v
|
219
|
+
end
|
199
220
|
|
200
221
|
# @see showErrorMessage
|
201
222
|
def showErrorMessage=(v); Axlsx::validate_boolean(v); @showErrorMessage = v end
|
@@ -216,7 +237,7 @@ module Axlsx
|
|
216
237
|
valid_attributes = get_valid_attributes
|
217
238
|
|
218
239
|
str << '<dataValidation '
|
219
|
-
str <<
|
240
|
+
str << Axlsx.instance_values_for(self).map do |key, value|
|
220
241
|
'' << key << '="' << Axlsx.booleanize(value).to_s << '"' if (valid_attributes.include?(key.to_sym) && !CHILD_ELEMENTS.include?(key.to_sym))
|
221
242
|
end.join(' ')
|
222
243
|
str << '>'
|
@@ -26,17 +26,33 @@ module Axlsx
|
|
26
26
|
@pages = []
|
27
27
|
@subtotal = nil
|
28
28
|
@no_subtotals_on_headers = []
|
29
|
+
@sort_on_headers = {}
|
29
30
|
@style_info = {}
|
30
31
|
parse_options options
|
31
32
|
yield self if block_given?
|
32
33
|
end
|
33
34
|
|
34
|
-
# Defines the headers in which subtotals are not to be included
|
35
|
-
# @return[Array]
|
35
|
+
# Defines the headers in which subtotals are not to be included.
|
36
|
+
# @return [Array]
|
36
37
|
attr_accessor :no_subtotals_on_headers
|
37
38
|
|
39
|
+
# Defines the headers in which sort is applied.
|
40
|
+
# Can be an array of headers to sort ascending by default, or a hash for specific control
|
41
|
+
# (with headers as keys, `:ascending` or `:descending` as values).
|
42
|
+
#
|
43
|
+
# Examples: `["year", "month"]` or `{"year" => :descending, "month" => :descending}`
|
44
|
+
# @return [Hash]
|
45
|
+
attr_reader :sort_on_headers
|
46
|
+
|
47
|
+
# (see #sort_on_headers)
|
48
|
+
def sort_on_headers=(headers)
|
49
|
+
headers ||= {}
|
50
|
+
headers = Hash[*headers.map { |h| [h, :ascending] }.flatten] if headers.is_a?(Array)
|
51
|
+
@sort_on_headers = headers
|
52
|
+
end
|
53
|
+
|
38
54
|
# Style info for the pivot table
|
39
|
-
# @return[Hash]
|
55
|
+
# @return [Hash]
|
40
56
|
attr_accessor :style_info
|
41
57
|
|
42
58
|
# The reference to the table data
|
@@ -173,12 +189,18 @@ module Axlsx
|
|
173
189
|
# @return [String]
|
174
190
|
def to_xml_string(str = '')
|
175
191
|
str << '<?xml version="1.0" encoding="UTF-8"?>'
|
176
|
-
|
192
|
+
|
193
|
+
str << ('<pivotTableDefinition xmlns="' << XML_NS << '" name="' << name << '" cacheId="' << cache_definition.cache_id.to_s << '"' << (data.size <= 1 ? ' dataOnRows="1"' : '') << ' applyNumberFormats="0" applyBorderFormats="0" applyFontFormats="0" applyPatternFormats="0" applyAlignmentFormats="0" applyWidthHeightFormats="1" dataCaption="Data" showMultipleLabel="0" showMemberPropertyTips="0" useAutoFormatting="1" indent="0" compact="0" compactData="0" gridDropZones="1" multipleFieldFilters="0">')
|
194
|
+
|
177
195
|
str << ('<location firstDataCol="1" firstDataRow="1" firstHeaderRow="1" ref="' << ref << '"/>')
|
178
196
|
str << ('<pivotFields count="' << header_cells_count.to_s << '">')
|
197
|
+
|
179
198
|
header_cell_values.each do |cell_value|
|
180
|
-
|
199
|
+
subtotal = !no_subtotals_on_headers.include?(cell_value)
|
200
|
+
sorttype = sort_on_headers[cell_value]
|
201
|
+
str << pivot_field_for(cell_value, subtotal, sorttype)
|
181
202
|
end
|
203
|
+
|
182
204
|
str << '</pivotFields>'
|
183
205
|
if rows.empty?
|
184
206
|
str << '<rowFields count="1"><field x="-2"/></rowFields>'
|
@@ -196,7 +218,17 @@ module Axlsx
|
|
196
218
|
str << '</rowItems>'
|
197
219
|
end
|
198
220
|
if columns.empty?
|
199
|
-
|
221
|
+
if data.size > 1
|
222
|
+
str << '<colFields count="1"><field x="-2"/></colFields>'
|
223
|
+
str << "<colItems count=\"#{data.size}\">"
|
224
|
+
str << '<i><x/></i>'
|
225
|
+
data[1..-1].each_with_index do |datum_value,i|
|
226
|
+
str << "<i i=\"#{i + 1}\"><x v=\"#{i + 1}\"/></i>"
|
227
|
+
end
|
228
|
+
str << '</colItems>'
|
229
|
+
else
|
230
|
+
str << '<colItems count="1"><i/></colItems>'
|
231
|
+
end
|
200
232
|
else
|
201
233
|
str << ('<colFields count="' << columns.size.to_s << '">')
|
202
234
|
columns.each do |column_value|
|
@@ -265,22 +297,31 @@ module Axlsx
|
|
265
297
|
|
266
298
|
private
|
267
299
|
|
268
|
-
def pivot_field_for(cell_ref, subtotal
|
300
|
+
def pivot_field_for(cell_ref, subtotal, sorttype)
|
301
|
+
attributes = %w[compact="0" outline="0" subtotalTop="0" showAll="0" includeNewItemsInFilter="1"]
|
302
|
+
items_tag = '<items count="1"><item t="default"/></items>'
|
303
|
+
include_items_tag = false
|
304
|
+
|
269
305
|
if rows.include? cell_ref
|
306
|
+
attributes << 'axis="axisRow"'
|
307
|
+
attributes << "sortType=\"#{sorttype == :descending ? 'descending' : 'ascending'}\"" if sorttype
|
270
308
|
if subtotal
|
271
|
-
|
309
|
+
include_items_tag = true
|
272
310
|
else
|
273
|
-
|
311
|
+
attributes << 'defaultSubtotal="0"'
|
274
312
|
end
|
275
313
|
elsif columns.include? cell_ref
|
276
|
-
'
|
314
|
+
attributes << 'axis="axisCol"'
|
315
|
+
attributes << "sortType=\"#{sorttype == :descending ? 'descending' : 'ascending'}\"" if sorttype
|
316
|
+
include_items_tag = true
|
277
317
|
elsif pages.include? cell_ref
|
278
|
-
'
|
318
|
+
attributes << 'axis="axisPage"'
|
319
|
+
include_items_tag = true
|
279
320
|
elsif data_refs.include? cell_ref
|
280
|
-
'
|
281
|
-
else
|
282
|
-
'<pivotField compact="0" outline="0" subtotalTop="0" showAll="0" includeNewItemsInFilter="1"></pivotField>'
|
321
|
+
attributes << 'dataField="1"'
|
283
322
|
end
|
323
|
+
|
324
|
+
"<pivotField #{attributes.join(' ')}>#{include_items_tag ? items_tag : nil}</pivotField>"
|
284
325
|
end
|
285
326
|
|
286
327
|
def data_refs
|
@@ -190,7 +190,7 @@ module Axlsx
|
|
190
190
|
# @return [String]
|
191
191
|
def to_xml_string(str = '')
|
192
192
|
valid = RichTextRun::INLINE_STYLES
|
193
|
-
data = Hash[self.
|
193
|
+
data = Hash[Axlsx.instance_values_for(self).map{ |k, v| [k.to_sym, v] }]
|
194
194
|
data = data.select { |key, value| valid.include?(key) && !value.nil? }
|
195
195
|
|
196
196
|
str << '<r><rPr>'
|