turbo_form 0.8.0 → 0.9.0
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/README.md +8 -20
- data/lib/generators/turbo_form/install/install_generator.rb +2 -15
- data/lib/turbo_form/controller.rb +1 -1
- data/lib/turbo_form/engine.rb +10 -0
- data/lib/turbo_form/form_builder.rb +5 -3
- data/lib/turbo_form/routes.rb +10 -1
- data/lib/turbo_form/select_renderer.rb +11 -0
- data/lib/turbo_form/system_test_helper.rb +4 -3
- data/lib/turbo_form/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cb59d187ec74c47b4ed52d8067f54faa85997be5e5551d22771b12c4224017fe
|
|
4
|
+
data.tar.gz: 376442d6aaf5c3d403355bc2ba1f4c653d4794fdd5b22288aa3650c0a132e3b2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 344e3f436b6fa24fcbbcd6f65e04a0212ff588b77766f121e7941decfa4ad4bcaa2ef181cc295c60a4eb80af1b7f14390387c74ced7c8ac106c67de1ffca7bdb
|
|
7
|
+
data.tar.gz: 5eb9d4403823fe67d7eaaf438d429e46d28c33e6163fd144b8f7aecd4a3e4ea478bd9c59ce066196da8bb2b5c67c40588000361b271339ea50c3d4dbf9b9e7ec
|
data/README.md
CHANGED
|
@@ -36,21 +36,12 @@ Then run the installer:
|
|
|
36
36
|
rails generate turbo_form:install
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
It
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
```ruby
|
|
43
|
-
class ApplicationController < ActionController::Base
|
|
44
|
-
include TurboForm::Controller
|
|
45
|
-
end
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
```ruby
|
|
49
|
-
concern :turbo_form, TurboForm::Routes
|
|
50
|
-
```
|
|
39
|
+
It imports the script into `app/javascript/application.js`, adding the npm
|
|
40
|
+
package first if your app bundles with esbuild, Vite, Bun or webpack; see
|
|
41
|
+
[JavaScript](#javascript) for doing that by hand.
|
|
51
42
|
|
|
52
|
-
|
|
53
|
-
|
|
43
|
+
The engine does the rest. Draw the `:turbo_form` route concern on each resource
|
|
44
|
+
with a dynamic form:
|
|
54
45
|
|
|
55
46
|
```ruby
|
|
56
47
|
resources :widgets, concerns: :turbo_form
|
|
@@ -58,11 +49,8 @@ resources :widgets, concerns: :turbo_form
|
|
|
58
49
|
|
|
59
50
|
It draws a PATCH beside whichever of `new` and `edit` the resource has, so
|
|
60
51
|
`resources :widgets, only: %i[new create], concerns: :turbo_form` gets only the
|
|
61
|
-
one for `new`.
|
|
62
|
-
|
|
63
|
-
It also imports the script into `app/javascript/application.js`, adding the npm
|
|
64
|
-
package first if your app bundles with esbuild, Vite, Bun or webpack; see
|
|
65
|
-
[JavaScript](#javascript) for doing that by hand.
|
|
52
|
+
one for `new`. Every controller inheriting from `ActionController::Base` already
|
|
53
|
+
knows how to answer it.
|
|
66
54
|
|
|
67
55
|
## The options
|
|
68
56
|
|
|
@@ -70,7 +58,7 @@ package first if your app bundles with esbuild, Vite, Bun or webpack; see
|
|
|
70
58
|
|
|
71
59
|
`dynamic: true` makes the form dynamic: a trigger sends it to the `new` or `edit`
|
|
72
60
|
page of its model — `edit` once the record is saved — which is where
|
|
73
|
-
|
|
61
|
+
the route concern listens.
|
|
74
62
|
|
|
75
63
|
### `dynamic_trigger:` on a field
|
|
76
64
|
|
|
@@ -2,9 +2,8 @@ require 'rails/generators'
|
|
|
2
2
|
|
|
3
3
|
module TurboForm
|
|
4
4
|
module Generators
|
|
5
|
-
# Every app gets
|
|
6
|
-
#
|
|
7
|
-
# script itself; bundled apps get the npm package to import instead.
|
|
5
|
+
# Every app gets an import of the script. On importmap-rails the engine pins
|
|
6
|
+
# the script itself; bundled apps get the npm package to import instead.
|
|
8
7
|
class InstallGenerator < Rails::Generators::Base
|
|
9
8
|
LOCKFILES = {
|
|
10
9
|
'yarn.lock' => 'yarn add', 'pnpm-lock.yaml' => 'pnpm add',
|
|
@@ -14,23 +13,11 @@ module TurboForm
|
|
|
14
13
|
ENTRYPOINT = 'app/javascript/application.js'
|
|
15
14
|
|
|
16
15
|
def install
|
|
17
|
-
include_controller
|
|
18
|
-
declare_route_concern
|
|
19
16
|
install_package unless importmap?
|
|
20
17
|
import_script
|
|
21
18
|
end
|
|
22
19
|
|
|
23
20
|
private
|
|
24
|
-
def include_controller
|
|
25
|
-
inject_into_class 'app/controllers/application_controller.rb', 'ApplicationController', " include TurboForm::Controller\n"
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
# Declared once, drawn on no resource: which forms are dynamic is the
|
|
29
|
-
# app's call, one `concerns: :turbo_form` at a time.
|
|
30
|
-
def declare_route_concern
|
|
31
|
-
route 'concern :turbo_form, TurboForm::Routes'
|
|
32
|
-
end
|
|
33
|
-
|
|
34
21
|
def importmap? = Rails.root.join('config/importmap.rb').exist?
|
|
35
22
|
|
|
36
23
|
def install_package
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
module TurboForm
|
|
2
|
-
# Included into the
|
|
2
|
+
# Included into ActionController::Base by the engine. A request that
|
|
3
3
|
# TurboForm::Routes marks runs `new` or `edit` as usual, callbacks and all,
|
|
4
4
|
# then assigns the form to what the action built just before it renders --
|
|
5
5
|
# implicitly, or with its own `render layout: 'panel'`.
|
data/lib/turbo_form/engine.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
require 'turbo-rails'
|
|
2
2
|
require 'turbo_form/form_helper'
|
|
3
3
|
require 'turbo_form/form_builder'
|
|
4
|
+
require 'turbo_form/select_renderer'
|
|
4
5
|
require 'turbo_form/routes'
|
|
5
6
|
require 'turbo_form/controller'
|
|
6
7
|
|
|
@@ -50,6 +51,14 @@ module TurboForm
|
|
|
50
51
|
end
|
|
51
52
|
end
|
|
52
53
|
|
|
54
|
+
initializer 'turbo_form.controller' do
|
|
55
|
+
ActiveSupport.on_load(:action_controller_base) { include TurboForm::Controller }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
initializer 'turbo_form.routes' do
|
|
59
|
+
ActionDispatch::Routing::Mapper.prepend(TurboForm::Routes::Declared)
|
|
60
|
+
end
|
|
61
|
+
|
|
53
62
|
# Deliberately eager rather than `ActiveSupport.on_load(:action_view)`: that
|
|
54
63
|
# hook doesn't fire until Action View is first loaded, which in an app that
|
|
55
64
|
# isn't eager loading is partway through rendering the first view -- late
|
|
@@ -59,6 +68,7 @@ module TurboForm
|
|
|
59
68
|
|
|
60
69
|
ActionView::Helpers::FormHelper.prepend(TurboForm::FormHelper)
|
|
61
70
|
ActionView::Helpers::FormBuilder.prepend(TurboForm::FormBuilder)
|
|
71
|
+
ActionView::Helpers::Tags::SelectRenderer.prepend(TurboForm::SelectRenderer)
|
|
62
72
|
end
|
|
63
73
|
end
|
|
64
74
|
end
|
|
@@ -78,9 +78,11 @@ module TurboForm
|
|
|
78
78
|
[ options.except(*DYNAMIC_OPTIONS), absorb_trigger(html_options.merge(options.slice(*DYNAMIC_OPTIONS))) ]
|
|
79
79
|
end
|
|
80
80
|
|
|
81
|
+
def absorb_trigger(attributes) = FormBuilder.absorb_trigger(attributes, @template)
|
|
82
|
+
|
|
81
83
|
# `dynamic_action:` makes a trigger of its own, on the default event unless
|
|
82
84
|
# `dynamic_trigger:` names one. It takes whatever `url_for` does.
|
|
83
|
-
def absorb_trigger(attributes)
|
|
85
|
+
def self.absorb_trigger(attributes, template)
|
|
84
86
|
return attributes unless attributes.keys.intersect?(DYNAMIC_OPTIONS)
|
|
85
87
|
|
|
86
88
|
trigger, action = attributes.values_at(*DYNAMIC_OPTIONS)
|
|
@@ -88,12 +90,12 @@ module TurboForm
|
|
|
88
90
|
trigger ||= action.present?
|
|
89
91
|
return attributes unless trigger
|
|
90
92
|
|
|
91
|
-
attributes.merge(data: { **attributes[:data].to_h, turbo_form_trigger: trigger_event(trigger), turbo_form_action: (
|
|
93
|
+
attributes.merge(data: { **attributes[:data].to_h, turbo_form_trigger: trigger_event(trigger), turbo_form_action: (template.url_for(action) if action) })
|
|
92
94
|
end
|
|
93
95
|
|
|
94
96
|
# Left blank for `true`, which the script reads as the element's own
|
|
95
97
|
# default: `change` for a select, `input` for a text field, `click` for a
|
|
96
98
|
# button.
|
|
97
|
-
def trigger_event(trigger) = trigger == true ? '' : trigger.to_s
|
|
99
|
+
def self.trigger_event(trigger) = trigger == true ? '' : trigger.to_s
|
|
98
100
|
end
|
|
99
101
|
end
|
data/lib/turbo_form/routes.rb
CHANGED
|
@@ -3,7 +3,6 @@ module TurboForm
|
|
|
3
3
|
# and `edit` it has, at the same paths and onto the same actions, marked so the
|
|
4
4
|
# controller renders them from what the form currently holds.
|
|
5
5
|
#
|
|
6
|
-
# concern :turbo_form, TurboForm::Routes
|
|
7
6
|
# resources :widgets, concerns: :turbo_form
|
|
8
7
|
module Routes
|
|
9
8
|
def self.call(mapper, _options = {})
|
|
@@ -12,5 +11,15 @@ module TurboForm
|
|
|
12
11
|
mapper.new { mapper.patch :new, as: nil, defaults: { dynamic_form: true } } if actions.include?(:new)
|
|
13
12
|
mapper.patch :edit, on: :member, as: nil, defaults: { dynamic_form: true } if actions.include?(:edit)
|
|
14
13
|
end
|
|
14
|
+
|
|
15
|
+
# Rails keeps concerns per Mapper, and builds a fresh one for every `draw`,
|
|
16
|
+
# `prepend` and `append`, so declaring it once from the engine can't reach
|
|
17
|
+
# them all. An app's own `concern :turbo_form` still replaces this one.
|
|
18
|
+
module Declared
|
|
19
|
+
def initialize(...)
|
|
20
|
+
super
|
|
21
|
+
concern :turbo_form, TurboForm::Routes
|
|
22
|
+
end
|
|
23
|
+
end
|
|
15
24
|
end
|
|
16
25
|
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
module TurboForm
|
|
2
|
+
# Prepended onto ActionView::Helpers::Tags::SelectRenderer, which every select
|
|
3
|
+
# tag renders through -- including those of builder methods other gems add,
|
|
4
|
+
# like country_select's, which hand their html_options straight to the tag.
|
|
5
|
+
module SelectRenderer
|
|
6
|
+
private
|
|
7
|
+
def select_content_tag(option_tags, options, html_options)
|
|
8
|
+
super(option_tags, options, FormBuilder.absorb_trigger(html_options.symbolize_keys, @template_object))
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
module TurboForm::SystemTestHelper
|
|
2
|
-
# Waits for a dynamic form to finish reloading the page.
|
|
2
|
+
# Waits for a dynamic form to finish reloading the page. Reads <html> from the
|
|
3
|
+
# document, so it works inside `within` too.
|
|
3
4
|
#
|
|
4
5
|
# expect_dynamic_form_request { select "Bourbon", from: "Category" }
|
|
5
6
|
# select "Barrel Aged", from: "Flavor"
|
|
6
7
|
def expect_dynamic_form_request
|
|
7
|
-
completed = page.find('html')['data-turbo-form-visits'].to_i + 1
|
|
8
|
+
completed = page.document.find('html')['data-turbo-form-visits'].to_i + 1
|
|
8
9
|
|
|
9
10
|
yield
|
|
10
11
|
|
|
11
|
-
page.assert_selector "html[data-turbo-form-visits='#{completed}']"
|
|
12
|
+
page.document.assert_selector "html[data-turbo-form-visits='#{completed}']"
|
|
12
13
|
end
|
|
13
14
|
end
|
data/lib/turbo_form/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: turbo_form
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andy Cohen
|
|
@@ -85,6 +85,7 @@ files:
|
|
|
85
85
|
- lib/turbo_form/form_builder.rb
|
|
86
86
|
- lib/turbo_form/form_helper.rb
|
|
87
87
|
- lib/turbo_form/routes.rb
|
|
88
|
+
- lib/turbo_form/select_renderer.rb
|
|
88
89
|
- lib/turbo_form/system_test_helper.rb
|
|
89
90
|
- lib/turbo_form/version.rb
|
|
90
91
|
homepage: https://github.com/outlawandy/turbo_form
|
|
@@ -108,7 +109,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
108
109
|
- !ruby/object:Gem::Version
|
|
109
110
|
version: '0'
|
|
110
111
|
requirements: []
|
|
111
|
-
rubygems_version: 4.0.
|
|
112
|
+
rubygems_version: 4.0.16
|
|
112
113
|
specification_version: 4
|
|
113
114
|
summary: Turbo-Stream backed dynamic forms, by convention.
|
|
114
115
|
test_files: []
|