diff --git a/CHANGELOG.md b/CHANGELOG.md
index 17accc3..c3be449 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,7 @@ CHANGELOG
- **5.0.0 - Unreleased** - [View Diff](https://github.com/westonganger/spreadsheet_architect/compare/v4.2.0...master)
- **Breaking Change** - [PR #38](https://github.com/westonganger/spreadsheet_architect/pull/38) - Add `escape_formulas` option for xlsx spreadsheets. This is a breaking change because we default to `escape_formulas: true` whereas before there was no formula escaping at all. The reasoning for this breaking change is that creating spreadsheets where many of the fields contain direct user input are a large majority compared to use cases that involve formulas.
- Add option `use_zero_based_row_index: true` (Default `false`) which allows you to use zero-based row indexes instead of the default 1-based row indexes. Recomended to set this option for the whole project. The original reason it was designed to be 1-based is because spreadsheet row numbers literally start with 1. However this tends to be unituitive for the developer because columns use zero based indexes because they use letter-based notation instead.
+ - Improve argument handling for freeze option and add support for all Axlsx supported options for panes using the `:freeze` hash. See test case for example (./test/unit/xlsx_freeze_test.rb)
- **4.2.0** - May 27, 2021 - [View Diff](https://github.com/westonganger/spreadsheet_architect/compare/v4.1.0...v4.2.0)
- Add option `:skip_defaults` which removes the defaults and default styles. Particularily useful for heavily customized spreadsheets where the default styles get in the way.
diff --git a/README.md b/README.md
index cf22374..58bca73 100644
--- a/README.md
+++ b/README.md
@@ -224,7 +224,7 @@ See this file for more details: [test/unit/multi_sheet_test.rb](./test/unit/mult
|**column_types**
*Array*||Valid types for XLSX are :string, :integer, :float, :date, :time, :boolean, nil = auto determine.|
|**column_widths**
*Array*||Sometimes you may want explicit column widths. Use nil if you want a column to autofit again.|
|**freeze_headers**
*Boolean*||Make all header rows frozen/fixed so they do not scroll.|
-|**freeze**
*Hash*|`{rows: (1..4), columns: :all}`|Make all specified rows and columns frozen/fixed so they do not scroll.|
+|**freeze**
*Hash*||Make all specified row and/or column frozen/fixed so they do not scroll. See [example usage](./test/unit/xlsx_freeze_test.rb)|
|**skip_defaults**
*Boolean*|`false`|Removes defaults and default styles. Particularily useful for heavily customized spreadsheets where the default styles get in the way.|
|**escape_formulas**
*Boolean* or *Array*|`true`|Pass a single boolean to apply to all cells, or an array of booleans to control column-by-column. Advisable to be set true when involved with untrusted user input. See [an example of the underlying functionality](https://github.com/caxlsx/caxlsx/blob/master/examples/escape_formula_example.md). NOTE: Header row cells are not escaped. |
|**use_zero_based_row_index**
*Boolean*|`false`|Allows you to use zero-based row indexes when defining `range_styles`, `merges`, etc. Recomended to set this option for the whole project rather than per call. The original reason it was designed to be 1-based is because spreadsheet row numbers actually start with 1.|
diff --git a/lib/spreadsheet_architect/class_methods/xlsx.rb b/lib/spreadsheet_architect/class_methods/xlsx.rb
index 7315d3f..29e7b60 100644
--- a/lib/spreadsheet_architect/class_methods/xlsx.rb
+++ b/lib/spreadsheet_architect/class_methods/xlsx.rb
@@ -14,10 +14,6 @@ def to_axlsx_package(opts={}, package=nil)
opts = SpreadsheetArchitect::Utils.get_options(opts, self)
options = SpreadsheetArchitect::Utils.get_cell_data(opts, self)
- if options[:column_types] && !(options[:column_types].compact.collect(&:to_sym) - SpreadsheetArchitect::XLSX_COLUMN_TYPES).empty?
- raise SpreadsheetArchitect::Exceptions::ArgumentError.new("Invalid column type. Valid XLSX values are #{SpreadsheetArchitect::XLSX_COLUMN_TYPES}")
- end
-
header_style = SpreadsheetArchitect::Utils::XLSX.convert_styles_to_axlsx(options[:header_style])
row_style = SpreadsheetArchitect::Utils::XLSX.convert_styles_to_axlsx(options[:row_style])
@@ -212,33 +208,62 @@ def to_axlsx_package(opts={}, package=nil)
end
elsif options[:freeze]
- options[:freeze] = SpreadsheetArchitect::Utils.symbolize_keys(options[:freeze])
+ case options[:freeze][:type].to_s
+ when "split_panes"
+ options[:freeze][:state] == "split"
+ when "frozen", "freeze"
+ options[:freeze][:state] == "frozen"
+ end
+
+ if options[:freeze][:rows]
+ options[:freeze][:row] ||= options[:freeze][:rows]
+ end
+
+ if options[:freeze][:columns]
+ options[:freeze][:column] ||= options[:freeze][:columns]
+ end
+
+ if options[:freeze][:row] == :all
+ options[:freeze][:row] = nil
+ elsif options[:freeze][:row].is_a?(Range)
+ options[:freeze][:row] = options[:freeze][:row].last
+ end
+
+ if options[:freeze][:column] == :all
+ options[:freeze][:column] = nil
+ elsif options[:freeze][:column].is_a?(Range)
+ options[:freeze][:column] = options[:freeze][:column].last
+ end
+
+ if !options[:freeze][:row] && !options[:freeze][:column]
+ raise SpreadsheetArchitect::Exceptions::ArgumentError.new("Missing required :row or :column value in the :freeze option hash")
+ elsif options[:freeze][:row] && !options[:freeze][:row].is_a?(Integer)
+ raise SpreadsheetArchitect::Exceptions::ArgumentError.new("Invalid :row value provided for in :freeze option hash, must be an Integer")
+ elsif options[:freeze][:column] && !options[:freeze][:column].is_a?(Integer)
+ raise SpreadsheetArchitect::Exceptions::ArgumentError.new("Invalid :column value provided for in :freeze option hash, must be an Integer")
+ end
sheet.sheet_view.pane do |pane|
- pane.state = :frozen
+ pane.state = (options[:freeze][:state] || :frozen).to_sym ### Other options are :split and :frozen_split
- ### Currently not working
- #if options[:freeze][:active_pane]
- # Axlsx.validate_pane_type(options[:freeze][:active_pane])
- # pane.active_pane = options[:freeze][:active_pane]
- #else
- # pane.active_pane = :bottom_right
- #end
-
- if !options[:freeze][:rows]
- raise SpreadsheetArchitect::Exceptions::ArgumentError.new("The :rows key must be specified in the :freeze option hash")
- elsif options[:freeze][:rows].is_a?(Range)
- pane.y_split = options[:freeze][:rows].count
- else
- pane.y_split = 1
+ if options[:freeze][:active_pane]
+ pane.active_pane = options[:freeze][:active_pane].to_sym
end
- if options[:freeze][:columns] && options[:freeze][:columns] != :all
- if options[:freeze][:columns].is_a?(Range)
- pane.x_split = options[:freeze][:columns].count
- else
- pane.x_split = 1
+ if options[:freeze][:top_left_cell]
+ pane.top_left_cell = options[:freeze][:top_left_cell]
+ end
+
+ if options[:freeze][:row]
+ if options[:use_zero_based_row_index]
+ options[:freeze][:row] += 1
end
+
+ pane.y_split = options[:freeze][:row]
+ end
+
+ if options[:freeze][:column]
+ pane.x_split = options[:freeze][:column]
end
end
end
diff --git a/lib/spreadsheet_architect/utils.rb b/lib/spreadsheet_architect/utils.rb
index 279e3d1..e9888c1 100644
--- a/lib/spreadsheet_architect/utils.rb
+++ b/lib/spreadsheet_architect/utils.rb
@@ -142,11 +142,15 @@ def self.get_options(options, klass)
end
end
+ if options[:column_types] && !(options[:column_types].compact.collect(&:to_sym) - SpreadsheetArchitect::XLSX_COLUMN_TYPES).empty?
+ raise SpreadsheetArchitect::Exceptions::ArgumentError.new("Invalid column type. Valid XLSX values are #{SpreadsheetArchitect::XLSX_COLUMN_TYPES}")
+ end
+
if options[:freeze]
+ options[:freeze] = SpreadsheetArchitect::Utils.symbolize_keys(options[:freeze])
+
if options[:freeze_headers]
raise SpreadsheetArchitect::Exceptions::ArgumentError.new('Cannot use both :freeze and :freeze_headers options at the same time')
- elsif options[:freeze].is_a?(Hash) && !options[:freeze][:rows]
- raise SpreadsheetArchitect::Exceptions::ArgumentError.new('Must provide a :rows key when passing a hash to the :freeze option')
end
end
diff --git a/test/unit/xlsx_freeze_test.rb b/test/unit/xlsx_freeze_test.rb
index a39c722..c45024a 100644
--- a/test/unit/xlsx_freeze_test.rb
+++ b/test/unit/xlsx_freeze_test.rb
@@ -2,6 +2,12 @@
class XlsxFreezeTest < ActiveSupport::TestCase
+ def base_path
+ path = VERSIONED_BASE_PATH.join("xlsx/freeze/")
+ FileUtils.mkdir_p(path)
+ return path
+ end
+
def setup
@options = {
headers: [
@@ -15,7 +21,7 @@ def setup
def teardown
end
- def test_1
+ def test_basic
opts = @options.merge({
freeze: {rows: 1, columns: 1},
})
@@ -23,12 +29,12 @@ def test_1
# Using Array Data
file_data = SpreadsheetArchitect.to_xlsx(opts)
- File.open(VERSIONED_BASE_PATH.join("freeze_test_1.xlsx"),'w+b') do |f|
+ File.open(base_path.join("freeze_#{__method__}.xlsx"),'w+b') do |f|
f.write file_data
end
end
- def test_2
+ def test_using_ranges
opts = @options.merge({
freeze: {rows: (2..4), columns: (2..4)},
})
@@ -36,7 +42,52 @@ def test_2
# Using Array Data
file_data = SpreadsheetArchitect.to_xlsx(opts)
- File.open(VERSIONED_BASE_PATH.join("freeze_test_2.xlsx"),'w+b') do |f|
+ File.open(base_path.join("freeze_#{__method__}.xlsx"),'w+b') do |f|
+ f.write file_data
+ end
+ end
+
+ def test_using_legacy_arguments
+ opts = @options.merge({
+ freeze: {rows: :all, columns: 2},
+ })
+
+ # Using Array Data
+ file_data = SpreadsheetArchitect.to_xlsx(opts)
+
+ File.open(base_path.join("freeze_#{__method__}.xlsx"),'w+b') do |f|
+ f.write file_data
+ end
+ end
+
+ def test_freeze_type
+ opts = @options.merge({
+ freeze: {row: (@options[:data].size-2), column: 16, type: "split_panes"},
+ })
+
+ # Using Array Data
+ file_data = SpreadsheetArchitect.to_xlsx(opts)
+
+ File.open(base_path.join("freeze_#{__method__}.xlsx"),'w+b') do |f|
+ f.write file_data
+ end
+ end
+
+ def test_panes_all_axlsx_options
+ opts = @options.merge({
+ freeze: {
+ row: (@options[:data].size-2),
+ column: 16,
+ state: "split",
+ #active_pane: "top_right",
+ #top_left_cell: "A2",
+ },
+ })
+
+ # Using Array Data
+ file_data = SpreadsheetArchitect.to_xlsx(opts)
+
+ File.open(base_path.join("freeze_#{__method__}.xlsx"),'w+b') do |f|
f.write file_data
end
end