inline_forms 7.5.2 → 7.9.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +110 -0
- data/README.rdoc +10 -0
- data/app/assets/javascripts/inline_forms/inline_forms.js +3 -10
- data/app/assets/stylesheets/inline_forms/inline_forms.scss +5 -4
- data/app/controllers/concerns/versions_concern.rb +0 -2
- data/app/controllers/inline_forms_controller.rb +76 -21
- data/app/helpers/inline_forms_helper.rb +42 -28
- data/app/views/inline_forms/_close.html.erb +9 -7
- data/app/views/inline_forms/_edit.html.erb +1 -1
- data/app/views/inline_forms/_list.html.erb +6 -21
- data/app/views/inline_forms/_new.html.erb +3 -5
- data/app/views/inline_forms/_show.html.erb +0 -26
- data/app/views/inline_forms/_versions.html.erb +5 -4
- data/app/views/inline_forms/_versions_list.html.erb +8 -8
- data/app/views/inline_forms/row_close.html.erb +10 -2
- data/app/views/inline_forms/versions_panel.html.erb +5 -2
- data/app/views/layouts/application.html.erb +2 -4
- data/app/views/layouts/inline_forms.html.erb +2 -5
- data/archived/README.md +47 -0
- data/archived/form_elements/README.md +27 -0
- data/archived/form_elements/chicas/README.md +31 -0
- data/archived/form_elements/geo_code_curacao/README.md +62 -0
- data/{app → archived/form_elements/geo_code_curacao/app}/helpers/form_elements/geo_code_curacao.rb +0 -1
- data/archived/form_elements/geo_code_curacao/app/views/geo_code_curacao/list_streets.html.erb +1 -0
- data/archived/form_elements/geo_code_curacao/app/views/geo_code_curacao/list_streets.js.erb +1 -0
- data/archived/form_elements/kansen_slider/README.md +31 -0
- data/archived/form_elements/tree/README.md +47 -0
- data/archived/form_elements/tree/app/views/inline_forms/_show_tree.html.erb +30 -0
- data/{app → archived/form_elements/tree/app}/views/inline_forms/_tree.html.erb +18 -5
- data/bin/inline_forms_installer_core.rb +70 -5
- data/docs/ujs-to-turbo.md +36 -37
- data/lib/generators/assets/stylesheets/inline_forms.scss +5 -4
- data/lib/inline_forms/archived_form_elements.rb +70 -0
- data/lib/inline_forms/version.rb +1 -1
- data/lib/inline_forms.rb +3 -1
- data/lib/installer_templates/example_app_tests/test/integration/example_app_apartment_field_turbo_test.rb +6 -7
- data/lib/installer_templates/example_app_tests/test/integration/example_app_apartment_name_required_test.rb +21 -0
- data/lib/installer_templates/example_app_tests/test/integration/example_app_apartment_photos_pagination_test.rb +28 -0
- data/lib/installer_templates/example_app_tests/test/integration/example_app_apartment_row_turbo_test.rb +14 -5
- data/lib/installer_templates/example_app_tests/test/integration/example_app_apartment_top_level_new_test.rb +30 -60
- data/lib/installer_templates/example_app_tests/test/integration/example_app_apartment_top_level_pagination_test.rb +40 -0
- data/lib/installer_templates/example_app_tests/test/integration/example_app_apartment_versions_turbo_test.rb +93 -0
- data/lib/installer_templates/example_app_tests/test/integration/example_app_photo_revert_test.rb +94 -0
- data/lib/installer_templates/example_app_tests/test/integration/example_app_turbo_layout_test.rb +6 -9
- data/lib/installer_templates/example_app_tests/test/models/example_app_apartment_name_validation_test.rb +16 -0
- data/test/archived_form_elements_test.rb +41 -0
- data/test/form_element_from_callee_test.rb +2 -2
- metadata +25 -20
- data/app/views/geo_code_curacao/list_streets.html.erb +0 -1
- data/app/views/geo_code_curacao/list_streets.js.erb +0 -1
- data/app/views/inline_forms/close.js.erb +0 -4
- data/app/views/inline_forms/list.js.erb +0 -1
- data/app/views/inline_forms/new.js.erb +0 -1
- data/app/views/inline_forms/record_destroyed.js.erb +0 -1
- data/app/views/inline_forms/show.js.erb +0 -1
- data/app/views/inline_forms/show_undo.js.erb +0 -1
- data/app/views/inline_forms/versions.js.erb +0 -4
- data/app/views/inline_forms/versions_list.js.erb +0 -1
- /data/{app → archived/form_elements/chicas/app}/helpers/form_elements/chicas_dropdown_with_family_members.rb +0 -0
- /data/{app → archived/form_elements/chicas/app}/helpers/form_elements/chicas_family_photo_list.rb +0 -0
- /data/{app → archived/form_elements/chicas/app}/helpers/form_elements/chicas_photo_list.rb +0 -0
- /data/{app → archived/form_elements/geo_code_curacao/app}/controllers/geo_code_curacao_controller.rb +0 -0
- /data/{app → archived/form_elements/geo_code_curacao/app}/models/geo_code_curacao.rb +0 -0
- /data/{app → archived/form_elements/kansen_slider/app}/helpers/form_elements/kansen_slider.rb +0 -0
- /data/{app → archived/form_elements/tree/app}/helpers/form_elements/move.rb +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9cce3cdf65d2a40a3481fba51c95e57bfa6a65cd4a73359ad974fc327252dd7a
|
|
4
|
+
data.tar.gz: 7f57a6489ef1d88328474330fe70492f1266e5e394163260b2cc773c414571b8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fb6275f4b67706bee0e3b263e3b54b5a5a8be8a7f20676fd0ea0504be0e98edc3e3f41c98a807f1f28cdc4f5367e9a0f9a8c895bfa052978483f09148e1904e7
|
|
7
|
+
data.tar.gz: f168431ca3b73f07cfd2190b21ba211be91ab529861751d588ff33ed2e832e985411ec414ae2c5f958a9dd867e84083b5841e79424d2662bc558f35c10caac15
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,116 @@ All notable changes to this project are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [7.9.1] - 2026-05-17
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **Example app — apartment name required:** the `--example` installer injects `validates :name, presence: true` on `Apartment`. Top-level create without a name re-renders the new form instead of persisting.
|
|
12
|
+
- **Regression tests:** `example_app_apartment_name_validation_test.rb` (model); `example_app_apartment_name_required_test.rb` (Turbo create).
|
|
13
|
+
|
|
14
|
+
### Verified
|
|
15
|
+
|
|
16
|
+
- **`bundle exec rails test`** (new validation tests) in `--example` MyApp — **3 runs, 10 assertions, 0 failures**.
|
|
17
|
+
|
|
18
|
+
## [7.9.0] - 2026-05-16
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- **Restore rich_text (ActionText) versions from the versions panel:** the Restore link now renders for `:rich_text` entries too. `InlineFormsController#revert` reifies the `ActionText::RichText` row, saves it, and `touch`es the parent so any timestamp display refreshes.
|
|
23
|
+
- **CarrierWave history for `image_field` / `multi_image_field`:** the installer ships a `config/initializers/carrierwave.rb` with `remove_previously_stored_files_after_update = false` and patches the generated `app/uploaders/image_uploader.rb` with a no-op `remove!` plus a per-upload UUID `filename` prefix. PaperTrail reverts on an image column now restore the previous bytes (not just the previous filename). Source: <https://stackoverflow.com/questions/9423279/papertrail-and-carrierwave> (Answers 2, 4, 5).
|
|
24
|
+
- **Regression tests:** `example_app_photo_revert_test.rb` (image-column revert restores bytes); rich_text revert assertions in `example_app_apartment_versions_turbo_test.rb`.
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- **`render_revert_turbo_streams`:** no longer mutates `@update_span` mid-method. The row and versions frames are rendered with explicit `locals: { update_span:, object:, inline_forms_turbo_row: }`. The `row_close` / `versions_panel` templates and their `_close` / `_versions` partials prefer `local_assigns[:…]` and fall back to the matching ivar.
|
|
29
|
+
- **Frame ids in revert:** `row_id` and `versions_id` now derive from `@parent` (the rich_text branch sets `@parent = @rich_text_record.record`), so revert works identically for primary and rich_text versions.
|
|
30
|
+
|
|
31
|
+
### Removed
|
|
32
|
+
|
|
33
|
+
- **`format.html` fallback in `revert`:** the action only responds with `turbo_stream` now. The "Turbo POST on row frame" regression test was updated to send `Accept: text/vnd.turbo-stream.html`.
|
|
34
|
+
|
|
35
|
+
### Trade-offs
|
|
36
|
+
|
|
37
|
+
- The `ImageUploader` no longer deletes previous files on update or destroy. Files accumulate; sweep tooling is out of scope (would have to reconcile with `PaperTrail::Version#object` snapshots across the whole table).
|
|
38
|
+
|
|
39
|
+
### Verified
|
|
40
|
+
|
|
41
|
+
- **`bundle exec rails test`** in `--example` MyApp — **68 runs, 358 assertions, 0 failures, 0 errors, 0 skips**.
|
|
42
|
+
|
|
43
|
+
## [7.8.1] - 2026-05-16
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
|
|
47
|
+
- **Restore from versions panel (Turbo 2 + Drive):** POSTs from inside `<turbo-frame id="…_versions">` sent `Turbo-Frame: …_versions` while the server returned only the **row** frame, so Turbo showed **Content missing**. Restore links now request **`turbo_stream`**; **`revert`** responds with **`turbo_stream.replace`** for both the row and the versions panel.
|
|
48
|
+
|
|
49
|
+
### Added
|
|
50
|
+
|
|
51
|
+
- **Regression tests:** versions list restore link carries `data-turbo-stream`; revert with versions-frame header returns stream (`example_app_apartment_versions_turbo_test.rb`).
|
|
52
|
+
|
|
53
|
+
### Verified
|
|
54
|
+
|
|
55
|
+
- **`bundle exec rails test`** in `--example` MyApp — **67 runs, 342 assertions, 0 failures**.
|
|
56
|
+
|
|
57
|
+
## [7.8.0] - 2026-05-16
|
|
58
|
+
|
|
59
|
+
### Changed
|
|
60
|
+
|
|
61
|
+
- **Step 5 (UJS → Turbo):** **Turbo Drive** left at the default (**enabled**); removed **`Turbo.session.drive = false`** from **`inline_forms`** and **`application`** layouts.
|
|
62
|
+
- **`app/assets/javascripts/inline_forms/inline_forms.js`:** dropped **`jquery_ujs`** and **`jquery.remotipart`**; inline navigation uses Turbo only.
|
|
63
|
+
- **Installer Gemfile** (`bin/inline_forms_installer_core.rb`): removed **`remotipart`**; updated **`turbo-rails`** comment.
|
|
64
|
+
- **Helpers / partials:** removed **`remote: true`** fallbacks (`close_link`, toolbar, new/versions links, field cancel, `link_to_inline_edit` legacy branch, **`_close`**, **`_new`**); all use **`data-turbo`** + frame targets.
|
|
65
|
+
|
|
66
|
+
### Verified
|
|
67
|
+
|
|
68
|
+
- **`bundle exec rails test`** in `--example` MyApp — **65 runs, 330 assertions, 0 failures**.
|
|
69
|
+
|
|
70
|
+
## [7.7.3] - 2026-05-16
|
|
71
|
+
|
|
72
|
+
### Changed
|
|
73
|
+
|
|
74
|
+
- **Step 4 (UJS → Turbo) — versions panel:** `VersionsConcern#list_versions` is **HTML-only** (`versions_panel` / `versions_list_panel` inside matching `<turbo-frame>`). Removed **`versions.js.erb`** and **`versions_list.js.erb`**.
|
|
75
|
+
|
|
76
|
+
### Fixed
|
|
77
|
+
|
|
78
|
+
- **Nested Photo (and other `not_accessible_through_html?` children) versions restore:** `_versions_list` revert links targeted `photo_<id>` but nested list rows use `apartment_<aid>_photo_<id>`. Turbo could not find that frame, fell back to `photo_<id>_versions`, and `revert` returned **406** (`row_html_turbo_allowed?` false for bare `photo_<id>`). **`inline_forms_row_turbo_frame_id`** now matches `_list.html.erb` row ids.
|
|
79
|
+
|
|
80
|
+
### Added
|
|
81
|
+
|
|
82
|
+
- **Regression tests:** expanded-row versions open link (Turbo, not `data-remote`); revert from versions list via Turbo POST (`example_app_apartment_versions_turbo_test.rb`); nested Photo versions list restore + Turbo POST revert (`example_app_apartment_photos_pagination_test.rb`).
|
|
83
|
+
|
|
84
|
+
### Verified
|
|
85
|
+
|
|
86
|
+
- **`bundle exec rails test`** in `--example` MyApp — **65 runs, 330 assertions, 0 failures**.
|
|
87
|
+
|
|
88
|
+
## [7.7.0] - 2026-05-16
|
|
89
|
+
|
|
90
|
+
### Changed
|
|
91
|
+
|
|
92
|
+
- **Step 4 (UJS → Turbo) — top-level list + create:** `/apartments` index list root is **`<turbo-frame id="apartments_list">`** with in-frame pagination (`update=apartments_list`); **`+ new` / cancel / create** use Turbo HTML (`new_record` / `create_list_frame`) instead of **`new.js.erb`** / **`list.js.erb`**. **`#outer_container > turbo-frame.list_container { width: 100% }`** fixes the 7.5.2 layout collapse.
|
|
93
|
+
- **`:tree` / `:move` archived:** hierarchical child list (**`_tree.html.erb`**) and reparent helper (**`move.rb`**) moved to **`archived/form_elements/tree/`** — they expect host-app tree APIs (`#children`, `#hash_tree_to_collection`, `#add_child`), not defined in the gem; no example-app model. Registry blocks `:tree` / `:move` in `inline_forms_attribute_list`.
|
|
94
|
+
- **Removed row/list UJS templates:** **`show.js.erb`**, **`close.js.erb`**, **`record_destroyed.js.erb`**, **`show_undo.js.erb`**, **`new.js.erb`**, **`list.js.erb`**; row actions and list flows use **`format.html`** only.
|
|
95
|
+
|
|
96
|
+
### Added
|
|
97
|
+
|
|
98
|
+
- **Regression tests:** `example_app_apartment_top_level_new_test.rb` (Turbo new/cancel/create), `example_app_apartment_top_level_pagination_test.rb`.
|
|
99
|
+
|
|
100
|
+
### Verified
|
|
101
|
+
|
|
102
|
+
- **`bundle exec rails test`** in `--example` MyApp — **62 runs, 312 assertions, 0 failures**.
|
|
103
|
+
|
|
104
|
+
## [7.6.0] - 2026-05-16
|
|
105
|
+
|
|
106
|
+
### Changed
|
|
107
|
+
|
|
108
|
+
- **Project-specific form elements archived (not loaded by default):** `:geo_code_curacao` (helper + model + controller + views), **`chicas_*`** (`:chicas_photo_list`, `:chicas_family_photo_list`, `:chicas_dropdown_with_family_members`), and **`:kansen_slider`**. Sources live under **`archived/form_elements/`** with per-folder README restore steps.
|
|
109
|
+
- **Registry:** **`InlineForms::ARCHIVED_FORM_ELEMENTS`**; boot raises **`ArchivedFormElementError`** if a model still declares an archived symbol (including **`:absence_list`**, removed in 6.3.0 without source in tree).
|
|
110
|
+
- **Versioned archive:** **`archived/README.md`** catalogs all retired features.
|
|
111
|
+
- **`_edit.html.erb`:** removed **`kansen_slider`** from `@BUTTONS_UNDER` (element archived).
|
|
112
|
+
|
|
113
|
+
### Upgrade notes
|
|
114
|
+
|
|
115
|
+
- **Breaking:** Remove or vendor archived symbols from `inline_forms_attribute_list`: **`:geo_code_curacao`**, **`:chicas_*`**, **`:kansen_slider`**. Copy from the matching **`archived/form_elements/<name>/`** README (geo also needs host route `get "geo_code_curacao", to: "geo_code_curacao#list_streets"`).
|
|
116
|
+
|
|
7
117
|
## [7.5.2] - 2026-05-16
|
|
8
118
|
|
|
9
119
|
### Fixed
|
data/README.rdoc
CHANGED
|
@@ -48,6 +48,16 @@ The +:image_field+ form element uses CarrierWave. Generated apps depend on +carr
|
|
|
48
48
|
|
|
49
49
|
To switch to S3, add +carrierwave-aws+ (or use the bundled fog backend) and configure a +CarrierWave.configure+ block in +config/initializers/carrierwave.rb+; nothing in inline_forms hard-codes local storage.
|
|
50
50
|
|
|
51
|
+
=== PaperTrail-driven restore keeps previous image bytes
|
|
52
|
+
|
|
53
|
+
PaperTrail snapshots the column scalar (a CarrierWave filename) on update; CarrierWave's defaults overwrite the previous file on disk and reuse the same filename, so a vanilla +version.reify; save!+ ends up restoring a filename whose bytes are gone. The generated +ImageUploader+ ships three knobs that fix this:
|
|
54
|
+
|
|
55
|
+
* +CarrierWave.configure { |c| c.remove_previously_stored_files_after_update = false }+ in +config/initializers/carrierwave.rb+ — covers +:multi_image_field+ uploaders too.
|
|
56
|
+
* +remove!+ overridden to a no-op, so hard-destroyed records keep their bytes and revert-after-destroy can still find them.
|
|
57
|
+
* +filename+ prefixed with a per-upload UUID, so successive uploads never collide on disk.
|
|
58
|
+
|
|
59
|
+
Trade-off: files accumulate on disk; periodic sweeping is out of scope of the gem. Source: https://stackoverflow.com/questions/9423279/papertrail-and-carrierwave (Answers 2, 4 and 5).
|
|
60
|
+
|
|
51
61
|
For long text fields, use +:plain_text+ for a plain textarea backed by a DB +text+ column, or +:rich_text+ for ActionText/Trix content. +:plain_text+ requires an actual column on the model table; if the column is missing, inline_forms now raises +InlineForms::PlainTextColumnMissingError+ during controller boot/runtime checks.
|
|
52
62
|
|
|
53
63
|
Note: generated apps also depend on ActiveStorage transitively because the +:rich_text+ form element uses ActionText (+active_storage:install+ runs during +inline_forms create+). Image uploads still go through CarrierWave; ActiveStorage is only there to back ActionText embeds.
|
|
@@ -1,24 +1,17 @@
|
|
|
1
1
|
//= require jquery
|
|
2
|
-
//= require jquery_ujs
|
|
3
2
|
//= require jquery.ui.all
|
|
4
3
|
//= require jquery.timepicker.js
|
|
5
4
|
//= require foundation
|
|
6
|
-
//= require jquery.remotipart
|
|
7
5
|
//= require autocomplete-rails
|
|
8
6
|
|
|
9
7
|
// Turbo / Hotwire is intentionally NOT required into this Sprockets bundle.
|
|
10
8
|
// `turbo-rails` ships only an ES-module build of turbo (`app/assets/javascripts/turbo.js`
|
|
11
9
|
// ends with `export { Turbo, cable }`). Concatenating that into a regular
|
|
12
|
-
// `<script>` bundle produces a parse error at the top-level `export
|
|
13
|
-
// silently kills jquery-ujs initialization (forms then submit as plain
|
|
14
|
-
// HTML POST and inline_forms controllers respond with `format.js` only,
|
|
15
|
-
// raising `ActionController::UnknownFormat`).
|
|
10
|
+
// `<script>` bundle produces a parse error at the top-level `export`.
|
|
16
11
|
//
|
|
17
12
|
// Turbo is loaded separately by `app/views/layouts/inline_forms.html.erb`
|
|
18
|
-
// (and `application.html.erb`) as `<script type="module"
|
|
19
|
-
//
|
|
20
|
-
// working unchanged. `<turbo-frame>` and `format.turbo_stream` are
|
|
21
|
-
// available for the per-view conversions that follow.
|
|
13
|
+
// (and `application.html.erb`) as `<script type="module">`. Inline flows use
|
|
14
|
+
// `<turbo-frame>` + HTML responses; jquery-ujs / remotipart were removed in 7.8.0.
|
|
22
15
|
|
|
23
16
|
$(function(){ $(document).foundation(); });
|
|
24
17
|
// initialize datepickers
|
|
@@ -224,13 +224,14 @@ select:hover, select:focus {
|
|
|
224
224
|
font-size: 110%;
|
|
225
225
|
}
|
|
226
226
|
// Custom elements default to `display: inline`, which collapses the row layout
|
|
227
|
-
// of
|
|
228
|
-
// hides its rows under the fixed top bar. Force block layout so frames behave
|
|
229
|
-
// like the legacy `<div class="list_container">` and `<div class="row">` they
|
|
230
|
-
// replaced (see app/views/inline_forms/_list.html.erb).
|
|
227
|
+
// of a top-level `<turbo-frame id="apartments_list">` inside `#outer_container`.
|
|
231
228
|
turbo-frame {
|
|
232
229
|
display: block;
|
|
233
230
|
}
|
|
231
|
+
#outer_container > turbo-frame.list_container {
|
|
232
|
+
display: block;
|
|
233
|
+
width: 100%;
|
|
234
|
+
}
|
|
234
235
|
.list_container {
|
|
235
236
|
.row {
|
|
236
237
|
font-size: 1.2rem;
|
|
@@ -12,12 +12,10 @@ module VersionsConcern
|
|
|
12
12
|
if close
|
|
13
13
|
respond_to do |format|
|
|
14
14
|
format.html { render "inline_forms/versions_panel", layout: "turbo_rails/frame" }
|
|
15
|
-
format.js { render :versions }
|
|
16
15
|
end
|
|
17
16
|
else
|
|
18
17
|
respond_to do |format|
|
|
19
18
|
format.html { render "inline_forms/versions_list_panel", layout: "turbo_rails/frame" }
|
|
20
|
-
format.js { render :versions_list }
|
|
21
19
|
end
|
|
22
20
|
end
|
|
23
21
|
end
|
|
@@ -44,7 +44,12 @@ class InlineFormsController < ApplicationController
|
|
|
44
44
|
foreign_key = @Klass.reflect_on_association(@parent_class.underscore.to_sym).options[:foreign_key] || @parent_class.foreign_key
|
|
45
45
|
conditions = [ "#{foreign_key} = ?", @parent_id ]
|
|
46
46
|
end
|
|
47
|
-
#
|
|
47
|
+
# CanCan's load_and_authorize_resource sets @apartments (etc.); keep @objects in sync.
|
|
48
|
+
collection_ivar = :"@#{controller_name}"
|
|
49
|
+
if instance_variable_defined?(collection_ivar)
|
|
50
|
+
loaded = instance_variable_get(collection_ivar)
|
|
51
|
+
@objects = loaded unless loaded.nil?
|
|
52
|
+
end
|
|
48
53
|
@objects ||= @Klass.accessible_by(current_ability) if cancan_enabled?
|
|
49
54
|
@objects ||= @Klass
|
|
50
55
|
@objects = @objects.order(@Klass.table_name + "." + @Klass.order_by_clause) if @Klass.respond_to?(:order_by_clause) && ! @Klass.order_by_clause.nil?
|
|
@@ -79,12 +84,14 @@ class InlineFormsController < ApplicationController
|
|
|
79
84
|
format.html do
|
|
80
85
|
if @parent_class.present?
|
|
81
86
|
render_nested_associated_list_html
|
|
87
|
+
elsif turbo_frame_request? && list_frame_id?(params[:update])
|
|
88
|
+
@ul_needed = true
|
|
89
|
+
render "inline_forms/_list", layout: "turbo_rails/frame"
|
|
82
90
|
else
|
|
83
91
|
render "inline_forms/_list", layout: "inline_forms"
|
|
84
92
|
end
|
|
85
93
|
end
|
|
86
94
|
end
|
|
87
|
-
format.js { render :list }
|
|
88
95
|
end
|
|
89
96
|
end
|
|
90
97
|
|
|
@@ -103,8 +110,7 @@ class InlineFormsController < ApplicationController
|
|
|
103
110
|
|
|
104
111
|
@object.inline_forms_attribute_list = @inline_forms_attribute_list if @inline_forms_attribute_list
|
|
105
112
|
respond_to do |format|
|
|
106
|
-
format.html { render_turbo_new } if
|
|
107
|
-
format.js { }
|
|
113
|
+
format.html { render_turbo_new } if html_list_flow_allowed?
|
|
108
114
|
end
|
|
109
115
|
end
|
|
110
116
|
|
|
@@ -128,7 +134,7 @@ class InlineFormsController < ApplicationController
|
|
|
128
134
|
attributes = @inline_forms_attribute_list || @object.inline_forms_attribute_list
|
|
129
135
|
attributes.each do | attribute, name, form_element |
|
|
130
136
|
InlineForms.assert_plain_text_column!(object: @object, attribute: attribute, form_element: form_element)
|
|
131
|
-
send("#{form_element.to_s}_update", @object, attribute) unless form_element == :
|
|
137
|
+
send("#{form_element.to_s}_update", @object, attribute) unless form_element == :associated || (cancan_enabled? && cannot?(:read, @object, attribute))
|
|
132
138
|
end
|
|
133
139
|
@parent_class = params[:parent_class]
|
|
134
140
|
@parent_id = params[:parent_id]
|
|
@@ -150,16 +156,14 @@ class InlineFormsController < ApplicationController
|
|
|
150
156
|
@objects = @objects.where(conditions).paginate(:page => params[:page])
|
|
151
157
|
@object = nil
|
|
152
158
|
respond_to do |format|
|
|
153
|
-
format.html {
|
|
154
|
-
format.js { render :list }
|
|
159
|
+
format.html { render_list_frame_after_save } if html_list_flow_allowed?
|
|
155
160
|
end
|
|
156
161
|
else
|
|
157
162
|
flash.now[:header] = ["Kan #{@object.class.to_s.underscore} niet aanmaken."]
|
|
158
163
|
flash.now[:error] = @object.errors.to_a
|
|
159
164
|
respond_to do |format|
|
|
160
165
|
@object.inline_forms_attribute_list = attributes
|
|
161
|
-
format.html { render_turbo_new } if
|
|
162
|
-
format.js { render :new }
|
|
166
|
+
format.html { render_turbo_new } if html_list_flow_allowed?
|
|
163
167
|
end
|
|
164
168
|
end
|
|
165
169
|
end
|
|
@@ -203,10 +207,8 @@ class InlineFormsController < ApplicationController
|
|
|
203
207
|
@attributes = @object.inline_forms_attribute_list
|
|
204
208
|
if close
|
|
205
209
|
format.html { render_row_turbo(:close) } if row_html_turbo_allowed?
|
|
206
|
-
format.js { render :close }
|
|
207
210
|
else
|
|
208
211
|
format.html { render_row_turbo(:show) } if row_html_turbo_allowed?
|
|
209
|
-
format.js { render :show }
|
|
210
212
|
end
|
|
211
213
|
end
|
|
212
214
|
else
|
|
@@ -223,7 +225,6 @@ class InlineFormsController < ApplicationController
|
|
|
223
225
|
@object.soft_delete(current_user)
|
|
224
226
|
respond_to do |format|
|
|
225
227
|
format.html { render_row_turbo(:close) } if row_html_turbo_allowed?
|
|
226
|
-
format.js { render :close }
|
|
227
228
|
end
|
|
228
229
|
end
|
|
229
230
|
|
|
@@ -234,7 +235,6 @@ class InlineFormsController < ApplicationController
|
|
|
234
235
|
@object.soft_restore
|
|
235
236
|
respond_to do |format|
|
|
236
237
|
format.html { render_row_turbo(:close) } if row_html_turbo_allowed?
|
|
237
|
-
format.js { render :close }
|
|
238
238
|
end
|
|
239
239
|
end
|
|
240
240
|
|
|
@@ -247,23 +247,42 @@ class InlineFormsController < ApplicationController
|
|
|
247
247
|
@object.destroy
|
|
248
248
|
respond_to do |format|
|
|
249
249
|
format.html { render_row_turbo_destroyed } if row_html_turbo_allowed?
|
|
250
|
-
format.js { render :record_destroyed }
|
|
251
250
|
end
|
|
252
251
|
end
|
|
253
252
|
end
|
|
254
253
|
|
|
255
254
|
# :revert works like undo.
|
|
256
255
|
# Thanks Ryan Bates: http://railscasts.com/episodes/255-undo-with-paper-trail
|
|
256
|
+
#
|
|
257
|
+
# Two reify paths:
|
|
258
|
+
#
|
|
259
|
+
# * Primary version: the reified object IS the row (Apartment, Photo, ...).
|
|
260
|
+
# Save it and we're done; CarrierWave keeps the previous file on disk
|
|
261
|
+
# (see app/uploaders/image_uploader.rb) so a restored `image` column
|
|
262
|
+
# still points at real bytes.
|
|
263
|
+
# * ActionText (rich_text) version: the reified object is the
|
|
264
|
+
# `ActionText::RichText` row hanging off the parent. Save the rich text,
|
|
265
|
+
# then `touch` the parent so any timestamp display refreshes. Frame ids
|
|
266
|
+
# below derive from `@parent` for both branches.
|
|
257
267
|
def revert
|
|
258
268
|
@update_span = params[:update]
|
|
259
269
|
if current_user.role? :superadmin
|
|
260
270
|
@version = PaperTrail::Version.find(params[:id])
|
|
261
271
|
@object = @version.reify
|
|
262
|
-
@object.
|
|
263
|
-
|
|
272
|
+
if defined?(ActionText::RichText) && @object.is_a?(ActionText::RichText)
|
|
273
|
+
@rich_text_record = @object
|
|
274
|
+
@parent = @rich_text_record.record
|
|
275
|
+
@rich_text_record.save!
|
|
276
|
+
@parent.touch if @parent.respond_to?(:touch)
|
|
277
|
+
else
|
|
278
|
+
@parent = @object
|
|
279
|
+
@parent.save!
|
|
280
|
+
end
|
|
281
|
+
authorize!(:revert, @parent) if cancan_enabled?
|
|
282
|
+
return unless row_html_turbo_allowed?
|
|
283
|
+
|
|
264
284
|
respond_to do |format|
|
|
265
|
-
format.
|
|
266
|
-
format.js { render :close }
|
|
285
|
+
format.turbo_stream { render_revert_turbo_streams }
|
|
267
286
|
end
|
|
268
287
|
end
|
|
269
288
|
end
|
|
@@ -282,6 +301,30 @@ class InlineFormsController < ApplicationController
|
|
|
282
301
|
|
|
283
302
|
private
|
|
284
303
|
|
|
304
|
+
# Versions list lives in +<turbo-frame id="…_versions">+; POST +restore+ would otherwise
|
|
305
|
+
# send +Turbo-Frame: …_versions+ while +row_close+ only returns the row frame. Stream
|
|
306
|
+
# replaces both the row and the versions panel in one response.
|
|
307
|
+
def render_revert_turbo_streams
|
|
308
|
+
row_id = helpers.inline_forms_row_turbo_frame_id(@parent)
|
|
309
|
+
versions_id = "#{@parent.class.name.underscore}_#{@parent.id}_versions"
|
|
310
|
+
row_html = render_to_string(
|
|
311
|
+
"inline_forms/row_close",
|
|
312
|
+
layout: false,
|
|
313
|
+
formats: [:html],
|
|
314
|
+
locals: { update_span: row_id, object: @parent, inline_forms_turbo_row: true }
|
|
315
|
+
)
|
|
316
|
+
versions_html = render_to_string(
|
|
317
|
+
"inline_forms/versions_panel",
|
|
318
|
+
layout: false,
|
|
319
|
+
formats: [:html],
|
|
320
|
+
locals: { update_span: versions_id, object: @parent, inline_forms_turbo_row: true }
|
|
321
|
+
)
|
|
322
|
+
render turbo_stream: [
|
|
323
|
+
turbo_stream.replace(row_id, row_html),
|
|
324
|
+
turbo_stream.replace(versions_id, versions_html)
|
|
325
|
+
]
|
|
326
|
+
end
|
|
327
|
+
|
|
285
328
|
# HTML field edit/show inside a +<turbo-frame>+ (Step 3). Scalar fields no longer
|
|
286
329
|
# use UJS; +format.html+ is always registered for edit/update/single-attribute show.
|
|
287
330
|
#
|
|
@@ -289,9 +332,8 @@ class InlineFormsController < ApplicationController
|
|
|
289
332
|
# +*_show+ helpers it wraps) to emit Turbo data attributes. The flag is set in
|
|
290
333
|
# +_show.html.erb+ when a row first opens, but bare +field_show+ / +field_edit+
|
|
291
334
|
# responses (on +cancel+ / +update+) do not re-render +_show+. Without setting
|
|
292
|
-
# it here the link in the swapped frame
|
|
293
|
-
#
|
|
294
|
-
# registers +format.html+, so the click silently fails (no swap, no edit form).
|
|
335
|
+
# it here the link in the swapped frame would not target the field frame and
|
|
336
|
+
# inline edit would not open reliably.
|
|
295
337
|
def render_turbo_field(template, turbo_field_show: false)
|
|
296
338
|
@turbo_frame = true if template == :field_edit
|
|
297
339
|
@turbo_field_show_turbo_frame = turbo_field_show
|
|
@@ -315,10 +357,23 @@ class InlineFormsController < ApplicationController
|
|
|
315
357
|
end
|
|
316
358
|
|
|
317
359
|
# Nested has_many +new+ / cancel / +create+ inside a parent +<turbo-frame>+ (e.g. Apartment → Photo).
|
|
360
|
+
def html_list_flow_allowed?
|
|
361
|
+
params[:update].present? && (@parent_class.present? || !@Klass.not_accessible_through_html?)
|
|
362
|
+
end
|
|
363
|
+
|
|
318
364
|
def associated_list_html_allowed?
|
|
319
365
|
@parent_class.present? && params[:update].present?
|
|
320
366
|
end
|
|
321
367
|
|
|
368
|
+
def list_frame_id?(update)
|
|
369
|
+
update.present? && update.to_s.end_with?("_list")
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
def render_list_frame_after_save
|
|
373
|
+
@ul_needed = true
|
|
374
|
+
render "inline_forms/create_list_frame", layout: associated_list_frame_layout
|
|
375
|
+
end
|
|
376
|
+
|
|
322
377
|
def associated_list_frame_layout
|
|
323
378
|
# Use full inline_forms chrome so the swapped frame is styled; Turbo extracts
|
|
324
379
|
# the matching <turbo-frame id="…"> from the response body.
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
|
2
2
|
module InlineFormsHelper
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
3
|
+
# Load active form elements (top-level *.rb only). Retired elements live under
|
|
4
|
+
# archived/form_elements/ — see archived/README.md.
|
|
6
5
|
INLINE_FORMS_PATH = File.dirname(__FILE__) + "/form_elements/"
|
|
7
6
|
Dir[INLINE_FORMS_PATH + "*.rb"].each do |form_element|
|
|
8
7
|
require form_element
|
|
@@ -54,12 +53,36 @@ module InlineFormsHelper
|
|
|
54
53
|
|
|
55
54
|
# Turbo Frames navigation for row toolbar, versions, and nested +new+ (Step 3).
|
|
56
55
|
# +update_span+ must match the target +<turbo-frame id="…">+.
|
|
57
|
-
|
|
56
|
+
#
|
|
57
|
+
# When +turbo_stream: true+ (e.g. restore from inside +*_versions+ frame), the client
|
|
58
|
+
# requests +text/vnd.turbo-stream.html+ so Turbo does not expect a single matching
|
|
59
|
+
# frame in the response — POSTs from nested +…_versions+ frames otherwise send
|
|
60
|
+
# +Turbo-Frame: …_versions+ while the server returns the row frame (+Content missing+).
|
|
61
|
+
def inline_forms_turbo_link_data(update_span, method: :get, turbo_stream: false)
|
|
58
62
|
data = { turbo: true, turbo_frame: update_span }
|
|
59
63
|
data[:turbo_method] = method.to_s.downcase unless method == :get
|
|
64
|
+
data[:turbo_stream] = true if turbo_stream
|
|
60
65
|
{ data: data }
|
|
61
66
|
end
|
|
62
67
|
|
|
68
|
+
# +<turbo-frame>+ id for a list row's open/close/revert target.
|
|
69
|
+
# Top-level models: +apartment_5+. Nested +not_accessible_through_html?+ children
|
|
70
|
+
# (e.g. Photo under Apartment): +apartment_5_photo_2+ — must match +_list.html.erb+.
|
|
71
|
+
def inline_forms_row_turbo_frame_id(object)
|
|
72
|
+
frame_id = "#{object.class.name.underscore}_#{object.id}"
|
|
73
|
+
return frame_id unless object.class.respond_to?(:not_accessible_through_html?) &&
|
|
74
|
+
object.class.not_accessible_through_html?
|
|
75
|
+
|
|
76
|
+
belongs_to = object.class.reflect_on_all_associations(:belongs_to)
|
|
77
|
+
.find { |assoc| !assoc.polymorphic? }
|
|
78
|
+
return frame_id unless belongs_to
|
|
79
|
+
|
|
80
|
+
parent = object.public_send(belongs_to.name)
|
|
81
|
+
return frame_id unless parent
|
|
82
|
+
|
|
83
|
+
"#{parent.class.name.underscore}_#{parent.id}_#{object.class.name.underscore}_#{object.id}"
|
|
84
|
+
end
|
|
85
|
+
|
|
63
86
|
private
|
|
64
87
|
|
|
65
88
|
def validation_hints_as_list_for(object, attribute)
|
|
@@ -74,12 +97,8 @@ module InlineFormsHelper
|
|
|
74
97
|
close: true
|
|
75
98
|
)
|
|
76
99
|
opts = { class: html_class, title: t("inline_forms.view.close") }
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
link_to "<i class='fi-x'></i>".html_safe, path, opts
|
|
80
|
-
else
|
|
81
|
-
link_to "<i class='fi-x'></i>".html_safe, path, opts.merge(remote: true)
|
|
82
|
-
end
|
|
100
|
+
opts[:data] = { turbo: true, turbo_frame: "_self" }
|
|
101
|
+
link_to "<i class='fi-x'></i>".html_safe, path, opts
|
|
83
102
|
end
|
|
84
103
|
|
|
85
104
|
# delete link. Mind the difference between delete and destroy.
|
|
@@ -89,12 +108,12 @@ module InlineFormsHelper
|
|
|
89
108
|
if object.deleted? && (cancan_disabled? || (can? :soft_restore, object))
|
|
90
109
|
path = send("soft_restore_#{object.class.to_s.underscore}_path", object, update: update_span)
|
|
91
110
|
opts = { title: t("inline_forms.view.undelete") }
|
|
92
|
-
opts.merge!(
|
|
111
|
+
opts.merge!(inline_forms_turbo_link_data(update_span, method: :post))
|
|
93
112
|
soft = link_to "<i class='fi-refresh'></i>".html_safe, path, opts
|
|
94
113
|
elsif !object.deleted? && (cancan_disabled? || (can? :soft_delete, object))
|
|
95
114
|
path = send("soft_delete_#{object.class.to_s.underscore}_path", object, update: update_span)
|
|
96
115
|
opts = { title: t("inline_forms.view.trash") }
|
|
97
|
-
opts.merge!(
|
|
116
|
+
opts.merge!(inline_forms_turbo_link_data(update_span, method: :post))
|
|
98
117
|
soft = link_to "<i class='fi-trash'></i>".html_safe, path, opts
|
|
99
118
|
end
|
|
100
119
|
end
|
|
@@ -107,7 +126,7 @@ module InlineFormsHelper
|
|
|
107
126
|
if cancan_disabled? || (can? :destroy, object)
|
|
108
127
|
path = polymorphic_path(object, update: update_span)
|
|
109
128
|
opts = { title: t("inline_forms.view.trash") }
|
|
110
|
-
opts.merge!(
|
|
129
|
+
opts.merge!(inline_forms_turbo_link_data(update_span, method: :delete))
|
|
111
130
|
hard = link_to " <font color='FF0000'><i class='fi-x'></i></font>".html_safe, path, opts
|
|
112
131
|
end
|
|
113
132
|
hard.html_safe
|
|
@@ -115,13 +134,8 @@ module InlineFormsHelper
|
|
|
115
134
|
|
|
116
135
|
# new link
|
|
117
136
|
#
|
|
118
|
-
# +turbo_row:+
|
|
119
|
-
#
|
|
120
|
-
# passes no +parent_class+; for that case we fall back to UJS (+remote: true+) so
|
|
121
|
-
# +new.js.erb+ / +list.js.erb+ swap +#apartments_list+ contents instead of trying
|
|
122
|
-
# to navigate a Turbo frame the page does not have. Without this the Turbo data
|
|
123
|
-
# attributes either logged "Content missing" on cancel/create or fell back to a
|
|
124
|
-
# full-page navigation that broke the inline-edit experience (7.5.1 regression).
|
|
137
|
+
# +turbo_row:+ kept for API compatibility; navigation always targets +update_span+
|
|
138
|
+
# as a +<turbo-frame>+ (no jquery-ujs).
|
|
125
139
|
def link_to_new_record(model, path_to_new, update_span, parent_class = nil, parent_id = nil, html_class = "button new_button", turbo_row: true)
|
|
126
140
|
path = send(
|
|
127
141
|
path_to_new,
|
|
@@ -133,7 +147,7 @@ module InlineFormsHelper
|
|
|
133
147
|
class: html_class,
|
|
134
148
|
title: t("inline_forms.view.add_new", model: model.model_name.human)
|
|
135
149
|
}
|
|
136
|
-
opts.merge!(
|
|
150
|
+
opts.merge!(inline_forms_turbo_link_data(update_span))
|
|
137
151
|
out = link_to "<i class='fi-plus'></i>".html_safe, path, opts
|
|
138
152
|
if cancan_enabled?
|
|
139
153
|
if can? :create, model
|
|
@@ -154,7 +168,7 @@ module InlineFormsHelper
|
|
|
154
168
|
if defined?(PaperTrail) && object.respond_to?(:versions)
|
|
155
169
|
path = send(path_to_versions_list, object, update: update_span)
|
|
156
170
|
opts = { class: html_class, title: t("inline_forms.view.list_versions") }
|
|
157
|
-
opts.merge!(
|
|
171
|
+
opts.merge!(inline_forms_turbo_link_data(update_span))
|
|
158
172
|
raw link_to("<i class='fi-list'></i>".html_safe, path, opts)
|
|
159
173
|
end
|
|
160
174
|
end
|
|
@@ -169,7 +183,7 @@ module InlineFormsHelper
|
|
|
169
183
|
close: true
|
|
170
184
|
)
|
|
171
185
|
opts = { class: html_class, title: t("inline_forms.view.close_versions_list") }
|
|
172
|
-
opts.merge!(
|
|
186
|
+
opts.merge!(inline_forms_turbo_link_data(update_span))
|
|
173
187
|
link_to "<i class='fi-x'></i>".html_safe, path, opts
|
|
174
188
|
end
|
|
175
189
|
|
|
@@ -198,11 +212,10 @@ module InlineFormsHelper
|
|
|
198
212
|
)
|
|
199
213
|
opts = { class: "inline_forms-field-cancel" }
|
|
200
214
|
if turbo_frame
|
|
201
|
-
# Inside a <turbo-frame>: plain GET link; no data-method (
|
|
215
|
+
# Inside a <turbo-frame>: plain GET link; no data-method (legacy ujs fought Turbo).
|
|
202
216
|
opts[:data] = { turbo: true, turbo_frame: "_self" }
|
|
203
217
|
else
|
|
204
|
-
opts[:
|
|
205
|
-
opts[:method] = :get
|
|
218
|
+
opts[:data] = { turbo: true, turbo_frame: update_span }
|
|
206
219
|
end
|
|
207
220
|
link_to path, opts do
|
|
208
221
|
tag.input(
|
|
@@ -218,7 +231,8 @@ module InlineFormsHelper
|
|
|
218
231
|
# link_to_inline_edit
|
|
219
232
|
#
|
|
220
233
|
# Pass +from_callee:+ +__callee__+ from the enclosing +*_show+ method so the edit route receives the correct form element name.
|
|
221
|
-
# When +turbo_frame:+ is true the link
|
|
234
|
+
# When +turbo_frame:+ is true the link targets +_self+; otherwise it targets the
|
|
235
|
+
# field frame id (+css_class_id+) so edit works without a surrounding +_show+ wrap.
|
|
222
236
|
def link_to_inline_edit(object, attribute, attribute_value='', from_callee:, turbo_frame: false)
|
|
223
237
|
form_element = InlineForms.form_element_string_from_callee(from_callee)
|
|
224
238
|
attribute_value = attribute_value.to_s
|
|
@@ -231,7 +245,7 @@ module InlineFormsHelper
|
|
|
231
245
|
link_opts = if use_turbo_frame
|
|
232
246
|
{ data: { turbo: true, turbo_frame: "_self" } }
|
|
233
247
|
else
|
|
234
|
-
{
|
|
248
|
+
{ data: { turbo: true, turbo_frame: css_class_id } }
|
|
235
249
|
end
|
|
236
250
|
link_to value,
|
|
237
251
|
edit_polymorphic_path(
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
<%
|
|
2
|
-
<%
|
|
3
|
-
<%
|
|
1
|
+
<% update_span = local_assigns[:update_span] || @update_span -%>
|
|
2
|
+
<% object = local_assigns[:object] || @object -%>
|
|
3
|
+
<% inline_forms_turbo_row = local_assigns.fetch(:inline_forms_turbo_row, @inline_forms_turbo_row) -%>
|
|
4
|
+
<% presentation_link_opts = { data: { turbo: true, turbo_frame: update_span } } %>
|
|
5
|
+
<% if cancan_disabled? || ( can? :soft_delete, object ) %>
|
|
4
6
|
<div class="small-1 column">
|
|
5
|
-
<%= link_to_soft_delete(
|
|
6
|
-
<%= link_to_destroy(
|
|
7
|
+
<%= link_to_soft_delete(object, update_span, turbo_row: inline_forms_turbo_row) -%>
|
|
8
|
+
<%= link_to_destroy(object, update_span, turbo_row: inline_forms_turbo_row) -%>
|
|
7
9
|
</div>
|
|
8
10
|
<div class="small-11 column">
|
|
9
|
-
<%= link_to h(
|
|
11
|
+
<%= link_to h(object._presentation), polymorphic_path(object, :update => update_span), presentation_link_opts -%>
|
|
10
12
|
</div>
|
|
11
13
|
<% else %>
|
|
12
14
|
<div class="small-12 column">
|
|
13
|
-
<%= link_to h(
|
|
15
|
+
<%= link_to h(object._presentation), polymorphic_path(object, :update => update_span), presentation_link_opts -%>
|
|
14
16
|
</div>
|
|
15
17
|
<% end %>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<% @BUTTONS_UNDER = [ "text_area", "
|
|
1
|
+
<% @BUTTONS_UNDER = [ "text_area", "rich_text" ] %>
|
|
2
2
|
<% edit_form_opts = { method: :put, multipart: true, class: "edit_form", abide: true } %>
|
|
3
3
|
<% edit_form_opts[:remote] = true unless @turbo_frame %>
|
|
4
4
|
<%= form_tag polymorphic_path(@object,
|