axlsx 1.1.5 → 1.1.6
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/README.md +26 -7
- data/Rakefile +2 -1
- data/examples/chart_colors.xlsx +0 -0
- data/examples/data_validation.rb +50 -0
- data/examples/example.xlsx +0 -0
- data/examples/example_streamed.xlsx +0 -0
- data/examples/examples_saved.xlsx +0 -0
- data/examples/fish.xlsx +0 -0
- data/examples/no-use_autowidth.xlsx +0 -0
- data/examples/pareto.rb +28 -0
- data/examples/pareto.xlsx +0 -0
- data/examples/pie_chart.rb +16 -0
- data/examples/pie_chart.xlsx +0 -0
- data/examples/pie_chart_saved.xlsx +0 -0
- data/examples/shared_strings_example.xlsx +0 -0
- data/examples/sheet_protection.rb +10 -0
- data/examples/sheet_protection.xlsx +0 -0
- data/examples/two_cell_anchor_image.rb +11 -0
- data/examples/two_cell_anchor_image.xlsx +0 -0
- data/examples/~$pie_chart_saved.xlsx +0 -0
- data/lib/axlsx.rb +7 -0
- data/lib/axlsx/content_type/default.rb +15 -9
- data/lib/axlsx/content_type/override.rb +10 -6
- data/lib/axlsx/doc_props/app.rb +152 -99
- data/lib/axlsx/drawing/axis.rb +30 -23
- data/lib/axlsx/drawing/bar_series.rb +1 -1
- data/lib/axlsx/drawing/drawing.rb +7 -2
- data/lib/axlsx/drawing/pic.rb +44 -4
- data/lib/axlsx/drawing/two_cell_anchor.rb +6 -1
- data/lib/axlsx/drawing/vml_shape.rb +2 -5
- data/lib/axlsx/rels/relationships.rb +1 -1
- data/lib/axlsx/stylesheet/table_style.rb +3 -3
- data/lib/axlsx/util/simple_typed_list.rb +0 -13
- data/lib/axlsx/util/validators.rb +21 -0
- data/lib/axlsx/version.rb +1 -1
- data/lib/axlsx/workbook/workbook.rb +2 -0
- data/lib/axlsx/workbook/worksheet/cell.rb +3 -4
- data/lib/axlsx/workbook/worksheet/comment.rb +3 -9
- data/lib/axlsx/workbook/worksheet/data_validation.rb +245 -0
- data/lib/axlsx/workbook/worksheet/page_setup.rb +17 -3
- data/lib/axlsx/workbook/worksheet/row.rb +34 -18
- data/lib/axlsx/workbook/worksheet/sheet_protection.rb +224 -0
- data/lib/axlsx/workbook/worksheet/table.rb +2 -2
- data/lib/axlsx/workbook/worksheet/worksheet.rb +57 -22
- data/test/doc_props/tc_app.rb +31 -1
- data/test/drawing/tc_axis.rb +12 -2
- data/test/drawing/tc_chart.rb +21 -3
- data/test/drawing/tc_drawing.rb +6 -1
- data/test/drawing/tc_hyperlink.rb +0 -5
- data/test/drawing/tc_pic.rb +22 -2
- data/test/drawing/tc_scatter_chart.rb +6 -1
- data/test/drawing/tc_two_cell_anchor.rb +1 -2
- data/test/stylesheet/tc_styles.rb +3 -4
- data/test/stylesheet/tc_table_style.rb +8 -0
- data/test/stylesheet/tc_table_style_element.rb +10 -1
- data/test/tc_package.rb +43 -15
- data/test/util/tc_simple_typed_list.rb +13 -0
- data/test/util/tc_validators.rb +7 -7
- data/test/workbook/worksheet/table/tc_table.rb +3 -3
- data/test/workbook/worksheet/tc_cell.rb +15 -6
- data/test/workbook/worksheet/tc_col.rb +9 -0
- data/test/workbook/worksheet/tc_comment.rb +8 -7
- data/test/workbook/worksheet/tc_comments.rb +8 -1
- data/test/workbook/worksheet/tc_conditional_formatting.rb +44 -0
- data/test/workbook/worksheet/tc_data_bar.rb +1 -1
- data/test/workbook/worksheet/tc_data_validation.rb +265 -0
- data/test/workbook/worksheet/tc_page_setup.rb +22 -4
- data/test/workbook/worksheet/tc_row.rb +14 -2
- data/test/workbook/worksheet/tc_sheet_protection.rb +117 -0
- data/test/workbook/worksheet/tc_worksheet.rb +29 -4
- metadata +31 -10
data/lib/axlsx/drawing/axis.rb
CHANGED
@@ -5,11 +5,13 @@ module Axlsx
|
|
5
5
|
|
6
6
|
# the id of the axis.
|
7
7
|
# @return [Integer]
|
8
|
-
attr_reader :
|
8
|
+
attr_reader :ax_id
|
9
|
+
alias :axID :ax_id
|
9
10
|
|
10
11
|
# The perpendicular axis
|
11
12
|
# @return [Integer]
|
12
|
-
attr_reader :
|
13
|
+
attr_reader :cross_ax
|
14
|
+
alias :crossAx :cross_ax
|
13
15
|
|
14
16
|
# The scaling of the axis
|
15
17
|
# @see Scaling
|
@@ -19,12 +21,14 @@ module Axlsx
|
|
19
21
|
# The position of the axis
|
20
22
|
# must be one of [:l, :r, :t, :b]
|
21
23
|
# @return [Symbol]
|
22
|
-
attr_reader :
|
24
|
+
attr_reader :ax_pos
|
25
|
+
alias :axPos :ax_pos
|
23
26
|
|
24
27
|
# the position of the tick labels
|
25
28
|
# must be one of [:nextTo, :high, :low]
|
26
29
|
# @return [Symbol]
|
27
|
-
attr_reader :
|
30
|
+
attr_reader :tick_lbl_pos
|
31
|
+
alias :tickLblPos :tick_lbl_pos
|
28
32
|
|
29
33
|
# The number format format code for this axis
|
30
34
|
# default :General
|
@@ -49,22 +53,22 @@ module Axlsx
|
|
49
53
|
attr_reader :delete
|
50
54
|
|
51
55
|
# Creates an Axis object
|
52
|
-
# @param [Integer]
|
53
|
-
# @param [Integer]
|
54
|
-
# @option options [Symbol]
|
56
|
+
# @param [Integer] ax_id the id of this axis
|
57
|
+
# @param [Integer] cross_ax the id of the perpendicular axis
|
58
|
+
# @option options [Symbol] ax_pos
|
55
59
|
# @option options [Symbol] crosses
|
56
|
-
# @option options [Symbol]
|
57
|
-
# @raise [ArgumentError] If
|
58
|
-
def initialize(
|
59
|
-
Axlsx::validate_unsigned_int(
|
60
|
-
Axlsx::validate_unsigned_int(
|
61
|
-
@
|
62
|
-
@
|
60
|
+
# @option options [Symbol] tick_lbl_pos
|
61
|
+
# @raise [ArgumentError] If axi_id or cross_ax are not unsigned integers
|
62
|
+
def initialize(ax_id, cross_ax, options={})
|
63
|
+
Axlsx::validate_unsigned_int(ax_id)
|
64
|
+
Axlsx::validate_unsigned_int(cross_ax)
|
65
|
+
@ax_id = ax_id
|
66
|
+
@cross_ax = cross_ax
|
63
67
|
@format_code = "General"
|
64
68
|
@delete = @label_rotation = 0
|
65
69
|
@scaling = Scaling.new(:orientation=>:minMax)
|
66
|
-
self.
|
67
|
-
self.
|
70
|
+
self.ax_pos = :b
|
71
|
+
self.tick_lbl_pos = :nextTo
|
68
72
|
self.format_code = "General"
|
69
73
|
self.crosses = :autoZero
|
70
74
|
self.gridlines = true
|
@@ -72,13 +76,16 @@ module Axlsx
|
|
72
76
|
self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
|
73
77
|
end
|
74
78
|
end
|
79
|
+
|
75
80
|
# The position of the axis
|
76
81
|
# must be one of [:l, :r, :t, :b]
|
77
|
-
def
|
82
|
+
def ax_pos=(v) RestrictionValidator.validate "#{self.class}.ax_pos", [:l, :r, :b, :t], v; @ax_pos = v; end
|
83
|
+
alias :axPos= :ax_pos=
|
78
84
|
|
79
85
|
# the position of the tick labels
|
80
86
|
# must be one of [:nextTo, :high, :low1]
|
81
|
-
def
|
87
|
+
def tick_lbl_pos=(v) RestrictionValidator.validate "#{self.class}.tick_lbl_pos", [:nextTo, :high, :low], v; @tick_lbl_pos = v; end
|
88
|
+
alias :tickLblPos= :tick_lbl_pos=
|
82
89
|
|
83
90
|
# The number format format code for this axis
|
84
91
|
# default :General
|
@@ -111,12 +118,12 @@ module Axlsx
|
|
111
118
|
# @param [String] str
|
112
119
|
# @return [String]
|
113
120
|
def to_xml_string(str = '')
|
114
|
-
str << '<c:axId val="' << @
|
121
|
+
str << '<c:axId val="' << @ax_id.to_s << '"/>'
|
115
122
|
@scaling.to_xml_string str
|
116
123
|
str << '<c:delete val="'<< @delete.to_s << '"/>'
|
117
|
-
str << '<c:axPos val="' << @
|
124
|
+
str << '<c:axPos val="' << @ax_pos.to_s << '"/>'
|
118
125
|
str << '<c:majorGridlines>'
|
119
|
-
if
|
126
|
+
if gridlines == false
|
120
127
|
str << '<c:spPr>'
|
121
128
|
str << '<a:ln>'
|
122
129
|
str << '<a:noFill/>'
|
@@ -127,10 +134,10 @@ module Axlsx
|
|
127
134
|
str << '<c:numFmt formatCode="' << @format_code << '" sourceLinked="1"/>'
|
128
135
|
str << '<c:majorTickMark val="none"/>'
|
129
136
|
str << '<c:minorTickMark val="none"/>'
|
130
|
-
str << '<c:tickLblPos val="' << @
|
137
|
+
str << '<c:tickLblPos val="' << @tick_lbl_pos.to_s << '"/>'
|
131
138
|
# some potential value in implementing this in full. Very detailed!
|
132
139
|
str << '<c:txPr><a:bodyPr rot="' << @label_rotation.to_s << '"/><a:lstStyle/><a:p><a:pPr><a:defRPr/></a:pPr><a:endParaRPr/></a:p></c:txPr>'
|
133
|
-
str << '<c:crossAx val="' << @
|
140
|
+
str << '<c:crossAx val="' << @cross_ax.to_s << '"/>'
|
134
141
|
str << '<c:crosses val="' << @crosses.to_s << '"/>'
|
135
142
|
end
|
136
143
|
|
@@ -42,7 +42,7 @@ module Axlsx
|
|
42
42
|
def colors=(v) DataTypeValidator.validate "BarSeries.colors", [Array], v; @colors = v end
|
43
43
|
|
44
44
|
# The shabe of the bars or columns
|
45
|
-
# must be one of [:
|
45
|
+
# must be one of [:cone, :coneToMax, :box, :cylinder, :pyramid, :pyramidToMax]
|
46
46
|
def shape=(v)
|
47
47
|
RestrictionValidator.validate "BarSeries.shape", [:cone, :coneToMax, :box, :cylinder, :pyramid, :pyramidToMax], v
|
48
48
|
@shape = v
|
@@ -68,11 +68,16 @@ module Axlsx
|
|
68
68
|
@anchors = SimpleTypedList.new [TwoCellAnchor, OneCellAnchor]
|
69
69
|
end
|
70
70
|
|
71
|
-
# Adds an image to the chart
|
71
|
+
# Adds an image to the chart If th end_at option is specified we create a two cell anchor. By default we use a one cell anchor.
|
72
72
|
# @note The recommended way to manage images is to use Worksheet.add_image. Please refer to that method for documentation.
|
73
73
|
# @see Worksheet#add_image
|
74
|
+
# @return [Pic]
|
74
75
|
def add_image(options={})
|
75
|
-
|
76
|
+
if options[:end_at]
|
77
|
+
TwoCellAnchor.new(self, options).add_pic(options)
|
78
|
+
else
|
79
|
+
OneCellAnchor.new(self, options)
|
80
|
+
end
|
76
81
|
@anchors.last.object
|
77
82
|
end
|
78
83
|
|
data/lib/axlsx/drawing/pic.rb
CHANGED
@@ -90,8 +90,7 @@ module Axlsx
|
|
90
90
|
# @return [String]
|
91
91
|
def extname
|
92
92
|
File.extname(image_src).delete('.') unless image_src.nil?
|
93
|
-
end
|
94
|
-
|
93
|
+
end
|
95
94
|
# The index of this image in the workbooks images collections
|
96
95
|
# @return [Index]
|
97
96
|
def index
|
@@ -113,27 +112,32 @@ module Axlsx
|
|
113
112
|
# @param [Integer] v
|
114
113
|
# @see OneCellAnchor.width
|
115
114
|
def width
|
115
|
+
return unless @anchor.is_a?(OneCellAnchor)
|
116
116
|
@anchor.width
|
117
117
|
end
|
118
118
|
|
119
119
|
# @see width
|
120
120
|
def width=(v)
|
121
|
+
use_one_cell_anchor unless @anchor.is_a?(OneCellAnchor)
|
121
122
|
@anchor.width = v
|
122
123
|
end
|
123
124
|
|
124
125
|
# providing access to update the anchor's height attribute
|
125
126
|
# @param [Integer] v
|
126
127
|
# @see OneCellAnchor.width
|
128
|
+
# @note this is a noop if you are using a TwoCellAnchor
|
127
129
|
def height
|
128
130
|
@anchor.height
|
129
131
|
end
|
130
132
|
|
131
133
|
# @see height
|
134
|
+
# @note This is a noop if you are using a TwoCellAnchor
|
132
135
|
def height=(v)
|
136
|
+
use_one_cell_anchor unless @anchor.is_a?(OneCellAnchor)
|
133
137
|
@anchor.height = v
|
134
138
|
end
|
135
|
-
|
136
|
-
|
139
|
+
|
140
|
+
# This is a short cut method to set the start anchor position
|
137
141
|
# If you need finer granularity in positioning use
|
138
142
|
# graphic_frame.anchor.from.colOff / rowOff
|
139
143
|
# @param [Integer] x The column
|
@@ -142,6 +146,18 @@ module Axlsx
|
|
142
146
|
def start_at(x, y)
|
143
147
|
@anchor.from.col = x
|
144
148
|
@anchor.from.row = y
|
149
|
+
@anchor.from
|
150
|
+
end
|
151
|
+
|
152
|
+
# noop if not using a two cell anchor
|
153
|
+
# @param [Integer] x The column
|
154
|
+
# @param [Integer] y The row
|
155
|
+
# @return [Marker]
|
156
|
+
def end_at(x, y)
|
157
|
+
use_two_cell_anchor unless @anchor.is_a?(TwoCellAnchor)
|
158
|
+
@anchor.to.col = x
|
159
|
+
@anchor.to.row = y
|
160
|
+
@anchor.to
|
145
161
|
end
|
146
162
|
|
147
163
|
# Serializes the object
|
@@ -162,6 +178,30 @@ module Axlsx
|
|
162
178
|
str << '<a:prstGeom prst="rect"><a:avLst/></a:prstGeom></xdr:spPr></xdr:pic>'
|
163
179
|
|
164
180
|
end
|
181
|
+
|
182
|
+
private
|
183
|
+
|
184
|
+
# Changes the anchor to a one cell anchor.
|
185
|
+
def use_one_cell_anchor
|
186
|
+
return if @anchor.is_a?(OneCellAnchor)
|
187
|
+
swap_anchor(OneCellAnchor.new(@anchor.drawing, :from => @anchor.from))
|
188
|
+
end
|
189
|
+
|
190
|
+
#changes the anchor type to a two cell anchor
|
191
|
+
def use_two_cell_anchor
|
192
|
+
return if @anchor.is_a?(TwoCellAnchor)
|
193
|
+
swap_anchor(TwoCellAnchor.new(@anchor.drawing)).tap do |new_anchor|
|
194
|
+
new_anchor.from.col = @anchor.from.col
|
195
|
+
new_anchor.from.row = @anchor.from.row
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
# refactoring of swapping code, law of demeter be damned!
|
200
|
+
def swap_anchor(new_anchor)
|
201
|
+
new_anchor.drawing.anchors.delete(new_anchor)
|
202
|
+
@anchor.drawing.anchors[@anchor.drawing.anchors.index(@anchor)] = new_anchor
|
203
|
+
@anchor = new_anchor
|
204
|
+
end
|
165
205
|
|
166
206
|
end
|
167
207
|
end
|
@@ -34,7 +34,7 @@ module Axlsx
|
|
34
34
|
# @param [Drawing] drawing
|
35
35
|
# @param [Class] chart_type This is passed to the graphic frame for instantiation. must be Chart or a subclass of Chart
|
36
36
|
# @param object The object this anchor holds.
|
37
|
-
# @option options [Array] start_at the col, row to start at
|
37
|
+
# @option options [Array] start_at the col, row to start at THIS IS DOCUMENTED BUT NOT IMPLEMENTED HERE!
|
38
38
|
# @option options [Array] end_at the col, row to end at
|
39
39
|
def initialize(drawing, options={})
|
40
40
|
@drawing = drawing
|
@@ -49,6 +49,11 @@ module Axlsx
|
|
49
49
|
@object.chart
|
50
50
|
end
|
51
51
|
|
52
|
+
# Creates an image associated with this anchor.
|
53
|
+
def add_pic(options={})
|
54
|
+
@object = Pic.new(self, options)
|
55
|
+
end
|
56
|
+
|
52
57
|
# The index of this anchor in the drawing
|
53
58
|
# @return [Integer]
|
54
59
|
def index
|
@@ -58,6 +58,7 @@ module Axlsx
|
|
58
58
|
@top_offset = 2
|
59
59
|
@right_offset = 50
|
60
60
|
@bottom_offset = 5
|
61
|
+
@id = (0...8).map{65.+(rand(25)).chr}.join
|
61
62
|
options.each do |o|
|
62
63
|
self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
|
63
64
|
end
|
@@ -99,14 +100,10 @@ module Axlsx
|
|
99
100
|
def to_xml_string(str ='')
|
100
101
|
str << <<SHAME_ON_YOU
|
101
102
|
|
102
|
-
<v:shape id="" type="#_x0000_t202"
|
103
|
-
style='position:absolute;margin-left:104pt;margin-top:2pt;width:800px;height:27pt;z-index:1;mso-wrap-style:tight'
|
104
|
-
fillcolor="#ffffa1 [80]" o:insetmode="auto">
|
105
|
-
|
103
|
+
<v:shape id="#{@id}" type="#_x0000_t202" fillcolor="#ffffa1 [80]" o:insetmode="auto">
|
106
104
|
<v:fill color2="#ffffa1 [80]"/>
|
107
105
|
<v:shadow on="t" obscured="t"/>
|
108
106
|
<v:path o:connecttype="none"/>
|
109
|
-
|
110
107
|
<v:textbox style='mso-fit-text-with-word-wrap:t'>
|
111
108
|
<div style='text-align:left'></div>
|
112
109
|
</v:textbox>
|
@@ -40,10 +40,10 @@ module Axlsx
|
|
40
40
|
# @param [String] str
|
41
41
|
# @return [String]
|
42
42
|
def to_xml_string(str = '')
|
43
|
-
|
44
|
-
|
43
|
+
attrs = instance_values.reject { |k, v| ![:name, :pivot, :table].include?(k) }
|
44
|
+
attrs[:count] = self.size
|
45
45
|
str << '<tableStyle '
|
46
|
-
str <<
|
46
|
+
str << attrs.map { |key, value| '' << key.to_s << '="' << value.to_s << '"' }.join(' ')
|
47
47
|
str << '>'
|
48
48
|
each { |table_style_el| table_style_el.to_xml_string(str) }
|
49
49
|
str << '</tableStyle>'
|
@@ -155,19 +155,6 @@ module Axlsx
|
|
155
155
|
str << '</' << el_name << '>'
|
156
156
|
end
|
157
157
|
|
158
|
-
# Serializes the list
|
159
|
-
# If the serialize_as property is set, it is used as the parent node name.
|
160
|
-
# If the serialize_as property is nil, the first item in the list of allowed_types will be used, having the first letter of the class changed to lower case.
|
161
|
-
# @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
|
162
|
-
# @return [String]
|
163
|
-
def to_xml(xml)
|
164
|
-
classname = @allowed_types[0].name.split('::').last
|
165
|
-
el_name = serialize_as || (classname[0,1].downcase + classname[1..-1])
|
166
|
-
xml.send(el_name, :count=>@list.size) {
|
167
|
-
@list.each { |item| item.to_xml(xml) }
|
168
|
-
}
|
169
|
-
end
|
170
|
-
|
171
158
|
end
|
172
159
|
|
173
160
|
|
@@ -217,4 +217,25 @@ module Axlsx
|
|
217
217
|
RestrictionValidator.validate :table_element_type, [:wholeTable, :headerRow, :totalRow, :firstColumn, :lastColumn, :firstRowStripe, :secondRowStripe, :firstColumnStripe, :secondColumnStripe, :firstHeaderCell, :lastHeaderCell, :firstTotalCell, :lastTotalCell, :firstSubtotalColumn, :secondSubtotalColumn, :thirdSubtotalColumn, :firstSubtotalRow, :secondSubtotalRow, :thirdSubtotalRow, :blankRow, :firstColumnSubheading, :secondColumnSubheading, :thirdColumnSubheading, :firstRowSubheading, :secondRowSubheading, :thirdRowSubheading, :pageFieldLabels, :pageFieldValues], v
|
218
218
|
end
|
219
219
|
|
220
|
+
# Requires that the value is a valid data_validation_error_style
|
221
|
+
# :information, :stop, :warning
|
222
|
+
# @param [Any] v The value validated
|
223
|
+
def self.validate_data_validation_error_style(v)
|
224
|
+
RestrictionValidator.validate :validate_data_validation_error_style, [:information, :stop, :warning], v
|
225
|
+
end
|
226
|
+
|
227
|
+
# Requires that the value is valid data validation operator.
|
228
|
+
# valid operators must be one of lessThan, lessThanOrEqual, equal,
|
229
|
+
# notEqual, greaterThanOrEqual, greaterThan, between, notBetween
|
230
|
+
# @param [Any] v The value validated
|
231
|
+
def self.validate_data_validation_operator(v)
|
232
|
+
RestrictionValidator.validate :data_validation_operator, [:lessThan, :lessThanOrEqual, :equal, :notEqual, :greaterThanOrEqual, :greaterThan, :between, :notBetween], v
|
233
|
+
end
|
234
|
+
|
235
|
+
# Requires that the value is valid data validation type.
|
236
|
+
# valid types must be one of custom, data, decimal, list, none, textLength, time, whole
|
237
|
+
# @param [Any] v The value validated
|
238
|
+
def self.validate_data_validation_type(v)
|
239
|
+
RestrictionValidator.validate :data_validation_type, [:custom, :data, :decimal, :list, :none, :textLength, :time, :whole], v
|
240
|
+
end
|
220
241
|
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.6" unless defined? Axlsx::VERSION
|
9
9
|
|
10
10
|
end
|
@@ -16,9 +16,11 @@ require 'axlsx/workbook/worksheet/row.rb'
|
|
16
16
|
require 'axlsx/workbook/worksheet/col.rb'
|
17
17
|
require 'axlsx/workbook/worksheet/comments.rb'
|
18
18
|
require 'axlsx/workbook/worksheet/comment.rb'
|
19
|
+
require 'axlsx/workbook/worksheet/sheet_protection.rb'
|
19
20
|
require 'axlsx/workbook/worksheet/worksheet.rb'
|
20
21
|
require 'axlsx/workbook/shared_strings_table.rb'
|
21
22
|
require 'axlsx/workbook/worksheet/table.rb'
|
23
|
+
require 'axlsx/workbook/worksheet/data_validation.rb'
|
22
24
|
|
23
25
|
# The Workbook class is an xlsx workbook that manages worksheets, charts, drawings and styles.
|
24
26
|
# The following parts of the Office Open XML spreadsheet specification are not implimented in this version.
|
@@ -195,7 +195,7 @@ module Axlsx
|
|
195
195
|
# @option options [Symbol] scheme must be one of :none, major, :minor
|
196
196
|
def initialize(row, value="", options={})
|
197
197
|
self.row=row
|
198
|
-
@font_name = @charset = @family = @b = @i = @strike = @outline = @shadow = nil
|
198
|
+
@value = @font_name = @charset = @family = @b = @i = @strike = @outline = @shadow = nil
|
199
199
|
@condense = @u = @vertAlign = @sz = @color = @scheme = @extend = @ssti = nil
|
200
200
|
@styles = row.worksheet.workbook.styles
|
201
201
|
@row.cells << self
|
@@ -261,9 +261,8 @@ module Axlsx
|
|
261
261
|
# @return [String]
|
262
262
|
def run_xml_string(str = '')
|
263
263
|
if is_text_run?
|
264
|
-
data =
|
264
|
+
data = instance_values.reject{|key, value| value == nil || key == 'value' || key == 'type' }
|
265
265
|
keys = data.keys & INLINE_STYLES
|
266
|
-
keys.delete ['value', 'type']
|
267
266
|
str << "<r><rPr>"
|
268
267
|
keys.each do |key|
|
269
268
|
case key
|
@@ -272,7 +271,7 @@ module Axlsx
|
|
272
271
|
when 'color'
|
273
272
|
str << data[key].to_xml_string
|
274
273
|
else
|
275
|
-
"<" << key.to_s << " val='" << data[key].to_s << "'/>"
|
274
|
+
str << "<" << key.to_s << " val='" << data[key].to_s << "'/>"
|
276
275
|
end
|
277
276
|
end
|
278
277
|
str << "</rPr>" << "<t>" << value.to_s << "</t></r>"
|
@@ -41,12 +41,6 @@ module Axlsx
|
|
41
41
|
@vml_shape ||= initialize_vml_shape
|
42
42
|
end
|
43
43
|
|
44
|
-
# The index of this comment
|
45
|
-
# @return [Integer]
|
46
|
-
def index
|
47
|
-
@comments.index(self)
|
48
|
-
end
|
49
|
-
|
50
44
|
#
|
51
45
|
# The index of this author in a unique sorted list of all authors in
|
52
46
|
# the comment.
|
@@ -96,10 +90,10 @@ module Axlsx
|
|
96
90
|
def initialize_vml_shape
|
97
91
|
pos = Axlsx::name_to_indices(ref)
|
98
92
|
@vml_shape = VmlShape.new(:row => pos[1], :column => pos[0]) do |vml|
|
99
|
-
vml.left_column = vml.
|
100
|
-
vml.right_column = vml.column +
|
93
|
+
vml.left_column = vml.column
|
94
|
+
vml.right_column = vml.column + 2
|
101
95
|
vml.top_row = vml.row
|
102
|
-
|
96
|
+
vml.bottom_row = vml.row + 4
|
103
97
|
end
|
104
98
|
end
|
105
99
|
|
@@ -0,0 +1,245 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
module Axlsx
|
3
|
+
# Data validation allows the validation of cell data
|
4
|
+
#
|
5
|
+
# @note The recommended way to manage data validations is via Worksheet#add_data_validation
|
6
|
+
# @see Worksheet#add_data_validation
|
7
|
+
class DataValidation
|
8
|
+
|
9
|
+
# instance values that must be serialized as their own elements - e.g. not attributes.
|
10
|
+
CHILD_ELEMENTS = [:formula1, :formula2]
|
11
|
+
|
12
|
+
# Formula1
|
13
|
+
# Available for type whole, decimal, date, time, textLength, list, custom
|
14
|
+
# @see type
|
15
|
+
# @return [String]
|
16
|
+
# default nil
|
17
|
+
attr_reader :formula1
|
18
|
+
|
19
|
+
# Formula2
|
20
|
+
# Available for type whole, decimal, date, time, textLength
|
21
|
+
# @see type
|
22
|
+
# @return [String]
|
23
|
+
# default nil
|
24
|
+
attr_reader :formula2
|
25
|
+
|
26
|
+
# Allow Blank
|
27
|
+
# A boolean value indicating whether the data validation allows the use of empty or blank
|
28
|
+
# entries. 1 means empty entries are OK and do not violate the validation constraints.
|
29
|
+
# Available for type whole, decimal, date, time, textLength, list, custom
|
30
|
+
# @see type
|
31
|
+
# @return [Boolean]
|
32
|
+
# default true
|
33
|
+
attr_reader :allowBlank
|
34
|
+
|
35
|
+
# Error Message
|
36
|
+
# Message text of error alert.
|
37
|
+
# Available for type whole, decimal, date, time, textLength, list, custom
|
38
|
+
# @see type
|
39
|
+
# @return [String]
|
40
|
+
# default nil
|
41
|
+
attr_reader :error
|
42
|
+
|
43
|
+
# Error Style (ST_DataValidationErrorStyle)
|
44
|
+
# The style of error alert used for this data validation.
|
45
|
+
# Options are:
|
46
|
+
# * information: This data validation error style uses an information icon in the error alert.
|
47
|
+
# * stop: This data validation error style uses a stop icon in the error alert.
|
48
|
+
# * warning: This data validation error style uses a warning icon in the error alert.
|
49
|
+
# Available for type whole, decimal, date, time, textLength, list, custom
|
50
|
+
# @see type
|
51
|
+
# @return [Symbol]
|
52
|
+
# default :stop
|
53
|
+
attr_reader :errorStyle
|
54
|
+
|
55
|
+
# Error Title
|
56
|
+
# Title bar text of error alert.
|
57
|
+
# Available for type whole, decimal, date, time, textLength, list, custom
|
58
|
+
# @see type
|
59
|
+
# @return [String]
|
60
|
+
# default nil
|
61
|
+
attr_reader :errorTitle
|
62
|
+
|
63
|
+
# Operator (ST_DataValidationOperator)
|
64
|
+
# The relational operator used with this data validation.
|
65
|
+
# Options are:
|
66
|
+
# * between: Data validation which checks if a value is between two other values.
|
67
|
+
# * equal: Data validation which checks if a value is equal to a specified value.
|
68
|
+
# * greater_than: Data validation which checks if a value is greater than a specified value.
|
69
|
+
# * greater_than_or_equal: Data validation which checks if a value is greater than or equal to a specified value.
|
70
|
+
# * less_than: Data validation which checks if a value is less than a specified value.
|
71
|
+
# * less_than_or_equal: Data validation which checks if a value is less than or equal to a specified value.
|
72
|
+
# * not_between: Data validation which checks if a value is not between two other values.
|
73
|
+
# * not_equal: Data validation which checks if a value is not equal to a specified value.
|
74
|
+
# Available for type whole, decimal, date, time, textLength
|
75
|
+
# @see type
|
76
|
+
# @return [Symbol]
|
77
|
+
# default nil
|
78
|
+
attr_reader :operator
|
79
|
+
|
80
|
+
# Input prompt
|
81
|
+
# Message text of input prompt.
|
82
|
+
# Available for type whole, decimal, date, time, textLength, list, custom
|
83
|
+
# @see type
|
84
|
+
# @return [String]
|
85
|
+
# default nil
|
86
|
+
attr_reader :prompt
|
87
|
+
|
88
|
+
# Prompt title
|
89
|
+
# Title bar text of input prompt.
|
90
|
+
# Available for type whole, decimal, date, time, textLength, list, custom
|
91
|
+
# @see type
|
92
|
+
# @return [String]
|
93
|
+
# default nil
|
94
|
+
attr_reader :promptTitle
|
95
|
+
|
96
|
+
# Show drop down
|
97
|
+
# A boolean value indicating whether to display a dropdown combo box for a list type data
|
98
|
+
# validation. Be careful: false shows the dropdown list!
|
99
|
+
# Available for type list
|
100
|
+
# @see type
|
101
|
+
# @return [Boolean]
|
102
|
+
# default false
|
103
|
+
attr_reader :showDropDown
|
104
|
+
|
105
|
+
# Show error message
|
106
|
+
# A boolean value indicating whether to display the error alert message when an invalid
|
107
|
+
# value has been entered, according to the criteria specified.
|
108
|
+
# Available for type whole, decimal, date, time, textLength, list, custom
|
109
|
+
# @see type
|
110
|
+
# @return [Boolean]
|
111
|
+
# default false
|
112
|
+
attr_reader :showErrorMessage
|
113
|
+
|
114
|
+
# Show input message
|
115
|
+
# A boolean value indicating whether to display the input prompt message.
|
116
|
+
# Available for type whole, decimal, date, time, textLength, list, custom
|
117
|
+
# @see type
|
118
|
+
# @return [Boolean]
|
119
|
+
# default false
|
120
|
+
attr_reader :showInputMessage
|
121
|
+
|
122
|
+
# Range over which data validation is applied, in "A1:B2" format
|
123
|
+
# Available for type whole, decimal, date, time, textLength, list, custom
|
124
|
+
# @see type
|
125
|
+
# @return [String]
|
126
|
+
# default nil
|
127
|
+
attr_reader :sqref
|
128
|
+
|
129
|
+
# The type (ST_DataValidationType) of data validation.
|
130
|
+
# Options are:
|
131
|
+
# * custom: Data validation which uses a custom formula to check the cell value.
|
132
|
+
# * date: Data validation which checks for date values satisfying the given condition.
|
133
|
+
# * decimal: Data validation which checks for decimal values satisfying the given condition.
|
134
|
+
# * list: Data validation which checks for a value matching one of list of values.
|
135
|
+
# * none: No data validation.
|
136
|
+
# * textLength: Data validation which checks for text values, whose length satisfies the given condition.
|
137
|
+
# * time: Data validation which checks for time values satisfying the given condition.
|
138
|
+
# * whole: Data validation which checks for whole number values satisfying the given condition.
|
139
|
+
# @return [Symbol]
|
140
|
+
# default none
|
141
|
+
attr_reader :type
|
142
|
+
|
143
|
+
# Creates a new {DataValidation} object
|
144
|
+
# @option options [String] formula1
|
145
|
+
# @option options [String] formula2
|
146
|
+
# @option options [Boolean] allowBlank - A boolean value indicating whether the data validation allows the use of empty or blank entries.
|
147
|
+
# @option options [String] error - Message text of error alert.
|
148
|
+
# @option options [Symbol] errorStyle - The style of error alert used for this data validation.
|
149
|
+
# @option options [String] errorTitle - itle bar text of error alert.
|
150
|
+
# @option options [Symbol] operator - The relational operator used with this data validation.
|
151
|
+
# @option options [String] prompt - Message text of input prompt.
|
152
|
+
# @option options [String] promptTitle - Title bar text of input prompt.
|
153
|
+
# @option options [Boolean] showDropDown - A boolean value indicating whether to display a dropdown combo box for a list type data validation
|
154
|
+
# @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.
|
155
|
+
# @option options [Boolean] showInputMessage - A boolean value indicating whether to display the input prompt message.
|
156
|
+
# @option options [String] sqref - Range over which data validation is applied, in "A1:B2" format.
|
157
|
+
# @option options [Symbol] type - The type of data validation.
|
158
|
+
def initialize(options={})
|
159
|
+
# defaults
|
160
|
+
@formula1 = @formula2 = @error = @errorTitle = @operator = @prompt = @promptTitle = @sqref = nil
|
161
|
+
@allowBlank = @showErrorMessage = true
|
162
|
+
@showDropDown = @showInputMessage = false
|
163
|
+
@type = :none
|
164
|
+
@errorStyle = :stop
|
165
|
+
|
166
|
+
options.each do |o|
|
167
|
+
self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# @see formula1
|
172
|
+
def formula1=(v); Axlsx::validate_string(v); @formula1 = v end
|
173
|
+
|
174
|
+
# @see formula2
|
175
|
+
def formula2=(v); Axlsx::validate_string(v); @formula2 = v end
|
176
|
+
|
177
|
+
# @see allowBlank
|
178
|
+
def allowBlank=(v); Axlsx::validate_boolean(v); @allowBlank = v end
|
179
|
+
|
180
|
+
# @see error
|
181
|
+
def error=(v); Axlsx::validate_string(v); @error = v end
|
182
|
+
|
183
|
+
# @see errorStyle
|
184
|
+
def errorStyle=(v); Axlsx::validate_data_validation_error_style(v); @errorStyle = v end
|
185
|
+
|
186
|
+
# @see errorTitle
|
187
|
+
def errorTitle=(v); Axlsx::validate_string(v); @errorTitle = v end
|
188
|
+
|
189
|
+
# @see operator
|
190
|
+
def operator=(v); Axlsx::validate_data_validation_operator(v); @operator = v end
|
191
|
+
|
192
|
+
# @see prompt
|
193
|
+
def prompt=(v); Axlsx::validate_string(v); @prompt = v end
|
194
|
+
|
195
|
+
# @see promptTitle
|
196
|
+
def promptTitle=(v); Axlsx::validate_string(v); @promptTitle = v end
|
197
|
+
|
198
|
+
# @see showDropDown
|
199
|
+
def showDropDown=(v); Axlsx::validate_boolean(v); @showDropDown = v end
|
200
|
+
|
201
|
+
# @see showErrorMessage
|
202
|
+
def showErrorMessage=(v); Axlsx::validate_boolean(v); @showErrorMessage = v end
|
203
|
+
|
204
|
+
# @see showInputMessage
|
205
|
+
def showInputMessage=(v); Axlsx::validate_boolean(v); @showInputMessage = v end
|
206
|
+
|
207
|
+
# @see sqref
|
208
|
+
def sqref=(v); Axlsx::validate_string(v); @sqref = v end
|
209
|
+
|
210
|
+
# @see type
|
211
|
+
def type=(v); Axlsx::validate_data_validation_type(v); @type = v end
|
212
|
+
|
213
|
+
# Serializes the data validation
|
214
|
+
# @param [String] str
|
215
|
+
# @return [String]
|
216
|
+
def to_xml_string(str = '')
|
217
|
+
valid_attributes = get_valid_attributes
|
218
|
+
|
219
|
+
str << '<dataValidation '
|
220
|
+
str << instance_values.map { |key, value| '' << key << '="' << value.to_s << '"' if (valid_attributes.include?(key.to_sym) and not CHILD_ELEMENTS.include?(key.to_sym)) }.join(' ')
|
221
|
+
str << '>'
|
222
|
+
str << '<formula1>' << self.formula1 << '</formula1>' if @formula1 and valid_attributes.include?(:formula1)
|
223
|
+
str << '<formula2>' << self.formula2 << '</formula2>' if @formula2 and valid_attributes.include?(:formula2)
|
224
|
+
str << '</dataValidation>'
|
225
|
+
end
|
226
|
+
|
227
|
+
private
|
228
|
+
def get_valid_attributes
|
229
|
+
attributes = [:allowBlank, :error, :errorStyle, :errorTitle, :prompt, :promptTitle, :showErrorMessage, :showInputMessage, :sqref, :type ]
|
230
|
+
|
231
|
+
if [:whole, :decimal, :data, :time, :textLength].include?(@type)
|
232
|
+
attributes << [:operator, :formula1]
|
233
|
+
attributes << [:formula2] if [:between, :notBetween].include?(@operator)
|
234
|
+
elsif @type == :list
|
235
|
+
attributes << [:showDropDown, :formula1]
|
236
|
+
elsif @type == :custom
|
237
|
+
attributes << [:formula1]
|
238
|
+
else
|
239
|
+
attributes = []
|
240
|
+
end
|
241
|
+
|
242
|
+
attributes.flatten!
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|