inline_forms 7.2.11 → 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 +286 -0
- data/README.rdoc +14 -2
- data/app/assets/javascripts/inline_forms/inline_forms.js +26 -10
- data/app/assets/stylesheets/inline_forms/inline_forms.scss +33 -16
- data/app/controllers/concerns/versions_concern.rb +2 -3
- data/app/controllers/inline_forms_application_controller.rb +5 -1
- data/app/controllers/inline_forms_controller.rb +185 -34
- data/app/helpers/form_elements/ckeditor.rb +4 -30
- data/app/helpers/form_elements/plain_text.rb +23 -0
- data/app/helpers/form_elements/plain_text_area.rb +7 -3
- data/app/helpers/form_elements/text_area.rb +4 -44
- data/app/helpers/form_elements/text_area_without_ckeditor.rb +5 -4
- data/app/helpers/form_elements/text_field.rb +2 -2
- data/app/helpers/inline_forms_helper.rb +144 -74
- data/app/views/devise/sessions/_form.html.erb +4 -1
- data/app/views/inline_forms/_close.html.erb +9 -5
- data/app/views/inline_forms/_edit.html.erb +8 -41
- data/app/views/inline_forms/_list.html.erb +53 -55
- data/app/views/inline_forms/_new.html.erb +22 -12
- data/app/views/inline_forms/_show.html.erb +13 -37
- data/app/views/inline_forms/_versions.html.erb +5 -4
- data/app/views/inline_forms/_versions_list.html.erb +8 -12
- data/app/views/inline_forms/create_list_frame.html.erb +3 -0
- data/app/views/inline_forms/field_edit.html.erb +3 -0
- data/app/views/inline_forms/field_show.html.erb +3 -0
- data/app/views/inline_forms/new_record.html.erb +3 -0
- data/app/views/inline_forms/row_close.html.erb +13 -0
- data/app/views/inline_forms/row_destroyed.html.erb +9 -0
- data/app/views/inline_forms/row_show.html.erb +3 -0
- data/app/views/inline_forms/versions_list_panel.html.erb +3 -0
- data/app/views/inline_forms/versions_panel.html.erb +6 -0
- data/app/views/layouts/application.html.erb +2 -5
- data/app/views/layouts/inline_forms.html.erb +12 -6
- 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 +22 -1
- data/bin/inline_forms_installer_core.rb +108 -8
- data/docs/ujs-to-turbo.md +192 -0
- data/lib/generators/USAGE +2 -2
- data/lib/generators/assets/stylesheets/inline_forms.scss +33 -16
- data/lib/inline_forms/archived_form_elements.rb +70 -0
- data/lib/inline_forms/version.rb +1 -1
- data/lib/inline_forms.rb +60 -2
- data/lib/installer_templates/example_app_tests/test/integration/example_app_apartment_field_turbo_test.rb +73 -0
- data/lib/installer_templates/example_app_tests/test/integration/example_app_apartment_name_list_test.rb +73 -0
- 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 +227 -15
- data/lib/installer_templates/example_app_tests/test/integration/example_app_apartment_row_turbo_test.rb +103 -0
- data/lib/installer_templates/example_app_tests/test/integration/example_app_apartment_top_level_new_test.rb +70 -0
- 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 +120 -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/lib/installer_templates/example_app_tests/test/models/example_app_plain_text_rich_text_edge_cases_test.rb +46 -0
- data/lib/installer_templates/example_app_views/apartments/name_list.html.erb +26 -0
- data/lib/installer_templates/example_app_views/inline_forms/_header.html.erb +45 -0
- data/test/archived_form_elements_test.rb +41 -0
- data/test/form_element_from_callee_test.rb +2 -2
- data/test/inline_forms_generator_test.rb +10 -0
- data/test/plain_text_configuration_test.rb +90 -0
- metadata +45 -24
- 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/edit.js.erb +0 -1
- 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_element.js.erb +0 -1
- data/app/views/inline_forms/show_undo.js.erb +0 -1
- data/app/views/inline_forms/update.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/lib/generators/assets/javascripts/ckeditor/config.js +0 -72
- /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
data/bin/inline_forms
CHANGED
|
@@ -110,7 +110,28 @@ module InlineForms
|
|
|
110
110
|
|
|
111
111
|
app_template_file = File.join(File.dirname(__FILE__), 'inline_forms_app_template.rb')
|
|
112
112
|
|
|
113
|
-
|
|
113
|
+
# Prefer a Rails 7.0.x generator when one is installed locally: the
|
|
114
|
+
# generated `Gemfile`/`config/application.rb` pin to `rails ~> 7.0.0`,
|
|
115
|
+
# so running `rails new` from a newer system Rails (e.g. 8.0.x) emits
|
|
116
|
+
# 7.1+/8.0-only configuration (`load_defaults 8.0`,
|
|
117
|
+
# `config.autoload_lib(...)`) that aborts on the next `bundle exec`.
|
|
118
|
+
# The installer_core also patches `config/application.rb` defensively;
|
|
119
|
+
# the explicit version selector is the cleaner first line of defense.
|
|
120
|
+
require 'rubygems'
|
|
121
|
+
compatible_rails =
|
|
122
|
+
begin
|
|
123
|
+
Gem::Specification
|
|
124
|
+
.find_all_by_name("rails")
|
|
125
|
+
.map(&:version)
|
|
126
|
+
.select { |v| v >= Gem::Version.new("7.0") && v < Gem::Version.new("7.1") }
|
|
127
|
+
.max
|
|
128
|
+
rescue StandardError
|
|
129
|
+
nil
|
|
130
|
+
end
|
|
131
|
+
rails_invocation = compatible_rails ? "rails _#{compatible_rails}_" : "rails"
|
|
132
|
+
say "Generating app with: #{rails_invocation} new ...", :green
|
|
133
|
+
|
|
134
|
+
if ! run("#{rails_invocation} new #{app_name} -m #{app_template_file} --skip-bundle --skip-bootsnap --javascript=importmap")
|
|
114
135
|
say "Rails could not create the app '#{app_name}', maybe because it is a reserved word...", :red # TODO ROYTJE MAKE ERROR MESSAGE MORE RELEVANT # Rails could not create the app 'MyApp', maybe because it is a reserved word..
|
|
115
136
|
exit 1
|
|
116
137
|
end
|
|
@@ -5,12 +5,33 @@ GENERATOR_PATH = File.dirname(File.expand_path(__FILE__)) + '/../'
|
|
|
5
5
|
remove_file 'Gemfile' if File.exist?('Gemfile')
|
|
6
6
|
create_file 'Gemfile', "# created by inline_forms #{ENV['inline_forms_version']} on #{Date.today}\n"
|
|
7
7
|
|
|
8
|
+
# `rails new` is invoked with whatever the system `rails` binary points at
|
|
9
|
+
# (often Rails 8.x once it lands in the global gemset), so the generated
|
|
10
|
+
# `config/application.rb` may carry Rails 7.1+/8.0 idioms (`load_defaults
|
|
11
|
+
# 8.0`, `config.autoload_lib(...)`). The Gemfile we write below pins
|
|
12
|
+
# `rails ~> 7.0.0`, so Rails 7.0 must be able to interpret application.rb;
|
|
13
|
+
# otherwise the first `bundle exec rails …` aborts with `Unknown version
|
|
14
|
+
# "8.0"` or `NoMethodError: undefined method 'autoload_lib'`.
|
|
15
|
+
if File.exist?('config/application.rb')
|
|
16
|
+
gsub_file 'config/application.rb',
|
|
17
|
+
/config\.load_defaults\s+\d+\.\d+/,
|
|
18
|
+
'config.load_defaults 7.0'
|
|
19
|
+
# Strip Rails 7.1+ `config.autoload_lib(ignore: ...)` (and any surrounding
|
|
20
|
+
# explanatory comment block). Not supported on Rails 7.0.
|
|
21
|
+
gsub_file 'config/application.rb',
|
|
22
|
+
/^\s*#[^\n]*\n(\s*#[^\n]*\n)*\s*config\.autoload_lib\([^)]*\)\s*\n/,
|
|
23
|
+
""
|
|
24
|
+
gsub_file 'config/application.rb',
|
|
25
|
+
/^\s*config\.autoload_lib\([^)]*\)\s*\n/,
|
|
26
|
+
""
|
|
27
|
+
end
|
|
28
|
+
|
|
8
29
|
add_source 'https://rubygems.org'
|
|
9
30
|
|
|
10
31
|
gem 'cancancan'
|
|
11
32
|
gem 'carrierwave', '~> 3.1'
|
|
12
|
-
gem 'devise
|
|
13
|
-
gem 'devise'
|
|
33
|
+
gem 'devise', '~> 5.0'
|
|
34
|
+
gem 'devise-i18n', '~> 1.16'
|
|
14
35
|
gem 'autoprefixer-rails'
|
|
15
36
|
# foundation-rails 6.7+ uses Dart Sass (`sass:math`); sass-rails/sassc removed.
|
|
16
37
|
# Visually tuned against foundation-rails ~> 6.6.2; current pin ~> 6.9 (6.9.0.x).
|
|
@@ -36,7 +57,6 @@ gem 'rails-i18n', '~> 7.0'
|
|
|
36
57
|
gem 'rails-jquery-autocomplete'
|
|
37
58
|
gem 'rails', '~> 7.0.0'
|
|
38
59
|
gem 'rake'
|
|
39
|
-
gem 'remotipart', '~> 1.0'
|
|
40
60
|
gem 'rvm'
|
|
41
61
|
gem 'dartsass-rails'
|
|
42
62
|
# Rails 7 no longer adds sprockets-rails to the default Gemfile; declare it
|
|
@@ -45,10 +65,9 @@ gem 'dartsass-rails'
|
|
|
45
65
|
gem 'sprockets-rails'
|
|
46
66
|
# Rails 7 default JavaScript tooling: importmap-rails replaces Webpacker.
|
|
47
67
|
gem 'importmap-rails'
|
|
48
|
-
# Hotwire/Turbo. Loaded
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
# format so future controllers can opt in to Turbo Stream responses.
|
|
68
|
+
# Hotwire/Turbo. Loaded from layouts as `<script type="module">`; inline flows
|
|
69
|
+
# use `<turbo-frame>` + HTML responses (see docs/ujs-to-turbo.md). Registers the
|
|
70
|
+
# `turbo_stream` MIME type for optional stream responses.
|
|
52
71
|
gem 'turbo-rails'
|
|
53
72
|
gem 'tabs_on_rails', :git => 'https://github.com/acesuares/tabs_on_rails.git', :branch => 'update_remote_before_action'
|
|
54
73
|
gem 'unicorn'
|
|
@@ -443,7 +462,7 @@ sleep 1 # unique migration timestamps per generator
|
|
|
443
462
|
generate "inline_forms", "InlineFormsKey name:string inline_forms_translations:has_many inline_forms_translations:associated _enabled:yes _presentation:\#{name}"
|
|
444
463
|
sleep 1
|
|
445
464
|
generate "inline_forms", "InlineFormsTranslation inline_forms_key:belongs_to inline_forms_locale:dropdown value:text interpolations:text is_proc:boolean _presentation:\#{value}"
|
|
446
|
-
#
|
|
465
|
+
# Plain long text uses :plain_text; ActionText-backed fields use :rich_text.
|
|
447
466
|
sleep 1 # to get unique migration number
|
|
448
467
|
create_file "db/migrate/" +
|
|
449
468
|
Time.now.utc.strftime("%Y%m%d%H%M%S") +
|
|
@@ -661,6 +680,73 @@ if ENV['install_example'] == 'true'
|
|
|
661
680
|
run 'bundle exec rails generate uploader Image'
|
|
662
681
|
run 'bundle exec rails g inline_forms Apartment name:string title:string description:rich_text photos:has_many photos:associated _enabled:yes _presentation:\'#{name}\''
|
|
663
682
|
|
|
683
|
+
say "- Apartment name is required..."
|
|
684
|
+
inject_into_file "app/models/apartment.rb",
|
|
685
|
+
"\n validates :name, presence: true\n",
|
|
686
|
+
after: " has_paper_trail\n"
|
|
687
|
+
|
|
688
|
+
# CarrierWave + PaperTrail history.
|
|
689
|
+
# PaperTrail snapshots the column scalar (the stored filename) on update,
|
|
690
|
+
# but CarrierWave's default `remove_previously_stored_files_after_update`
|
|
691
|
+
# deletes the old file on disk and re-uses the same filename, so a
|
|
692
|
+
# PaperTrail revert restores a filename whose bytes are gone.
|
|
693
|
+
# We keep every uploaded file on disk and namespace filenames with a
|
|
694
|
+
# per-upload token so successive uploads do not collide. See
|
|
695
|
+
# https://stackoverflow.com/questions/9423279/papertrail-and-carrierwave
|
|
696
|
+
# (Answers 2, 4 and 5).
|
|
697
|
+
say "- Configuring CarrierWave to keep previously stored files (PaperTrail history)..."
|
|
698
|
+
create_file "config/initializers/carrierwave.rb", <<-CWINIT.strip_heredoc
|
|
699
|
+
# Keep previously stored files on disk so PaperTrail-driven restore
|
|
700
|
+
# actually returns the previous image bytes. See
|
|
701
|
+
# https://stackoverflow.com/questions/9423279/papertrail-and-carrierwave
|
|
702
|
+
# The per-uploader overrides in app/uploaders/image_uploader.rb
|
|
703
|
+
# complement this by giving every upload a unique on-disk filename
|
|
704
|
+
# and by no-op'ing `remove!` so destroyed records keep their files.
|
|
705
|
+
CarrierWave.configure do |config|
|
|
706
|
+
config.remove_previously_stored_files_after_update = false
|
|
707
|
+
end
|
|
708
|
+
CWINIT
|
|
709
|
+
|
|
710
|
+
inject_into_file "app/uploaders/image_uploader.rb",
|
|
711
|
+
after: "class ImageUploader < CarrierWave::Uploader::Base\n" do
|
|
712
|
+
<<-RUBY.strip_heredoc.gsub(/^/, " ")
|
|
713
|
+
# PaperTrail history support. CarrierWave's default behaviour wipes the
|
|
714
|
+
# previous file on update and reuses the same filename; PaperTrail only
|
|
715
|
+
# stores the column scalar, so a plain `version.reify; save!` restores a
|
|
716
|
+
# filename whose bytes are gone. The knobs below preserve every byte:
|
|
717
|
+
#
|
|
718
|
+
# * `remove_previously_stored_files_after_update = false` is set
|
|
719
|
+
# globally in config/initializers/carrierwave.rb (covers
|
|
720
|
+
# `multi_image_field` uploaders too).
|
|
721
|
+
# * `remove!` is a no-op so hard-destroyed records keep their files
|
|
722
|
+
# and revert-after-destroy still finds the bytes on disk.
|
|
723
|
+
# * `filename` is prefixed with a per-upload UUID so successive
|
|
724
|
+
# uploads never collide on disk.
|
|
725
|
+
#
|
|
726
|
+
# Trade-off: files accumulate on disk; sweeping is out of scope.
|
|
727
|
+
# Source: https://stackoverflow.com/questions/9423279/papertrail-and-carrierwave
|
|
728
|
+
def remove!
|
|
729
|
+
# no-op: keep the file so PaperTrail revert can restore it.
|
|
730
|
+
end
|
|
731
|
+
|
|
732
|
+
def filename
|
|
733
|
+
# CarrierWave 3.x calls `filename` again after storing to record the
|
|
734
|
+
# persisted name; at that point `original_filename` may be nil and we
|
|
735
|
+
# must still return the memoized name (see
|
|
736
|
+
# https://github.com/carrierwaveuploader/carrierwave/issues/2708).
|
|
737
|
+
@name ||= "\#{secure_token}-\#{original_filename}" if original_filename
|
|
738
|
+
@name
|
|
739
|
+
end
|
|
740
|
+
|
|
741
|
+
private
|
|
742
|
+
|
|
743
|
+
def secure_token
|
|
744
|
+
var = :"@\#{mounted_as}_secure_token"
|
|
745
|
+
model.instance_variable_get(var) || model.instance_variable_set(var, SecureRandom.uuid)
|
|
746
|
+
end
|
|
747
|
+
RUBY
|
|
748
|
+
end
|
|
749
|
+
|
|
664
750
|
say "- Lower Photo.per_page so the seeded gallery paginates..."
|
|
665
751
|
# The model template (lib/generators/templates/model.erb) emits
|
|
666
752
|
# attr_reader :per_page
|
|
@@ -756,6 +842,19 @@ if ENV['install_example'] == 'true'
|
|
|
756
842
|
|
|
757
843
|
remove_file 'public/index.html'
|
|
758
844
|
|
|
845
|
+
say "- Apartment name list demo (field-level inline edit without _show)..."
|
|
846
|
+
inject_into_file "app/controllers/apartments_controller.rb",
|
|
847
|
+
"\n skip_load_and_authorize_resource only: :name_list\n\n def name_list\n authorize! :read, Apartment\n @apartments = Apartment.accessible_by(current_ability).order(:id).limit(10)\n end\n",
|
|
848
|
+
after: "set_tab :apartment\n"
|
|
849
|
+
|
|
850
|
+
example_views_root = File.join(GENERATOR_PATH, "lib/installer_templates/example_app_views")
|
|
851
|
+
Dir.glob(File.join(example_views_root, "**", "*")).sort.each do |abs|
|
|
852
|
+
next unless File.file?(abs)
|
|
853
|
+
rel = abs.delete_prefix(example_views_root + File::SEPARATOR).tr("\\", "/")
|
|
854
|
+
create_file File.join("app/views", rel), File.read(abs)
|
|
855
|
+
end
|
|
856
|
+
|
|
857
|
+
route 'get "apartments/name_list", to: "apartments#name_list", as: :apartment_name_list'
|
|
759
858
|
route "root :to => 'apartments#index'"
|
|
760
859
|
|
|
761
860
|
say "- Adding example app regression tests (bundle exec rails test)..."
|
|
@@ -768,6 +867,7 @@ if ENV['install_example'] == 'true'
|
|
|
768
867
|
say "\nDone! Example app (Photo + Apartment) is ready.", :yellow
|
|
769
868
|
say " bundle exec rails test # example regression tests", :yellow
|
|
770
869
|
say " bundle exec rails s # then http://localhost:3000/apartments", :yellow
|
|
870
|
+
say " More menu → Apartment names (first 10) # /apartments/name_list", :yellow
|
|
771
871
|
say " Log in: #{ENV["email"]} / #{ENV["password"]}", :yellow
|
|
772
872
|
end
|
|
773
873
|
# done!
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# UJS → Turbo migration checklist
|
|
2
|
+
|
|
3
|
+
Track progress toward full Turbo integration and removal of jQuery UJS from inline_forms generated apps.
|
|
4
|
+
|
|
5
|
+
**Current gem version:** see `lib/inline_forms/version.rb` (**Step 5** — Turbo Drive on, jquery-ujs / remotipart removed in **7.8.0**)
|
|
6
|
+
|
|
7
|
+
**Architecture today:** inline interactions use **`<turbo-frame>`** + **`format.html`** (and optional **`format.turbo_stream`**). Turbo loads as an ES module from the layouts; **Turbo Drive** uses the library default (**enabled**). No `*.js.erb` in active engine views; no `jquery_ujs` or `jquery.remotipart` in the Sprockets bundle.
|
|
8
|
+
|
|
9
|
+
**Target end state:** Stock flows use Turbo Frames + HTML; optional `turbo_stream` where it simplifies a response. jQuery UJS and `*.js.erb` are gone from the engine.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Step 1 — Turbo wired (DONE)
|
|
14
|
+
|
|
15
|
+
- [x] `gem 'turbo-rails'` in installer Gemfile (`bin/inline_forms_installer_core.rb`)
|
|
16
|
+
- [x] Turbo loaded as `<script type="module">` in `layouts/inline_forms.html.erb` and `layouts/application.html.erb`
|
|
17
|
+
- [x] `Turbo.session.drive` uses the **default (enabled)** — **7.8.0** (was disabled while UJS coexisted)
|
|
18
|
+
- [x] Turbo **not** in Sprockets bundle (`app/assets/javascripts/inline_forms/inline_forms.js`) — ESM parse-error lesson from 7.1.1
|
|
19
|
+
- [x] Smoke test: `lib/installer_templates/example_app_tests/test/integration/example_app_turbo_layout_test.rb`
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Step 2 — Nested list + pagination as Turbo Frame (DONE)
|
|
24
|
+
|
|
25
|
+
- [x] `_list.html.erb`: nested has_many container is `<turbo-frame id="…_list">` when `parent_class` present
|
|
26
|
+
- [x] Nested pagination: no `:remote => true`; `update=` param matches frame id (`…_list` suffix)
|
|
27
|
+
- [x] `InlineFormsController#index`: HTML for nested frame requests; `turbo_rails/frame` vs `inline_forms` layout negotiation
|
|
28
|
+
- [x] **Nested rows (7.4.2):** per-row `<turbo-frame>` + Turbo presentation links; **`row_html_turbo_allowed?`** enables **`format.html`** row open/close for **`not_accessible_through_html?`** models when **`params[:update]`** is a nested associated row id (`apartment_<aid>_photo_<pid>`). Removed row-level **`data-turbo="false"`** (field cancel + pagination use Turbo inside nested frames).
|
|
29
|
+
- [x] Top-level rows must **not** carry `data-turbo="false"` (would poison inner frames — 7.2.3)
|
|
30
|
+
- [x] Smoke test: `example_app_apartment_photos_pagination_test.rb`
|
|
31
|
+
- [x] Example seed data (Konferensha + photos) for pagination assertions
|
|
32
|
+
|
|
33
|
+
**Explicitly deferred in this step:** top-level index lists (`/apartments`) stay full-page + UJS row open.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Step 3 — Per-row / per-field inline-edit lifecycle
|
|
38
|
+
|
|
39
|
+
Convert the **`show → edit → update → show_element → close`** cycle without UJS.
|
|
40
|
+
|
|
41
|
+
### DOM contract (unchanged)
|
|
42
|
+
|
|
43
|
+
- Every editable region needs a stable id: `{model}_{id}_{attribute}` (e.g. `apartment_5_name`)
|
|
44
|
+
- `params[:update]` must match that id (set by `link_to_inline_edit`, `_edit.html.erb`, etc.)
|
|
45
|
+
|
|
46
|
+
### Row-level (stock list → full `_show` panel)
|
|
47
|
+
|
|
48
|
+
- [x] Wrap each top-level list row in `<turbo-frame id="apartment_<id>">` (`_list.html.erb` when `parent_class` is nil)
|
|
49
|
+
- [x] Row title link: GET `show` → HTML `row_show` / `_show` inside frame (no `:remote`; `data-turbo` + `data-turbo-frame`)
|
|
50
|
+
- [x] `InlineFormsController#show` (full record, no `params[:attribute]`): `format.html` → `row_show` / `row_close` + `turbo_rails/frame` when `turbo_frame_request?`, else full `inline_forms` layout
|
|
51
|
+
- [x] `close_link` and `_close` presentation link: Turbo when `@inline_forms_turbo_row` (row HTML path)
|
|
52
|
+
- [x] `soft_delete`, `soft_restore`, `destroy`, `revert`: `format.html` → `row_close` / `row_destroyed` (+ Turbo toolbar links)
|
|
53
|
+
- [x] Remove `edit.js.erb`, `update.js.erb`, `show_element.js.erb` (field lifecycle is Turbo HTML only)
|
|
54
|
+
- [x] Remove `show.js.erb`, `close.js.erb`, `record_destroyed.js.erb`, `show_undo.js.erb` (7.7.0; tree migrated)
|
|
55
|
+
- [x] Remove `:remote => true` from nested `_list` / `_close` / toolbar where migrated (row toolbar, versions, nested `+` use Turbo; top-level `new` was Step 4)
|
|
56
|
+
- [x] Remove `data-turbo="false"` from nested rows once nested inline-edit is Turbo-native (7.4.2)
|
|
57
|
+
|
|
58
|
+
### Nested associated lists (e.g. Apartment → Photo)
|
|
59
|
+
|
|
60
|
+
- [x] Each nested row is `<turbo-frame id="{parent}_{id}_{assoc}_{child_id}">` with Turbo presentation links (same contract as top-level).
|
|
61
|
+
- [x] **`row_html_turbo_allowed?`:** `format.html` row open/close for **`not_accessible_through_html?`** models when **`params[:update]`** matches a nested associated row id (≥4 underscore segments, trailing numeric id).
|
|
62
|
+
- [x] Scalar field edit/cancel inside nested **`_show`** uses existing **`format.html`** field templates (no **`UnknownFormat`** for Photo).
|
|
63
|
+
|
|
64
|
+
### Field-level (`link_to_inline_edit` / `*_show` helpers)
|
|
65
|
+
|
|
66
|
+
- [x] **Stock `_show` scalar fields**: wrapped in `<turbo-frame id="{model}_{id}_{attribute}">`; `@inline_forms_turbo_field = true` so `link_to_inline_edit` omits `:remote => true`
|
|
67
|
+
- [x] **`link_to_inline_edit`**: uses Turbo when `@inline_forms_turbo_field` or explicit `turbo_frame: true`
|
|
68
|
+
- [x] **`InlineFormsController#edit`, `#update`, `#show`** (single attribute): `format.html` + `field_edit` / `field_show` templates when `turbo_frame_request?`
|
|
69
|
+
- [x] **`_edit.html.erb`**: omits `:remote => true` when `@turbo_frame` (Turbo form submit inside frame)
|
|
70
|
+
- [x] Remove `edit.js.erb`, `update.js.erb`, `show_element.js.erb`
|
|
71
|
+
- [x] **`not_accessible_through_html?` models** (e.g. Photo): nested list row **`show` / `close`** use **`format.html`** when **`params[:update]`** is a nested row id (`row_html_turbo_allowed?`); field **`edit` / `update` / `show`** already always register **`format.html`**.
|
|
72
|
+
|
|
73
|
+
### Widget re-init after swap
|
|
74
|
+
|
|
75
|
+
- [x] ActionText/Trix: `turbo:frame-load` in `inline_forms.js` attaches Trix editors after frame replace
|
|
76
|
+
- [x] jQuery UI datepicker / timepicker: re-bound on `turbo:frame-load` (autocomplete widgets in field partials still use inline scripts until Step 5)
|
|
77
|
+
|
|
78
|
+
### Helpers (`app/helpers/inline_forms_helper.rb`)
|
|
79
|
+
|
|
80
|
+
- [x] `close_link`, `link_to_soft_delete`, `link_to_destroy`, `link_to_new_record`, `link_to_versions_list`, `close_versions_list_link`: Turbo frame attrs only (**7.8.0**; `turbo_row:` retained for API compat)
|
|
81
|
+
|
|
82
|
+
### Tests
|
|
83
|
+
|
|
84
|
+
- [x] Integration: stock row open/close on `/apartments` (Turbo frame + HTML `show` / `close`): `example_app_apartment_row_turbo_test.rb`
|
|
85
|
+
- [x] Integration: open apartment row → edit text field → save → cancel (field flow: `example_app_apartment_field_turbo_test.rb`)
|
|
86
|
+
- [x] Integration: nested Photo row open/close + name field cancel (`example_app_apartment_photos_pagination_test.rb`)
|
|
87
|
+
- [x] Integration: replace photo image (multipart) inside nested frame (`example_app_apartment_photos_pagination_test.rb`)
|
|
88
|
+
- [x] Integration: custom field-only page (`ApartmentsController#name_list`) — Turbo edit/update/cancel without full `_show`
|
|
89
|
+
- [x] Assert no `406 UnknownFormat` on Turbo field update (name list test)
|
|
90
|
+
- [x] Integration: row destroy + PaperTrail revert via Turbo (`example_app_apartment_row_turbo_test.rb`)
|
|
91
|
+
- [x] Integration: versions panel open/close via Turbo (`example_app_apartment_versions_turbo_test.rb`)
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Step 4 — Remaining UJS surfaces
|
|
96
|
+
|
|
97
|
+
### Lists and create flow
|
|
98
|
+
|
|
99
|
+
- [x] Top-level index: wrap in `<turbo-frame id="apartments_list">`; in-frame pagination (7.7.0)
|
|
100
|
+
- [x] `new` / `create`: frame refresh replacing list container (7.7.0)
|
|
101
|
+
- [x] Remove `new.js.erb`, `list.js.erb` (7.7.0)
|
|
102
|
+
- [x] `_new.html.erb`: Turbo path when `@turbo_frame` (no `:remote` on cancel)
|
|
103
|
+
|
|
104
|
+
### Tree
|
|
105
|
+
|
|
106
|
+
- [x] ~~`:tree` / `_tree.html.erb`~~ — **archived in 7.7.0** (`archived/form_elements/tree/`); needs host tree gem/APIs. Turbo-ready partial kept in archive.
|
|
107
|
+
|
|
108
|
+
### Versions panel
|
|
109
|
+
|
|
110
|
+
- [x] `VersionsConcern#list_versions`: HTML frame (`versions_panel` / `versions_list_panel`, `turbo_rails/frame` layout) — **7.7.3** drops `format.js`
|
|
111
|
+
- [x] Remove `versions.js.erb`, `versions_list.js.erb` (**7.7.3**)
|
|
112
|
+
- [x] `_versions_list.html.erb`: revert uses `inline_forms_turbo_link_data` (row frame), not `:remote => true`
|
|
113
|
+
|
|
114
|
+
### Geo / misc
|
|
115
|
+
|
|
116
|
+
- [x] ~~`geo_code_curacao`~~ — **archived in 7.6.0** (`archived/form_elements/geo_code_curacao/`). If restored, migrate `list_streets.js.erb` to frame or stream.
|
|
117
|
+
|
|
118
|
+
### Controller cleanup
|
|
119
|
+
|
|
120
|
+
- [x] Every action in `InlineFormsController` + `VersionsConcern` has a non-JS response path (**7.8.0** audit)
|
|
121
|
+
- [ ] Audit `respond_to` blocks: parallel `format.turbo_stream` where stream is cleaner than full frame (optional)
|
|
122
|
+
|
|
123
|
+
### Tests
|
|
124
|
+
|
|
125
|
+
- [x] Top-level list pagination in frame (`example_app_apartment_top_level_pagination_test.rb`)
|
|
126
|
+
- [x] Create apartment → list frame updates (`example_app_apartment_top_level_new_test.rb`)
|
|
127
|
+
- [x] Versions panel open/close + revert from list (`example_app_apartment_versions_turbo_test.rb`, **7.7.3**)
|
|
128
|
+
- [x] Assert zero `data-remote="true"` in rendered HTML for inline_forms flows (helpers + `_new` / `_close` no longer fall back to UJS — **7.8.0**)
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Step 5 — Enable Drive, remove UJS (DONE in **7.8.0**)
|
|
133
|
+
|
|
134
|
+
- [x] Remove `Turbo.session.drive = false` from both layouts (Drive default **on**)
|
|
135
|
+
- [x] Delete `//= require jquery_ujs` from `inline_forms.js`
|
|
136
|
+
- [x] Delete `//= require jquery.remotipart` from `inline_forms.js`
|
|
137
|
+
- [x] Delete all `app/views/inline_forms/*.js.erb` (completed by **7.7.3**)
|
|
138
|
+
- [x] Remove `format.js` branches from controllers (none remain on stock actions)
|
|
139
|
+
- [x] Update `example_app_turbo_layout_test.rb`: refute `Turbo.session.drive = false`
|
|
140
|
+
- [x] Full `bundle exec rails test` in `--example` app (before release)
|
|
141
|
+
|
|
142
|
+
### jQuery (optional follow-up — not required to drop UJS)
|
|
143
|
+
|
|
144
|
+
These can remain while UJS is gone; separate migration if desired:
|
|
145
|
+
|
|
146
|
+
- [ ] `jquery.ui.all` (datepicker)
|
|
147
|
+
- [ ] `jquery.timepicker.js`
|
|
148
|
+
- [ ] `autocomplete-rails`
|
|
149
|
+
- [ ] `foundation` jQuery plugin → consider Foundation JS without jQuery or Stimulus
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Reference — UJS inventory
|
|
154
|
+
|
|
155
|
+
### `*.js.erb` (all to delete by Step 5)
|
|
156
|
+
|
|
157
|
+
| File | Effect |
|
|
158
|
+
|------|--------|
|
|
159
|
+
| `show.js.erb` | Replace row with `_show` |
|
|
160
|
+
| `edit.js.erb` | Replace `#update_span` with `_edit` form |
|
|
161
|
+
| `update.js.erb` | Replace with `{form_element}_show` |
|
|
162
|
+
| `show_element.js.erb` | Single-field show after update |
|
|
163
|
+
| `new.js.erb` | Replace with `_new` form |
|
|
164
|
+
| `list.js.erb` | Replace list container |
|
|
165
|
+
| `close.js.erb` | Fade + `_close` partial |
|
|
166
|
+
| `record_destroyed.js.erb` | Fade out row |
|
|
167
|
+
| `show_undo.js.erb` | Undo link after destroy |
|
|
168
|
+
| ~~`versions.js.erb`~~ | Removed **7.7.3** — versions panel HTML frame |
|
|
169
|
+
| ~~`versions_list.js.erb`~~ | Removed **7.7.3** — versions list HTML frame |
|
|
170
|
+
| ~~`geo_code_curacao/list_streets.js.erb`~~ | Archived 7.6.0 — street autocomplete JSON |
|
|
171
|
+
|
|
172
|
+
### Controller actions still on `format.js`
|
|
173
|
+
|
|
174
|
+
None on `InlineFormsController` / `VersionsConcern` stock actions (**7.8.0**). Host app controllers may still use `format.js`.
|
|
175
|
+
|
|
176
|
+
### Key files
|
|
177
|
+
|
|
178
|
+
- `app/controllers/inline_forms_controller.rb`
|
|
179
|
+
- `app/controllers/concerns/versions_concern.rb`
|
|
180
|
+
- `app/views/inline_forms/_list.html.erb`, `_show.html.erb`, `_edit.html.erb`, `_new.html.erb`
|
|
181
|
+
- `app/helpers/inline_forms_helper.rb`
|
|
182
|
+
- `app/helpers/form_elements/*.rb` (`*_show` → `link_to_inline_edit`)
|
|
183
|
+
- `app/assets/javascripts/inline_forms/inline_forms.js`
|
|
184
|
+
- `app/views/layouts/inline_forms.html.erb`
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Custom field-only pages (helper bypass)
|
|
189
|
+
|
|
190
|
+
Stock `_show` / `_list` are not required for inline edit. Any page can call form-element helpers (e.g. `text_field_show(apartment, :name)`) inside a container with id `apartment_<id>_name`. Edit/update still hit `ApartmentsController#edit` / `#update` via polymorphic paths.
|
|
191
|
+
|
|
192
|
+
Example app **`--example` name list** (`GET /apartments/name_list`): custom page using the **same** turbo-field contract as stock `_show` (not a separate code path). Linked from the **More** menu; regression-tested after stock field Turbo lands.
|
data/lib/generators/USAGE
CHANGED
|
@@ -3,7 +3,7 @@ Description:
|
|
|
3
3
|
We will generate a model, a migration, a controller and a route. Please do check the migration and the model because they will likely need tweaking.
|
|
4
4
|
|
|
5
5
|
Example:
|
|
6
|
-
rails generate inline_forms Thing name:text_field description:
|
|
6
|
+
rails generate inline_forms Thing name:text_field description:plain_text yesno:check_box gender:boolean_with_values
|
|
7
7
|
|
|
8
8
|
This will create:
|
|
9
9
|
create app/models/thing.rb
|
|
@@ -19,7 +19,7 @@ This will create:
|
|
|
19
19
|
def inline_forms_field_list
|
|
20
20
|
[
|
|
21
21
|
[ :name, 'name', :text_field ],
|
|
22
|
-
[ :description, 'description', :
|
|
22
|
+
[ :description, 'description', :plain_text ],
|
|
23
23
|
[ :yesno, 'yesno', :check_box ],
|
|
24
24
|
[ :gender, 'gender', :boolean_with_values ],
|
|
25
25
|
]
|
|
@@ -223,6 +223,15 @@ select:hover, select:focus {
|
|
|
223
223
|
font-weight: bold;
|
|
224
224
|
font-size: 110%;
|
|
225
225
|
}
|
|
226
|
+
// Custom elements default to `display: inline`, which collapses the row layout
|
|
227
|
+
// of a top-level `<turbo-frame id="apartments_list">` inside `#outer_container`.
|
|
228
|
+
turbo-frame {
|
|
229
|
+
display: block;
|
|
230
|
+
}
|
|
231
|
+
#outer_container > turbo-frame.list_container {
|
|
232
|
+
display: block;
|
|
233
|
+
width: 100%;
|
|
234
|
+
}
|
|
226
235
|
.list_container {
|
|
227
236
|
.row {
|
|
228
237
|
font-size: 1.2rem;
|
|
@@ -258,6 +267,30 @@ select:hover, select:focus {
|
|
|
258
267
|
}
|
|
259
268
|
}
|
|
260
269
|
|
|
270
|
+
// Field edit cancel: outer <a> carries Turbo/UJS; inner input[type=button] matches ok height.
|
|
271
|
+
.edit_form .row.collapse {
|
|
272
|
+
input[type="submit"].postfix.button,
|
|
273
|
+
a.inline_forms-field-cancel input[type="button"].postfix.button {
|
|
274
|
+
margin: 2px 0 !important;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.edit_form a.inline_forms-field-cancel {
|
|
279
|
+
display: inline-block;
|
|
280
|
+
padding: 0;
|
|
281
|
+
border: 0;
|
|
282
|
+
background: transparent;
|
|
283
|
+
line-height: 0;
|
|
284
|
+
vertical-align: top;
|
|
285
|
+
text-decoration: none;
|
|
286
|
+
|
|
287
|
+
input[type="button"] {
|
|
288
|
+
pointer-events: none;
|
|
289
|
+
cursor: pointer;
|
|
290
|
+
width: auto;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
261
294
|
.object_presentation {
|
|
262
295
|
background-color: #B94C32;
|
|
263
296
|
color: white;
|
|
@@ -434,22 +467,6 @@ select:hover, select:focus {
|
|
|
434
467
|
margin-bottom: 0.5em;
|
|
435
468
|
}
|
|
436
469
|
|
|
437
|
-
.ckeditor_area {
|
|
438
|
-
position: relative;
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
.ckeditor_area .glass_plate {
|
|
442
|
-
position: absolute;
|
|
443
|
-
top: -1px;
|
|
444
|
-
width: 98%;
|
|
445
|
-
height: 232px;
|
|
446
|
-
border: 0;
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
.ckeditor_area .cke_top, .ckeditor_area .cke_bottom, .ckeditor_area .cke_border {
|
|
450
|
-
display: none;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
470
|
/* jQuery ui Slider 8 */
|
|
454
471
|
.slider {
|
|
455
472
|
width: 300px;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
module InlineForms
|
|
3
|
+
class ArchivedFormElementError < StandardError; end
|
|
4
|
+
|
|
5
|
+
# Retired form-element symbols. Full source for entries with +archive_path+ lives
|
|
6
|
+
# under archived/form_elements/<name>/ — see archived/README.md.
|
|
7
|
+
ARCHIVED_FORM_ELEMENTS = {
|
|
8
|
+
geo_code_curacao: {
|
|
9
|
+
archived_in_version: "7.6.0",
|
|
10
|
+
archive_path: "archived/form_elements/geo_code_curacao",
|
|
11
|
+
summary: "Curaçao street geocode (MySQL Zones/Buurten/Straatcode, jQuery autocomplete, UJS list_streets).",
|
|
12
|
+
},
|
|
13
|
+
chicas_photo_list: {
|
|
14
|
+
archived_in_version: "7.6.0",
|
|
15
|
+
archive_path: "archived/form_elements/chicas",
|
|
16
|
+
summary: "Chicas app read-only member photo gallery (show-only).",
|
|
17
|
+
},
|
|
18
|
+
chicas_family_photo_list: {
|
|
19
|
+
archived_in_version: "7.6.0",
|
|
20
|
+
archive_path: "archived/form_elements/chicas",
|
|
21
|
+
summary: "Chicas app read-only family member photo gallery (show-only).",
|
|
22
|
+
},
|
|
23
|
+
chicas_dropdown_with_family_members: {
|
|
24
|
+
archived_in_version: "7.6.0",
|
|
25
|
+
archive_path: "archived/form_elements/chicas",
|
|
26
|
+
summary: "Chicas client picker via family.clients; moves CarrierWave upload dir on update.",
|
|
27
|
+
},
|
|
28
|
+
kansen_slider: {
|
|
29
|
+
archived_in_version: "7.6.0",
|
|
30
|
+
archive_path: "archived/form_elements/kansen_slider",
|
|
31
|
+
summary: "jQuery UI slider for integer-coded chance scale; uses model attribute_values.",
|
|
32
|
+
},
|
|
33
|
+
tree: {
|
|
34
|
+
archived_in_version: "7.7.0",
|
|
35
|
+
archive_path: "archived/form_elements/tree",
|
|
36
|
+
summary: "Self-referential children list via parent.children; requires host tree APIs (see README).",
|
|
37
|
+
},
|
|
38
|
+
move: {
|
|
39
|
+
archived_in_version: "7.7.0",
|
|
40
|
+
archive_path: "archived/form_elements/tree",
|
|
41
|
+
summary: "Reparent via hash_tree_to_collection + add_child (host must implement; pairs with :tree).",
|
|
42
|
+
},
|
|
43
|
+
absence_list: {
|
|
44
|
+
removed_in_version: "6.3.0",
|
|
45
|
+
archive_path: nil,
|
|
46
|
+
summary: "Project-specific absence list UI; removed without a copy in this repo (see CHANGELOG 6.3.0).",
|
|
47
|
+
},
|
|
48
|
+
}.freeze
|
|
49
|
+
|
|
50
|
+
def self.validate_no_archived_form_elements_for!(klass)
|
|
51
|
+
return unless klass.instance_methods.include?(:inline_forms_attribute_list)
|
|
52
|
+
|
|
53
|
+
klass.new.inline_forms_attribute_list.each do |attribute, _label, form_element|
|
|
54
|
+
key = form_element.to_sym
|
|
55
|
+
next unless ARCHIVED_FORM_ELEMENTS.key?(key)
|
|
56
|
+
|
|
57
|
+
meta = ARCHIVED_FORM_ELEMENTS[key]
|
|
58
|
+
version = meta[:archived_in_version] || meta[:removed_in_version]
|
|
59
|
+
hint = if meta[:archive_path]
|
|
60
|
+
"Restore from #{meta[:archive_path]}/README.md or vendor into your app."
|
|
61
|
+
else
|
|
62
|
+
"See archived/README.md and CHANGELOG #{version}."
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
raise ArchivedFormElementError,
|
|
66
|
+
"#{klass.name} inline_forms_attribute_list declares #{attribute}:#{form_element}, " \
|
|
67
|
+
"which was retired in inline_forms #{version} (#{meta[:summary]}). #{hint}"
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
data/lib/inline_forms/version.rb
CHANGED
data/lib/inline_forms.rb
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
|
2
2
|
require ('inline_forms/version.rb')
|
|
3
3
|
require_relative ('inline_forms/form_element_from_callee')
|
|
4
|
+
require_relative ('inline_forms/archived_form_elements')
|
|
4
5
|
# InlineForms is a Rails Engine that let you setup an admin interface quick and
|
|
5
6
|
# easy. Please install it as a gem or include it in your Gemfile.
|
|
6
7
|
module InlineForms
|
|
8
|
+
class PlainTextColumnMissingError < StandardError; end
|
|
9
|
+
|
|
7
10
|
# DEFAULT_COLUMN_TYPES holds the standard ActiveRecord::Migration column types.
|
|
8
11
|
# This list provides compatability with the standard types, but we add our own
|
|
9
12
|
# later in 'Special Column Types'.
|
|
@@ -62,7 +65,7 @@ module InlineForms
|
|
|
62
65
|
#
|
|
63
66
|
DEFAULT_FORM_ELEMENTS = {
|
|
64
67
|
:string => :text_field,
|
|
65
|
-
:text => :
|
|
68
|
+
:text => :plain_text,
|
|
66
69
|
:integer => :text_field,
|
|
67
70
|
:float => :text_field,
|
|
68
71
|
:decimal => :text_field,
|
|
@@ -93,6 +96,45 @@ module InlineForms
|
|
|
93
96
|
:associated => :no_migration
|
|
94
97
|
}
|
|
95
98
|
|
|
99
|
+
PLAIN_TEXT_FORM_ELEMENTS = %i[
|
|
100
|
+
plain_text
|
|
101
|
+
plain_text_area
|
|
102
|
+
text_area_without_ckeditor
|
|
103
|
+
].freeze
|
|
104
|
+
|
|
105
|
+
def self.plain_text_form_element?(form_element)
|
|
106
|
+
PLAIN_TEXT_FORM_ELEMENTS.include?(form_element.to_sym)
|
|
107
|
+
rescue NoMethodError
|
|
108
|
+
false
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def self.assert_plain_text_column!(object:, attribute:, form_element:)
|
|
112
|
+
return unless plain_text_form_element?(form_element)
|
|
113
|
+
return if object.class.column_names.include?(attribute.to_s)
|
|
114
|
+
|
|
115
|
+
raise PlainTextColumnMissingError,
|
|
116
|
+
"#{object.class.name}##{attribute} uses #{form_element} but has no DB column `#{attribute}`. " \
|
|
117
|
+
"Use :rich_text for ActionText-backed attributes, or add a text column for :plain_text."
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def self.validate_plain_text_configuration_for!(klass)
|
|
121
|
+
return unless klass.respond_to?(:table_exists?) &&
|
|
122
|
+
klass.respond_to?(:column_names) &&
|
|
123
|
+
klass.instance_methods.include?(:inline_forms_attribute_list)
|
|
124
|
+
return unless klass.table_exists?
|
|
125
|
+
|
|
126
|
+
attributes = klass.new.inline_forms_attribute_list
|
|
127
|
+
attributes.each do |attribute, _label, form_element|
|
|
128
|
+
next unless plain_text_form_element?(form_element)
|
|
129
|
+
next if klass.column_names.include?(attribute.to_s)
|
|
130
|
+
|
|
131
|
+
raise PlainTextColumnMissingError,
|
|
132
|
+
"#{klass.name} inline_forms_attribute_list declares #{attribute}:#{form_element}, " \
|
|
133
|
+
"but table `#{klass.table_name}` has no `#{attribute}` column. " \
|
|
134
|
+
"Use :rich_text for ActionText-backed attributes."
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
96
138
|
# RELATIONS defines a mapping between AR::Migrations columns and the Model.
|
|
97
139
|
#
|
|
98
140
|
# When a column has the type of :references or :belongs_to, then
|
|
@@ -144,7 +186,6 @@ module InlineForms
|
|
|
144
186
|
inline_forms/inline_forms.css
|
|
145
187
|
inline_forms/devise.css
|
|
146
188
|
inline_forms/inline_forms.js
|
|
147
|
-
inline_forms/ckeditor/config.js
|
|
148
189
|
inline_forms/glass_plate.gif
|
|
149
190
|
)
|
|
150
191
|
end
|
|
@@ -159,6 +200,23 @@ module InlineForms
|
|
|
159
200
|
app.config.assets.paths << path unless app.config.assets.paths.include?(path)
|
|
160
201
|
end
|
|
161
202
|
|
|
203
|
+
config.to_prepare do
|
|
204
|
+
next unless defined?(ActiveRecord::Base)
|
|
205
|
+
|
|
206
|
+
ActiveRecord::Base.descendants.each do |klass|
|
|
207
|
+
begin
|
|
208
|
+
InlineForms.validate_no_archived_form_elements_for!(klass)
|
|
209
|
+
InlineForms.validate_plain_text_configuration_for!(klass)
|
|
210
|
+
rescue InlineForms::PlainTextColumnMissingError, InlineForms::ArchivedFormElementError
|
|
211
|
+
raise
|
|
212
|
+
rescue StandardError
|
|
213
|
+
# Some descendants might be abstract or temporarily unresolved while
|
|
214
|
+
# the app boots/reloads; runtime checks in controllers still enforce
|
|
215
|
+
# plain_text column presence for active resources.
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
162
220
|
I18n.load_path << Dir[File.join(File.expand_path(File.dirname(__FILE__) + '/locales'), '*.yml')]
|
|
163
221
|
I18n.load_path.flatten!
|
|
164
222
|
end
|