diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 9dc3ab4..9b0e859 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -11,7 +11,7 @@ jobs: strategy: matrix: ruby: ["3.0", "3.1", "3.2", "3.3"] - gemfile: [dev/gemfiles/rails-6.1.x.gemfile, dev/gemfiles/rails-7.0.x.gemfile, Gemfile] + gemfile: [dev/gemfiles/rails-6.1.x.gemfile, dev/gemfiles/rails-7.0.x.gemfile, dev/gemfiles/rails-7.1.x.gemfile, Gemfile] env: # $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile }} steps: diff --git a/CHANGELOG.md b/CHANGELOG.md index acc52a9..a5c229b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,43 +6,47 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] +### Fixed + +* Add support for Rails v7.2 and drop support for Rails < 6.1 (#70) + ## Version 2.2.1 (2024-05-20) ## Fixed -* Add UMD build of Coconned missing in 2.2.0 +* Add UMD build of Coconned missing in 2.2.0 ## Version 2.2.0 (2024-05-20) ## Added * Compatibility with Trix (ActionText editor) (#65) -* Allow to setup custom replacements on newly built items before insert (#65) +* Allow to setup custom replacements on newly built items before insert (#65) ## Version 2.1.1 (2024-02-10) ### Fixed -* Template lookup in nested use cases (#61) +* Template lookup in nested use cases (#61) Template lookup used to be done on the whole HTML document so add triggers can be declared anywhere inside or outside a Cocooned container. In nested use cases, this could lead to incorrect template being used to build grand-child items when multiple child items had been built since the last form save. Lookup is now done first inside the closest Cocooned item if any to ensure the correct template will be used. ## Version 2.1.0 (2024-01-28) ### Added -* Add support for custom tag name to container helpers (#55, #56) - `cocooned_container` and `cocooned_item` now support an optional tag name as their first argument (as `content_tag` do) when the default `
` is not appropriate. +* Add support for custom tag name to container helpers (#55, #56) + `cocooned_container` and `cocooned_item` now support an optional tag name as their first argument (as `content_tag` do) when the default `
` is not appropriate. **Warning:** This change is not supposed to break anything as helpers prototypes stays the same and no other positional argument where really expected before. However, depending on how you used these helpers with previous releases, you may encounter unexpected side effects. * Documentation about nested use cases and event initialization (#59) ### Fixed -* Replacements operated on a newly built item in some nested use cases (#52, #57) +* Replacements operated on a newly built item in some nested use cases (#52, #57) Replacements are now done recursively in nested templates if any exists. This should fix field naming in newly built items when multiple Cocooned instance are nested and correct naming of sub-items depends on generated names for their parent. ### Changed -* Update test matrix (#54) +* Update test matrix (#54) Add Ruby 3.3. Drop Ruby 2.6 and Ruby 2.7 ## Version 2.0.4 (2023-11-23) @@ -81,9 +85,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), #### Features dropped without any replacements -* Use of a function as `data-association-insertion-node` on add triggers support have been dropped (#18) +* Use of a function as `data-association-insertion-node` on add triggers support have been dropped (#18) As HTML dataset are `DOMStringMap`, they only support strings as values. The only way to use a function to loop up for insertion node on an add trigger was to use jQuery (ex: `$(addTrigger).data('association-insertion-node', (add) => {})`). -* `data-remove-timeout` on remove triggers (#18) +* `data-remove-timeout` on remove triggers (#18) Items are now removed at the end of their hiding animation. #### Events listener now use `CustomEvent`s (#17) @@ -104,14 +108,14 @@ These features are now deprecated and emit a warning message: * `:insertion_traversal` option on `cocooned_add_item_link` (#18) Use a more specific selector as `data-association-insertion-node` (set through `:insertion_node`) instead. -* Importing `@notus.sh/cocooned/cocooned` in your JavaScript files (#22) +* Importing `@notus.sh/cocooned/cocooned` in your JavaScript files (#22) Import Cocooned from either `@notus.sh/cocooned`, `@notus.sh/cocooned/jquery` or `@notus.sh/cocooned/src/cocooned/cocooned` instead. These features are now deprecated but don't emit any warning message (sorry): -* Containers identified only by the `data-cocooned-options` attribute (#26) +* Containers identified only by the `data-cocooned-options` attribute (#26) Use the `cocooned_container` helper in your forms. -* Containers identified only by the `.cocooned-item` class (#26) +* Containers identified only by the `.cocooned-item` class (#26) Use the `cocooned_item` helper in your forms. These features were already deprecated but now emit a warning message: @@ -119,7 +123,7 @@ These features were already deprecated but now emit a warning message: * `link_to_add_association` (replaced by `cocooned_add_item_link`) * `link_to_remove_association` (replaced by `cocooned_remove_item_link`) * The `cocoon` I18n namespace (replaced by `cocooned`) -* `:render_option` option on `cocooned_add_item_link` / `link_to_add_association` +* `:render_option` option on `cocooned_add_item_link` / `link_to_add_association` Use `:form_options` and/or `:locals` instead. These features were already deprecated but (still) don't emit any warning message (sorry): @@ -134,7 +138,7 @@ All deprecated features will be removed in the next major release. * Add support for association scoped label to `cocooned_move_item_up_link` and `cocooned_move_item_down_link` (#11) * Replace dependency to jQuery by an optional jQuery integration (#22) -* Introduce `cocooned_container` and `cocooned_item` helpers to ease forms markup construction (#26) +* Introduce `cocooned_container` and `cocooned_item` helpers to ease forms markup construction (#26) * Allow to choose between links or buttons for triggers (#27) * Use Web Animation API for animations instead of CSS / jQuery (#29) @@ -202,7 +206,7 @@ All deprecated features will be removed in the next major release. * Drop support for Ruby 1.9 (thanks @simi) * Drop support for Rubinius, Ruby < 2.2 and Rails < 4.0 -* Drop support for custom wrapper class on item containers +* Drop support for custom wrapper class on item containers Originaly supported _via_ an option on `link_to_remove_association`. ### Deprecated @@ -213,7 +217,7 @@ The gem has been renamed to `cocooned`: * Generated add links class `add_fields` has been renamed `cocooned-add` * `link_to_remove_association` has been renamed `cocooned_remove_item_link` * Generated remove links class `remove_fields` has been renamed `cocooned-remove` -* `cocoon:*` and `*.cocoon` Javascript events have been renamed to `cocooned:*` and `*.cocooned` +* `cocoon:*` and `*.cocoon` Javascript events have been renamed to `cocooned:*` and `*.cocooned` (ex: `cocooned:before-insert`, `click.cocooned`) * The `cocoon` i18n scope have been renamed to `cocooned` * The `.nested-fields` default item wrapper class have been renamed to `cocooned-item` diff --git a/Gemfile.lock b/Gemfile.lock index f490cd0..3021415 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,7 +2,7 @@ PATH remote: . specs: cocooned (2.2.1) - rails (>= 6.0, <= 7.2) + rails (>= 6.1, <= 7.3) GEM remote: https://rubygems.org/ diff --git a/README.md b/README.md index 80995f2..fc41048 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Cocooned makes it easier to handle nested forms in Rails. -Cocooned is form builder-agnostic: it works with standard Rails (>= 6.0, < 7.2) form helpers, [Formtastic](https://github.com/justinfrench/formtastic) or [SimpleForm](https://github.com/plataformatec/simple_form). +Cocooned is form builder-agnostic: it works with standard Rails (>= 6.1, < 7.3) form helpers, [Formtastic](https://github.com/justinfrench/formtastic) or [SimpleForm](https://github.com/plataformatec/simple_form). 1. [Background](#some-background) 2. [Installation](#installation) @@ -109,14 +109,14 @@ We will build a form where we can dynamically add items to a list, remove or reo <% # `app/views/lists/_form.html.erb` %> <%= form_for @list do |form| %> <%= form.text_field :name %> - +

Items

<%= form.fields_for :items do |item_form| %> <%= item_form.label :description %> <%= item_form.text_field :description %> <%= item_form.check_box :done %> <% end %> - + <%= form.submit "Save" %> <% end %> ``` @@ -140,7 +140,7 @@ Change your main form as follow: <% # `app/views/lists/_form.html.erb` %> <%= form_for @list do |form| %> <%= form.text_field :name %> - +

