summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md1
-rw-r--r--examples/borders_example.md9
-rw-r--r--lib/axlsx/stylesheet/border.rb2
-rw-r--r--lib/axlsx/stylesheet/styles.rb110
-rw-r--r--test/stylesheet/tc_styles.rb48
5 files changed, 152 insertions, 18 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6e5604fa..3e642869 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,7 @@ CHANGELOG
---------
- **Unreleased**
+ - [PR #117](https://github.com/caxlsx/caxlsx/pull/117) - Allow passing an Array of border hashes to the `border` style. Change previous behaviour where `border_top`, `border_*` styles would not be applied unless `border` style was also defined.
- [PR #122](https://github.com/caxlsx/caxlsx/pull/122) - Improve error messages when incorrect ranges are provided to `Worksheet#[]`
- [PR #123](https://github.com/caxlsx/caxlsx/pull/123) - Fix invalid xml when pivot table created with more than one column in data field. Solves [Issue #110](https://github.com/caxlsx/caxlsx/issues/110)
diff --git a/examples/borders_example.md b/examples/borders_example.md
index d637681c..2607d17c 100644
--- a/examples/borders_example.md
+++ b/examples/borders_example.md
@@ -14,9 +14,18 @@ s = wb.styles
red_border = s.add_style border: { style: :thick, color: 'FFFF0000', edges: [:left, :right] }
blue_border = s.add_style border: { style: :thick, color: 'FF0000FF' }
+complex_border = workbook.styles.add_style(
+ border: [
+ { style: :thin, color: '000' },
+ { style: :double, edges: [:top, :bottom] },
+ { style: :thick, edges: [:left, :right] },
+ ]
+)
+
wb.add_worksheet(name: 'Custom Borders') do |sheet|
sheet.add_row ['wrap', 'me', 'up in red'], style: red_border
sheet.add_row [1, 2, 3], style: blue_border
+ sheet.add_row [4, 5, 6], style: complex_border
end
p.serialize 'borders_example.xlsx'
diff --git a/lib/axlsx/stylesheet/border.rb b/lib/axlsx/stylesheet/border.rb
index 422a4466..0a823c7a 100644
--- a/lib/axlsx/stylesheet/border.rb
+++ b/lib/axlsx/stylesheet/border.rb
@@ -6,6 +6,8 @@ module Axlsx
include Axlsx::SerializedAttributes
include Axlsx::OptionsParser
+ EDGES = [:left, :right, :top, :bottom].freeze
+
# Creates a new Border object
# @option options [Boolean] diagonal_up
# @option options [Boolean] diagonal_down
diff --git a/lib/axlsx/stylesheet/styles.rb b/lib/axlsx/stylesheet/styles.rb
index 2460ab10..d1ee1f66 100644
--- a/lib/axlsx/stylesheet/styles.rb
+++ b/lib/axlsx/stylesheet/styles.rb
@@ -310,33 +310,108 @@ module Axlsx
# may include an :edges entry that references an array of symbols identifying which border edges
# you wish to apply the style or any other valid Border initializer options.
# If the :edges entity is not provided the style is applied to all edges of cells that reference this style.
- # Also available :border_top, :border_right, :border_bottom and :border_left options with :style and/or :color
- # key-value entries, which override :border values.
+ # Also available :border_top, :border_right, :border_bottom and :border_left options with :style and/or :color
+ # key-value entries, which override :border values.
# @example
# #apply a thick red border to the top and bottom
# { :border => { :style => :thick, :color => "FFFF0000", :edges => [:top, :bottom] }
# @return [Border|Integer]
def parse_border_options(options={})
- return unless options[:border]
- b_opts = options[:border]
- if b_opts.is_a?(Hash)
- raise ArgumentError, (ERR_INVALID_BORDER_OPTIONS % b_opts) unless b_opts.keys.include?(:style) && b_opts.keys.include?(:color)
- border = Border.new b_opts
- (b_opts[:edges] || [:left, :right, :top, :bottom]).each do |edge|
- edge_options = options["border_#{edge}".to_sym] || {}
- border_edge = b_opts.merge(edge_options)
- b_options = { :name => edge, :style => border_edge[:style], :color => Color.new(:rgb => border_edge[:color]) }
- border.prs << BorderPr.new(b_options)
+ if options[:border].nil? && Border::EDGES.all?{|x| options["border_#{x}".to_sym].nil? }
+ return nil
+ end
+
+ if options[:border].is_a?(Integer)
+ if options[:border] >= borders.size
+ raise ArgumentError, (ERR_INVALID_BORDER_ID % options[:border])
end
- options[:type] == :dxf ? border : borders << border
- elsif b_opts.is_a? Integer
- raise ArgumentError, (ERR_INVALID_BORDER_ID % b_opts) unless b_opts < borders.size
+
if options[:type] == :dxf
- borders[b_opts].clone
+ return borders[options[:border]].clone
+ else
+ return options[:border]
+ end
+ end
+
+ validate_border_hash = ->(val){
+ if !(val.keys.include?(:style) && val.keys.include?(:color))
+ raise ArgumentError, (ERR_INVALID_BORDER_OPTIONS % options[:border])
+ end
+ }
+
+ borders_array = []
+
+ if options[:border].nil?
+ base_border_opts = {}
+ else
+ if options[:border].is_a?(Array)
+ borders_array += options[:border]
+
+ base_border_opts = {}
+
+ options[:border].each do |b_opts|
+ if b_opts[:edges].nil?
+ base_border_opts = base_border_opts.merge(b_opts)
+ end
+ end
else
- border = b_opts
+ borders_array << options[:border]
+
+ base_border_opts = options[:border]
+
+ validate_border_hash.call(base_border_opts)
+ end
+ end
+
+ Border::EDGES.each do |edge|
+ val = options["border_#{edge}".to_sym]
+
+ if val
+ borders_array << val.merge(edges: [edge])
+ end
+ end
+
+ border = Border.new(base_border_opts)
+
+ Border::EDGES.each do |edge|
+ edge_b_opts = base_border_opts
+
+ skip_edge = true
+
+ borders_array.each do |b_opts|
+ if b_opts[:edges] && b_opts[:edges].include?(edge)
+ edge_b_opts = edge_b_opts.merge(b_opts)
+ skip_edge = false
+ end
+ end
+
+ if options["border_#{edge}".to_sym]
+ edge_b_opts = edge_b_opts.merge(options["border_#{edge}".to_sym])
+ skip_edge = false
+ end
+
+ if skip_edge && base_border_opts[:edges]
+ next
+ end
+
+ if !edge_b_opts.empty?
+ if base_border_opts.empty?
+ validate_border_hash.call(edge_b_opts)
+ end
+
+ border.prs << BorderPr.new({
+ :name => edge,
+ :style => edge_b_opts[:style],
+ :color => Color.new(:rgb => edge_b_opts[:color]) },
+ )
end
end
+
+ if options[:type] == :dxf
+ return border
+ else
+ return borders << border
+ end
end
# Parses Style#add_style options for number formatting.
@@ -417,4 +492,3 @@ module Axlsx
end
end
end
-
diff --git a/test/stylesheet/tc_styles.rb b/test/stylesheet/tc_styles.rb
index 72bf1466..c46b6bdb 100644
--- a/test/stylesheet/tc_styles.rb
+++ b/test/stylesheet/tc_styles.rb
@@ -17,6 +17,7 @@ class TestStyles < Test::Unit::TestCase
end
assert(errors.size == 0)
end
+
def test_add_style_border_hash
border_count = @styles.borders.size
@styles.add_style :border => {:style => :thin, :color => "FFFF0000"}
@@ -26,6 +27,32 @@ class TestStyles < Test::Unit::TestCase
assert_equal @styles.borders.last.prs.size, 4
end
+ def test_add_style_border_array
+ prev_border_count = @styles.borders.size
+
+ borders_array = [
+ {:style => :thin, :color => "DDDDDD"},
+ {:edges => [:top], :style => :thin, :color => "000000"},
+ {:edges => [:bottom], :style => :thick, :color => "FF0000"},
+ {:edges => [:left], :style => :dotted, :color => "FFFF00"},
+ {:edges => [:right], :style => :dashed, :color => "FFFFFF"},
+ {:style => :thick, :color => "CCCCCC"},
+ ]
+
+ @styles.add_style(border: borders_array)
+
+ assert_equal(@styles.borders.size, (prev_border_count+1))
+
+ current_border = @styles.borders.last
+
+ borders_array.each do |b_opts|
+ if b_opts[:edges]
+ border_pr = current_border.prs.detect{|x| x.name == b_opts[:edges].first }
+ assert_equal(border_pr.color.rgb, "FF#{b_opts[:color]}")
+ end
+ end
+ end
+
def test_add_style_border_edges
@styles.add_style :border => { :style => :thin, :color => "0000FFFF", :edges => [:top, :bottom] }
parts = @styles.borders.last.prs
@@ -258,4 +285,25 @@ class TestStyles < Test::Unit::TestCase
end
assert(errors.size == 0)
end
+
+ def test_border_top_without_border_regression
+ ### https://github.com/axlsx-styler-gem/axlsx_styler/issues/31
+
+ borders = {
+ top: { style: :double, color: '0000FF' },
+ right: { style: :thick, color: 'FF0000' },
+ bottom: { style: :double, color: '0000FF' },
+ left: { style: :thick, color: 'FF0000' }
+ }
+
+ borders.each do |edge, b_opts|
+ @styles.add_style("border_#{edge}".to_sym => b_opts)
+
+ current_border = @styles.borders.last
+
+ border_pr = current_border.prs.detect{|x| x.name == edge }
+ assert_equal(border_pr.color.rgb, "FF#{b_opts[:color]}")
+ end
+
+ end
end