Items

<%= form.fields_for :items do |item_form| - <%= item_form.label :description %> @@ -148,7 +148,7 @@ Change your main form as follow: - <%= item_form.check_box :done %> + <%= render 'item_fields', f: item_form %> <% end %> - + <%= form.submit "Save" %> <% end %> ``` @@ -170,14 +170,14 @@ Change your main form as follow: <% # `app/views/lists/_form.html.erb` %> <%= form_for @list do |form| %> <%= form.input :name %> - +

Items

+ <%= cocooned_container do %> <%= form.fields_for :items do |item_form| %> <%= render 'item_fields', f: item_form %> <% end %> + <% end %> - + <%= form.submit "Save" %> <% end %> ``` @@ -203,16 +203,16 @@ Change your main form as follow: <% # `app/views/lists/_form.html.erb` %> <%= form_for @list do |form| %> <%= form.input :name %> - +

Items

<%= cocooned_container do %> <%= form.fields_for :items do |item_form| %> <%= render 'item_fields', f: item_form %> <% end %> -+ ++ +

<%= cocooned_add_item_link 'Add an item', form, :items %>

<% end %> - + <%= form.submit "Save" %> <% end %> ``` @@ -284,9 +284,9 @@ The limit plugin requires you specify the maximum number of items allowed in the The reorderable plugin can be activated in two ways through the `cocooned_container` helper: -- With a boolean: `cocooned_container reorderable: true` +- With a boolean: `cocooned_container reorderable: true` Will use plugin's defaults (and start counting positions at 1) -- With a configuration hash: `cocooned_container reorderable: { startAt: 0 }` +- With a configuration hash: `cocooned_container reorderable: { startAt: 0 }` Will use given `:startAt` as base position To be able to move items up and down in your form and for positions to be saved, you need to change your sub form as follow: diff --git a/cocooned.gemspec b/cocooned.gemspec index e3d80ae..7fe4ec6 100644 --- a/cocooned.gemspec +++ b/cocooned.gemspec @@ -38,9 +38,9 @@ Gem::Specification.new do |spec| spec.files = `git ls-files -z`.split("\x0").reject do |f| f.match(excluded_dirs) || excluded_files.include?(f) end - spec.required_ruby_version = '>= 2.6' + spec.required_ruby_version = '>= 3.0' - spec.add_dependency 'rails', '>= 6.0', '<= 7.2' + spec.add_dependency 'rails', '>= 6.1', '<= 7.3' spec.add_development_dependency 'bundler', '~> 2.1' spec.add_development_dependency 'rake', '~> 13.0' diff --git a/dev/gemfiles/rails-7.1.x.gemfile b/dev/gemfiles/rails-7.1.x.gemfile new file mode 100644 index 0000000..fd26844 --- /dev/null +++ b/dev/gemfiles/rails-7.1.x.gemfile @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +source 'http://rubygems.org' + +gemspec path: '../..' + +group :development, :test do + gem 'psych', '< 4.0.0' + gem 'puma' + gem 'rails', '~> 7.1.0' + gem 'shakapacker', '~> 7.1.0' + gem 'sqlite3', '~> 1.4' + + gem 'formtastic', '~> 5.0' + gem 'nokogiri' + gem 'rspec-rails', '~> 6.0' + gem 'simplecov', require: false + gem 'simple_form', '~> 5.1' +end diff --git a/dev/rubocop.yml b/dev/rubocop.yml index 1957b5c..0d929b7 100644 --- a/dev/rubocop.yml +++ b/dev/rubocop.yml @@ -6,11 +6,8 @@ require: AllCops: NewCops: enable - TargetRubyVersion: 2.6 + TargetRubyVersion: 3.3 Naming/FileName: Exclude: - 'dev/**/*.gemfile' - -Rails/CompactBlank: - Enabled: false # As long as we support Rails 6.0 diff --git a/lib/cocooned/helpers/containers.rb b/lib/cocooned/helpers/containers.rb index 4827c45..7fd8fa7 100644 --- a/lib/cocooned/helpers/containers.rb +++ b/lib/cocooned/helpers/containers.rb @@ -64,8 +64,7 @@ def cocooned_item(*args, &block) protected def cocooned_wrapper_defaults(options, additional_classes, mark) - # TODO: Replace with compact_blank when dropping support for Rails 6.0 - classes = Array.wrap(options.delete(:class)).flat_map { |k| k.to_s.split }.reject(&:blank?) + classes = Array.wrap(options.delete(:class)).flat_map { |k| k.to_s.split }.compact_blank { class: (classes + additional_classes), data: { mark => true } } end diff --git a/lib/cocooned/tags/add.rb b/lib/cocooned/tags/add.rb index ae9b865..84d9c12 100644 --- a/lib/cocooned/tags/add.rb +++ b/lib/cocooned/tags/add.rb @@ -7,7 +7,6 @@ module AssociationOptions # :nodoc: protected def association_options - # TODO: Replace with compact_blank when dropping support for Rails 6.0 { association: association, template: html_template_name, @@ -15,7 +14,7 @@ def association_options association_insertion_node: options.delete(:insertion_node), association_insertion_method: options.delete(:insertion_method), association_insertion_traversal: options.delete(:insertion_traversal) - }.reject { |_, value| value.blank? } + }.compact_blank end end diff --git a/lib/cocooned/tags/base.rb b/lib/cocooned/tags/base.rb index c3ba57a..233dff5 100644 --- a/lib/cocooned/tags/base.rb +++ b/lib/cocooned/tags/base.rb @@ -47,14 +47,12 @@ def html_options @html_options ||= begin options[:class] = html_classes options[:data] = html_data - # TODO: Replace with compact_blank when dropping support for Rails 6.0 - options.reject { |_, value| value.blank? } + options.compact_blank end end def html_classes - # TODO: Replace with compact_blank when dropping support for Rails 6.0 - Array.wrap(options.delete(:class)).flat_map { |k| k.to_s.split }.reject(&:blank?) + Array.wrap(options.delete(:class)).flat_map { |k| k.to_s.split }.compact_blank end end end diff --git a/npm/README.md b/npm/README.md index 980cd82..ff2875b 100644 --- a/npm/README.md +++ b/npm/README.md @@ -4,7 +4,7 @@ This is a companion package for the [cocooned Ruby gem](https://rubygems.org/gem Cocooned makes it easier to handle nested forms in Rails. -Cocooned is form builder-agnostic: it works with standard Rails (>= 6.0, < 7.2) form helpers, [Formtastic](https://github.com/justinfrench/formtastic) or [SimpleForm](https://github.com/plataformatec/simple_form). +Cocooned is form builder-agnostic: it works with standard Rails (>= 6.1, < 7.3) form helpers, [Formtastic](https://github.com/justinfrench/formtastic) or [SimpleForm](https://github.com/plataformatec/simple_form). 1. [Installation](#installation) 2. [Import](#import), default, custom or with [jQuery integration](#jquery-integration) @@ -62,7 +62,7 @@ class Cocooned extends limitMixin(Base) { if ('cocoonedUuid' in container.dataset) { return Cocooned.getInstance(container.dataset.cocoonedUuid) } - + const cocooned = new this.constructor(container, options) cocooned.start() @@ -135,15 +135,15 @@ $('a selector to match container').cocooned(options) Any Cocooned instance supports following options: -#### `animate: [Boolean]` +#### `animate: [Boolean]` Toggle animations when moving or removing an item from the form. Default value depend on detected support of the [Web Animation API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API). -#### `duration: [Integer]` +#### `duration: [Integer]` Duration of animations, in milliseconds. Defaults to 450. -#### `animator: [Function]` +#### `animator: [Function]` A function returning animation keyframes, either an array of keyframe objects or a keyframe object whose properties are arrays of values to iterate over. See [Keyframe Formats documentation](https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API/Keyframe_Formats) for more details. @@ -172,7 +172,7 @@ When your collection is modified, the following events can be triggered: The limit plugin can trigger its own event: -* `cocooned:limit-reached`: when the limit is reached (when a new item should be inserted but won't) +* `cocooned:limit-reached`: when the limit is reached (when a new item should be inserted but won't) **Note:** Listeners on this event receive the event object that originally triggered the refused insertion. And so does the reorderable plugin: @@ -193,9 +193,9 @@ container.addEventListener('cocooned:before-insert', event => { Event handlers receive a `CustomEvent` with following detail: * `event.detail.link`, the clicked link or button -* `event.detail.node`, the item that will be added, removed or moved. +* `event.detail.node`, the item that will be added, removed or moved. Unavailable on `cocooned:limit-reached`, `cocooned:before-reindex` and `cocooned:after-reindex` -* `event.nodes`, the nested items that will be or just have been reindexed. +* `event.nodes`, the nested items that will be or just have been reindexed. Available on `cocooned:before-reindex` and `cocooned:after-reindex` * `event.detail.cocooned`, the Cocooned instance. * `event.detail.originalEvent`, the original (browser) event.