view_partial_form_builder 0.1.5 → 0.2.2
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 +15 -14
- data/lib/view_partial_form_builder/engine.rb +10 -2
- data/lib/view_partial_form_builder/form_builder.rb +5 -337
- data/lib/view_partial_form_builder/lookup_override.rb +8 -12
- data/lib/view_partial_form_builder/template_proxy.rb +120 -0
- data/lib/view_partial_form_builder/version.rb +1 -1
- data/lib/view_partial_form_builder.rb +5 -1
- metadata +14 -42
- data/lib/view_partial_form_builder/html_attributes.rb +0 -55
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c09b26fa824aff0b6fc36212577a96ca2daecefdf5dda0614ab000ea5882d4a3
|
4
|
+
data.tar.gz: dfaccd8fd95ec8049e4518079b67af9962fa1b2ffb28125233f400f109bf054f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6f3381c4245c6bd84e61c79d3d28b9ff195a4fa632f657be10153b7c58af1ce29ff2253556858450a9464b6b2b39a82aab83e53cc1327a046d77b2f21348be48
|
7
|
+
data.tar.gz: e0e2f622b47ed7bd4db4873f5864746c0663d64fed8583475a75ab4744b60567edcad91156cf721921aa4ee36d5a370a4116efd5b7c0b06839c597ae99825d40
|
data/README.md
CHANGED
@@ -37,7 +37,7 @@ Next, declare view partials that correspond to the [`FormBuilder`][FormBuilder]
|
|
37
37
|
helper method you'd like to have more control over:
|
38
38
|
|
39
39
|
```html+erb
|
40
|
-
<%# app/views/form_builder/_text_field.html.erb %>
|
40
|
+
<%# app/views/application/form_builder/_text_field.html.erb %>
|
41
41
|
|
42
42
|
<input
|
43
43
|
type="text"
|
@@ -48,7 +48,7 @@ helper method you'd like to have more control over:
|
|
48
48
|
<% end %>
|
49
49
|
>
|
50
50
|
|
51
|
-
<%# app/views/form_builder/_email_field.html.erb %>
|
51
|
+
<%# app/views/application/form_builder/_email_field.html.erb %>
|
52
52
|
|
53
53
|
<input
|
54
54
|
type="email"
|
@@ -59,7 +59,7 @@ helper method you'd like to have more control over:
|
|
59
59
|
<% end %>
|
60
60
|
>
|
61
61
|
|
62
|
-
<%# app/views/form_builder/_button.html.erb %>
|
62
|
+
<%# app/views/application/form_builder/_button.html.erb %>
|
63
63
|
|
64
64
|
<button
|
65
65
|
class="button button--primary"
|
@@ -76,7 +76,7 @@ You'll have local access to the `FormBuilder` instance as the template-local
|
|
76
76
|
generating HTML through Rails' helpers:
|
77
77
|
|
78
78
|
```html+erb
|
79
|
-
<%# app/views/form_builder/_email_field.html.erb %>
|
79
|
+
<%# app/views/application/form_builder/_email_field.html.erb %>
|
80
80
|
|
81
81
|
<div class="email-field-wrapper">
|
82
82
|
<%= form.email_field(method, required: true, **options)) %>
|
@@ -84,7 +84,7 @@ generating HTML through Rails' helpers:
|
|
84
84
|
```
|
85
85
|
|
86
86
|
```html+erb
|
87
|
-
<%# app/views/form_builder/_button.html.erb %>
|
87
|
+
<%# app/views/application/form_builder/_button.html.erb %>
|
88
88
|
|
89
89
|
<div class="button-wrapper">
|
90
90
|
<%= form.button(value, options, &block) %>
|
@@ -116,7 +116,8 @@ In addition, each view partial receives:
|
|
116
116
|
* `form` - a reference to the instance of `ViewPartialFormBuilder`, which is a
|
117
117
|
descendant of [`ActionView::Helpers::FormBuilder`][FormBuilder]
|
118
118
|
|
119
|
-
*
|
119
|
+
* `block` - the block if the helper method was passed one. Forward it along to
|
120
|
+
field helpers as `&block`.
|
120
121
|
|
121
122
|
#### Handling DOMTokenList attributes
|
122
123
|
|
@@ -148,7 +149,7 @@ and `Hash#delete`:
|
|
148
149
|
<%= form.text_field(:name, class: "text-field--modifier") %>
|
149
150
|
<% end %>
|
150
151
|
|
151
|
-
<# app/views/form_builder/_text_field.html.erb %>
|
152
|
+
<# app/views/application/form_builder/_text_field.html.erb %>
|
152
153
|
|
153
154
|
<%= form.text_field(
|
154
155
|
method,
|
@@ -195,7 +196,7 @@ look up path.
|
|
195
196
|
|
196
197
|
For example, when calling `form_with(model: User.new)`, a partial declared in
|
197
198
|
`app/views/users/form_builder/` would take precedent over a partial declared in
|
198
|
-
`app/views/form_builder/`.
|
199
|
+
`app/views/application/form_builder/`.
|
199
200
|
|
200
201
|
```erb
|
201
202
|
<%# app/views/users/form_builder/_password_field.html.erb %>
|
@@ -240,13 +241,13 @@ additional bells and whistles.
|
|
240
241
|
Declare the consumer facing inputs (in this example, `<input type="search">`):
|
241
242
|
|
242
243
|
```html+erb
|
243
|
-
<%# app/views/form_builder/_search_field.html.erb %>
|
244
|
+
<%# app/views/application/form_builder/_search_field.html.erb %>
|
244
245
|
|
245
246
|
<%= form.search_field(
|
246
247
|
method,
|
247
248
|
class: "
|
248
249
|
search-field
|
249
|
-
#{options.delete(:class}
|
250
|
+
#{options.delete(:class)}
|
250
251
|
",
|
251
252
|
"data-controller": "
|
252
253
|
input->search#executeQuery
|
@@ -260,7 +261,7 @@ Then, declare the administrative interface's inputs, in terms of overriding the
|
|
260
261
|
foundation built by the more general definitions:
|
261
262
|
|
262
263
|
```html+erb
|
263
|
-
<%# app/views/admin/form_builder/_search_field.html.erb %>
|
264
|
+
<%# app/views/admin/application/form_builder/_search_field.html.erb %>
|
264
265
|
|
265
266
|
<%= form.search_field(
|
266
267
|
method,
|
@@ -275,8 +276,8 @@ foundation built by the more general definitions:
|
|
275
276
|
) %>
|
276
277
|
```
|
277
278
|
|
278
|
-
The rendered `admin/form_builder/search_field` partial combines
|
279
|
-
arguments from both partials:
|
279
|
+
The rendered `admin/application/form_builder/search_field` partial combines
|
280
|
+
options and arguments from both partials:
|
280
281
|
|
281
282
|
```html
|
282
283
|
<input
|
@@ -326,7 +327,7 @@ Models declared within modules will be delimited with `/`. For example,
|
|
326
327
|
### Configuration
|
327
328
|
|
328
329
|
View partials lookup and resolution will be scoped to the
|
329
|
-
`app/views/form_builder` directory.
|
330
|
+
`app/views/application/form_builder` directory.
|
330
331
|
|
331
332
|
To override this destination to another directory (for example,
|
332
333
|
`app/views/fields`, or `app/views/users/fields`), set
|
@@ -1,9 +1,17 @@
|
|
1
|
-
require "view_partial_form_builder/form_builder"
|
2
|
-
|
3
1
|
module ViewPartialFormBuilder
|
4
2
|
class Engine < ::Rails::Engine
|
5
3
|
ActiveSupport.on_load(:action_controller_base) do
|
6
4
|
default_form_builder ViewPartialFormBuilder::FormBuilder
|
7
5
|
end
|
6
|
+
|
7
|
+
ActiveSupport.on_load(:view_partial_form_builder) do
|
8
|
+
if Rails::VERSION::MAJOR > 7
|
9
|
+
self.aliased_field_helpers = {
|
10
|
+
checkbox: [:check_box],
|
11
|
+
collection_checkboxes: [:collection_check_boxes],
|
12
|
+
rich_textarea: [:rich_text_area]
|
13
|
+
}
|
14
|
+
end
|
15
|
+
end
|
8
16
|
end
|
9
17
|
end
|
@@ -1,347 +1,15 @@
|
|
1
|
-
require "view_partial_form_builder/lookup_override"
|
2
|
-
require "view_partial_form_builder/html_attributes"
|
3
|
-
|
4
1
|
module ViewPartialFormBuilder
|
5
2
|
class FormBuilder < ActionView::Helpers::FormBuilder
|
3
|
+
class_attribute :aliased_field_helpers, default: {}
|
4
|
+
|
6
5
|
attr_reader :default
|
7
6
|
|
8
7
|
def initialize(*)
|
9
8
|
super
|
10
|
-
|
11
|
-
@
|
12
|
-
object_name,
|
13
|
-
object,
|
14
|
-
@template,
|
15
|
-
options,
|
16
|
-
)
|
17
|
-
@lookup_override = LookupOverride.new(
|
18
|
-
prefixes: @template.lookup_context.prefixes,
|
19
|
-
object_name: object&.model_name || object_name,
|
20
|
-
view_partial_directory: ViewPartialFormBuilder.view_partial_directory,
|
21
|
-
)
|
22
|
-
end
|
23
|
-
|
24
|
-
def label(method, text = nil, **options, &block)
|
25
|
-
locals = {
|
26
|
-
method: method,
|
27
|
-
text: text,
|
28
|
-
options: HtmlAttributes.new(options),
|
29
|
-
block: block,
|
30
|
-
arguments: [method, text],
|
31
|
-
}
|
32
|
-
|
33
|
-
render_partial("label", locals, fallback: -> { super }, &block)
|
34
|
-
end
|
35
|
-
|
36
|
-
def check_box(method, options = {}, checked_value = "1", unchecked_value = "0")
|
37
|
-
locals = {
|
38
|
-
method: method,
|
39
|
-
options: HtmlAttributes.new(options),
|
40
|
-
checked_value: checked_value,
|
41
|
-
unchecked_value: unchecked_value,
|
42
|
-
arguments: [method, options, checked_value, unchecked_value],
|
43
|
-
}
|
44
|
-
|
45
|
-
render_partial("check_box", locals, fallback: -> { super })
|
46
|
-
end
|
47
|
-
|
48
|
-
def radio_button(method, tag_value, **options)
|
49
|
-
locals = {
|
50
|
-
method: method,
|
51
|
-
tag_value: tag_value,
|
52
|
-
options: HtmlAttributes.new(options),
|
53
|
-
arguments: [method, tag_value],
|
54
|
-
}
|
55
|
-
|
56
|
-
render_partial("radio_button", locals, fallback: -> { super })
|
57
|
-
end
|
58
|
-
|
59
|
-
def select(method, choices = nil, options = {}, **html_options, &block)
|
60
|
-
html_options = @default_html_options.merge(html_options)
|
61
|
-
|
62
|
-
locals = {
|
63
|
-
method: method,
|
64
|
-
choices: choices,
|
65
|
-
options: options,
|
66
|
-
html_options: HtmlAttributes.new(html_options),
|
67
|
-
block: block,
|
68
|
-
arguments: [method, choices, options],
|
69
|
-
}
|
70
|
-
|
71
|
-
render_partial("select", locals, fallback: -> { super }, &block)
|
72
|
-
end
|
73
|
-
|
74
|
-
def collection_select(method, collection, value_method, text_method, options = {}, **html_options)
|
75
|
-
html_options = @default_html_options.merge(html_options)
|
76
|
-
|
77
|
-
locals = {
|
78
|
-
method: method,
|
79
|
-
collection: collection,
|
80
|
-
value_method: value_method,
|
81
|
-
text_method: text_method,
|
82
|
-
options: options,
|
83
|
-
html_options: html_options,
|
84
|
-
arguments: [method, collection, value_method, text_method, options],
|
85
|
-
}
|
86
|
-
|
87
|
-
render_partial("collection_select", locals, fallback: -> { super })
|
88
|
-
end
|
89
|
-
|
90
|
-
def collection_check_boxes(method, collection, value_method, text_method, options = {}, **html_options, &block)
|
91
|
-
html_options = @default_html_options.merge(html_options)
|
92
|
-
|
93
|
-
locals = {
|
94
|
-
method: method,
|
95
|
-
collection: collection,
|
96
|
-
value_method: value_method,
|
97
|
-
text_method: text_method,
|
98
|
-
options: options,
|
99
|
-
html_options: HtmlAttributes.new(html_options),
|
100
|
-
block: block,
|
101
|
-
arguments: [
|
102
|
-
method,
|
103
|
-
collection,
|
104
|
-
value_method,
|
105
|
-
text_method,
|
106
|
-
options,
|
107
|
-
],
|
108
|
-
}
|
109
|
-
|
110
|
-
render_partial("collection_check_boxes", locals, fallback: -> { super }, &block)
|
111
|
-
end
|
112
|
-
|
113
|
-
def collection_radio_buttons(method, collection, value_method, text_method, options = {}, **html_options, &block)
|
114
|
-
html_options = @default_html_options.merge(html_options)
|
115
|
-
|
116
|
-
locals = {
|
117
|
-
method: method,
|
118
|
-
collection: collection,
|
119
|
-
value_method: value_method,
|
120
|
-
text_method: text_method,
|
121
|
-
options: options,
|
122
|
-
html_options: HtmlAttributes.new(html_options),
|
123
|
-
block: block,
|
124
|
-
arguments: [
|
125
|
-
method,
|
126
|
-
collection,
|
127
|
-
value_method,
|
128
|
-
text_method,
|
129
|
-
options,
|
130
|
-
],
|
131
|
-
}
|
132
|
-
|
133
|
-
render_partial("collection_radio_buttons", locals, fallback: -> { super }, &block)
|
134
|
-
end
|
135
|
-
|
136
|
-
def grouped_collection_select(method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, **html_options)
|
137
|
-
html_options = @default_html_options.merge(html_options)
|
138
|
-
|
139
|
-
locals = {
|
140
|
-
method: method,
|
141
|
-
collection: collection,
|
142
|
-
group_method: group_method,
|
143
|
-
group_label_method: group_label_method,
|
144
|
-
option_key_method: option_key_method,
|
145
|
-
option_value_method: option_value_method,
|
146
|
-
html_options: HtmlAttributes.new(html_options),
|
147
|
-
options: options,
|
148
|
-
arguments: [
|
149
|
-
method,
|
150
|
-
collection,
|
151
|
-
group_method,
|
152
|
-
group_label_method,
|
153
|
-
option_key_method,
|
154
|
-
option_value_method,
|
155
|
-
options,
|
156
|
-
],
|
157
|
-
}
|
158
|
-
|
159
|
-
render_partial("grouped_collection_select", locals, fallback: -> { super })
|
160
|
-
end
|
161
|
-
|
162
|
-
def time_zone_select(method, priority_zones = nil, options = {}, **html_options)
|
163
|
-
html_options = @default_html_options.merge(html_options)
|
164
|
-
|
165
|
-
locals = {
|
166
|
-
method: method,
|
167
|
-
priority_zones: priority_zones,
|
168
|
-
html_options: HtmlAttributes.new(html_options),
|
169
|
-
options: options,
|
170
|
-
arguments: [method, priority_zones, options],
|
171
|
-
}
|
172
|
-
|
173
|
-
render_partial("time_zone_select", locals, fallback: -> { super })
|
174
|
-
end
|
175
|
-
|
176
|
-
def date_select(method, options = {}, **html_options)
|
177
|
-
locals = {
|
178
|
-
method: method,
|
179
|
-
options: options,
|
180
|
-
html_options: HtmlAttributes.new(html_options),
|
181
|
-
arguments: [method, options, html_options],
|
182
|
-
}
|
183
|
-
|
184
|
-
render_partial("date_select", locals, fallback: -> { super })
|
185
|
-
end
|
186
|
-
|
187
|
-
def hidden_field(method, **options)
|
188
|
-
@emitted_hidden_id = true if method == :id
|
189
|
-
|
190
|
-
locals = {
|
191
|
-
method: method,
|
192
|
-
options: HtmlAttributes.new(options),
|
193
|
-
arguments: [method],
|
194
|
-
}
|
195
|
-
|
196
|
-
render_partial("hidden_field", locals, fallback: -> { super })
|
197
|
-
end
|
198
|
-
|
199
|
-
def file_field(method, **options)
|
200
|
-
self.multipart = true
|
201
|
-
|
202
|
-
locals = {
|
203
|
-
method: method,
|
204
|
-
options: HtmlAttributes.new(options),
|
205
|
-
arguments: [method],
|
206
|
-
}
|
207
|
-
|
208
|
-
render_partial("file_field", locals, fallback: -> { super })
|
209
|
-
end
|
210
|
-
|
211
|
-
def submit(value = nil, **options)
|
212
|
-
value, options = nil, value if value.is_a?(Hash)
|
213
|
-
value ||= submit_default_value
|
214
|
-
|
215
|
-
locals = {
|
216
|
-
value: value,
|
217
|
-
options: HtmlAttributes.new(options),
|
218
|
-
arguments: [value],
|
219
|
-
}
|
220
|
-
|
221
|
-
render_partial("submit", locals, fallback: -> { super })
|
222
|
-
end
|
223
|
-
|
224
|
-
def button(value = nil, **options)
|
225
|
-
value, options = nil, value if value.is_a?(Hash)
|
226
|
-
value ||= submit_default_value
|
227
|
-
|
228
|
-
locals = {
|
229
|
-
value: value,
|
230
|
-
options: HtmlAttributes.new(options),
|
231
|
-
arguments: [value],
|
232
|
-
}
|
233
|
-
|
234
|
-
render_partial("button", locals, fallback: -> { super })
|
235
|
-
end
|
236
|
-
|
237
|
-
DYNAMICALLY_DECLARED = (
|
238
|
-
field_helpers +
|
239
|
-
[:rich_text_area] -
|
240
|
-
[:label, :check_box, :radio_button, :fields_for, :fields, :hidden_field, :file_field]
|
241
|
-
)
|
242
|
-
|
243
|
-
DYNAMICALLY_DECLARED.each do |selector|
|
244
|
-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
245
|
-
def #{selector}(method, **options)
|
246
|
-
render_partial(
|
247
|
-
"#{selector}",
|
248
|
-
{
|
249
|
-
method: method,
|
250
|
-
options: HtmlAttributes.new(options),
|
251
|
-
arguments: [method],
|
252
|
-
},
|
253
|
-
fallback: -> { super },
|
254
|
-
)
|
255
|
-
end
|
256
|
-
RUBY
|
257
|
-
end
|
258
|
-
|
259
|
-
private
|
260
|
-
|
261
|
-
def render_partial(field, locals, fallback:, &block)
|
262
|
-
options = locals.fetch(:options, {})
|
263
|
-
partial_override = options.delete(:partial)
|
264
|
-
options_as_locals = objectify_options(options)
|
265
|
-
locals = DeprecatedHash.new(
|
266
|
-
options_as_locals.merge(locals, form: self),
|
267
|
-
deprecated_keys: options_as_locals.keys + [:arguments],
|
268
|
-
)
|
269
|
-
|
270
|
-
partial = if partial_override.present?
|
271
|
-
ActiveSupport::Deprecation.new("0.2.0", "ViewPartialFormBuilder").warn(<<~WARNING)
|
272
|
-
Providing a `partial:` option for a form field is deprecated.
|
273
|
-
WARNING
|
274
|
-
|
275
|
-
find_partial(partial_override, locals, prefixes: [])
|
276
|
-
else
|
277
|
-
find_partial(field, locals, prefixes: prefixes_after(field))
|
278
|
-
end
|
279
|
-
|
280
|
-
if partial.nil? || about_to_recurse_infinitely?(partial)
|
281
|
-
fallback.call
|
282
|
-
else
|
283
|
-
partial.render(@template, locals, &block)
|
284
|
-
end
|
285
|
-
end
|
286
|
-
|
287
|
-
def find_partial(template_name, locals, prefixes:)
|
288
|
-
template_is_partial = true
|
289
|
-
|
290
|
-
@template.lookup_context.find_all(
|
291
|
-
template_name,
|
292
|
-
prefixes,
|
293
|
-
template_is_partial,
|
294
|
-
locals.keys,
|
295
|
-
).first.tap do |partial|
|
296
|
-
root_directory = ViewPartialFormBuilder.view_partial_directory
|
297
|
-
|
298
|
-
if partial&.virtual_path == "#{root_directory}/_#{template_name}"
|
299
|
-
ActiveSupport::Deprecation.new("0.2.0", "ViewPartialFormBuilder").warn(<<~WARNING.strip)
|
300
|
-
Declare root-level partials in app/views/application/#{root_directory}/, not app/views/#{root_directory}/.
|
301
|
-
WARNING
|
302
|
-
end
|
303
|
-
end
|
304
|
-
end
|
305
|
-
|
306
|
-
def prefixes_after(template_name)
|
307
|
-
prefixes = @lookup_override.prefixes
|
308
|
-
current_prefix = current_virtual_path.delete_suffix("/_#{template_name}")
|
309
|
-
|
310
|
-
if prefixes.include?(current_prefix)
|
311
|
-
prefixes.from(prefixes.index(current_prefix).to_i + 1)
|
312
|
-
else
|
313
|
-
prefixes
|
314
|
-
end
|
315
|
-
end
|
316
|
-
|
317
|
-
def about_to_recurse_infinitely?(partial)
|
318
|
-
partial.virtual_path == current_virtual_path
|
319
|
-
end
|
320
|
-
|
321
|
-
def current_virtual_path
|
322
|
-
if (current_template = @template.instance_values["current_template"])
|
323
|
-
current_template.virtual_path.to_s
|
324
|
-
else
|
325
|
-
@template.instance_values["virtual_path"].to_s
|
326
|
-
end
|
9
|
+
@default = dup
|
10
|
+
@template = TemplateProxy.new(builder: self, template: @template)
|
327
11
|
end
|
328
12
|
end
|
329
13
|
|
330
|
-
|
331
|
-
def initialize(hash, deprecated_keys: [])
|
332
|
-
super()
|
333
|
-
merge!(hash)
|
334
|
-
@deprecated_keys = deprecated_keys
|
335
|
-
end
|
336
|
-
|
337
|
-
def [](key)
|
338
|
-
if @deprecated_keys.include?(key)
|
339
|
-
ActiveSupport::Deprecation.new("0.2.0", "ViewPartialFormBuilder").warn <<~WARNING
|
340
|
-
Accessing `#{key}` from partials is deprecated.
|
341
|
-
WARNING
|
342
|
-
end
|
343
|
-
|
344
|
-
super
|
345
|
-
end
|
346
|
-
end
|
14
|
+
ActiveSupport.run_load_hooks(:view_partial_form_builder, FormBuilder)
|
347
15
|
end
|
@@ -11,28 +11,24 @@ module ViewPartialFormBuilder
|
|
11
11
|
|
12
12
|
prefixes = [
|
13
13
|
"#{object_name}/#{view_partial_directory}",
|
14
|
-
object_name,
|
15
|
-
view_partial_directory,
|
16
14
|
"#{root_prefix}/#{view_partial_directory}",
|
17
|
-
root_prefix,
|
18
15
|
]
|
19
16
|
|
20
17
|
overridden_prefixes.reverse_each do |prefix|
|
21
|
-
namespace, *files = prefix.split("/")
|
22
|
-
|
23
|
-
prefixes.unshift(prefix)
|
24
|
-
|
25
|
-
if namespace.present?
|
26
|
-
prefixes.unshift("#{namespace}/#{view_partial_directory}")
|
27
|
-
end
|
28
|
-
|
29
18
|
prefixes.unshift("#{prefix}/#{view_partial_directory}")
|
30
19
|
end
|
31
20
|
|
32
|
-
|
33
21
|
prefixes.uniq
|
34
22
|
end
|
35
23
|
|
24
|
+
def prefixes_after(current_prefix)
|
25
|
+
if prefixes.include?(current_prefix)
|
26
|
+
prefixes.from(prefixes.index(current_prefix).to_i + 1)
|
27
|
+
else
|
28
|
+
prefixes
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
36
32
|
private
|
37
33
|
|
38
34
|
attr_reader :object_name, :view_partial_directory
|
@@ -0,0 +1,120 @@
|
|
1
|
+
module ViewPartialFormBuilder
|
2
|
+
class TemplateProxy
|
3
|
+
delegate :field_id, :field_name, to: :@template
|
4
|
+
|
5
|
+
def initialize(builder:, template:)
|
6
|
+
@template = template
|
7
|
+
@builder = builder
|
8
|
+
end
|
9
|
+
|
10
|
+
def button_tag(value, options, &block)
|
11
|
+
render(:button, arguments: [value, options], block: block) do
|
12
|
+
@template.button_tag(value, options, &block)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def submit_tag(value, options)
|
17
|
+
render(:submit, arguments: [value, options]) do
|
18
|
+
@template.submit_tag(value, options)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def label(object_name, method, content_or_options = nil, options = nil, &block)
|
23
|
+
if content_or_options.is_a?(Hash)
|
24
|
+
options.merge! content_or_options
|
25
|
+
content = nil
|
26
|
+
else
|
27
|
+
content = content_or_options
|
28
|
+
end
|
29
|
+
|
30
|
+
render(:label, arguments: [method, content, options], block: block) do
|
31
|
+
@template.label(object_name, method, content, options, &block)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def method_missing(name, *arguments, &block)
|
38
|
+
if @builder.respond_to?(name)
|
39
|
+
arguments_after_object_name = arguments.from(1)
|
40
|
+
|
41
|
+
render(name, arguments: arguments_after_object_name, block: block) do
|
42
|
+
@template.public_send(name, *arguments, &block)
|
43
|
+
end
|
44
|
+
elsif @template.respond_to?(name)
|
45
|
+
@template.public_send(name, *arguments, &block)
|
46
|
+
else
|
47
|
+
super
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def respond_to_missing?(name, include_private = false)
|
52
|
+
@builder.respond_to_missing?(name) || @template.respond_to_missing?(name)
|
53
|
+
end
|
54
|
+
|
55
|
+
def render(partial_name, arguments:, block: nil, &fallback)
|
56
|
+
locals = extract_partial_locals(partial_name, *arguments).merge(
|
57
|
+
form: @builder,
|
58
|
+
block: block
|
59
|
+
)
|
60
|
+
|
61
|
+
partial = find_partial(partial_name, locals)
|
62
|
+
|
63
|
+
if partial.nil? || about_to_recurse_infinitely?(partial)
|
64
|
+
fallback.call
|
65
|
+
else
|
66
|
+
partial.render(@template, locals, &block)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def extract_partial_locals(form_method, *arguments)
|
71
|
+
parameters = @builder.method(form_method).parameters
|
72
|
+
|
73
|
+
parameters.each_with_index.each_with_object({}) { |(tuple, index), locals|
|
74
|
+
_type, parameter = tuple
|
75
|
+
|
76
|
+
locals[parameter] = arguments[index]
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
80
|
+
def find_partial(template_name, locals)
|
81
|
+
current_prefix = current_virtual_path.delete_suffix("/_#{template_name}")
|
82
|
+
template_is_partial = true
|
83
|
+
|
84
|
+
partials = template_names_for(template_name).lazy.map do |name|
|
85
|
+
@template.lookup_context.find_all(
|
86
|
+
name,
|
87
|
+
lookup_override.prefixes_after(current_prefix),
|
88
|
+
template_is_partial,
|
89
|
+
locals.keys
|
90
|
+
).first
|
91
|
+
end
|
92
|
+
|
93
|
+
partials.find(&:present?)
|
94
|
+
end
|
95
|
+
|
96
|
+
def template_names_for(template_name)
|
97
|
+
[template_name, *@builder.aliased_field_helpers[template_name]].compact
|
98
|
+
end
|
99
|
+
|
100
|
+
def about_to_recurse_infinitely?(partial)
|
101
|
+
partial.virtual_path == current_virtual_path
|
102
|
+
end
|
103
|
+
|
104
|
+
def current_virtual_path
|
105
|
+
if (current_template = @template.instance_values["current_template"])
|
106
|
+
current_template.virtual_path.to_s
|
107
|
+
else
|
108
|
+
@template.instance_values["virtual_path"].to_s
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def lookup_override
|
113
|
+
LookupOverride.new(
|
114
|
+
prefixes: @template.lookup_context.prefixes,
|
115
|
+
object_name: @builder.object.try(:model_name) || @builder.object_name,
|
116
|
+
view_partial_directory: ViewPartialFormBuilder.view_partial_directory
|
117
|
+
)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: view_partial_form_builder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sean Doyle
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-09-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actionview
|
@@ -16,36 +16,22 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: '0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: railties
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 4.0.0
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: 4.0.0
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: minitest-around
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
44
30
|
requirements:
|
45
31
|
- - ">="
|
46
32
|
- !ruby/object:Gem::Version
|
47
33
|
version: '0'
|
48
|
-
type: :
|
34
|
+
type: :runtime
|
49
35
|
prerelease: false
|
50
36
|
version_requirements: !ruby/object:Gem::Requirement
|
51
37
|
requirements:
|
@@ -53,33 +39,19 @@ dependencies:
|
|
53
39
|
- !ruby/object:Gem::Version
|
54
40
|
version: '0'
|
55
41
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
42
|
+
name: zeitwerk
|
57
43
|
requirement: !ruby/object:Gem::Requirement
|
58
44
|
requirements:
|
59
45
|
- - ">="
|
60
46
|
- !ruby/object:Gem::Version
|
61
|
-
version: 4.0
|
62
|
-
type: :
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: 4.0.0
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: activerecord-nulldb-adapter
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - ">="
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
76
|
-
type: :development
|
47
|
+
version: 2.4.0
|
48
|
+
type: :runtime
|
77
49
|
prerelease: false
|
78
50
|
version_requirements: !ruby/object:Gem::Requirement
|
79
51
|
requirements:
|
80
52
|
- - ">="
|
81
53
|
- !ruby/object:Gem::Version
|
82
|
-
version:
|
54
|
+
version: 2.4.0
|
83
55
|
description: A Rails form builder where all designer-facing configuration is via templates.
|
84
56
|
email:
|
85
57
|
- sean.p.doyle24@gmail.com
|
@@ -93,14 +65,14 @@ files:
|
|
93
65
|
- lib/view_partial_form_builder.rb
|
94
66
|
- lib/view_partial_form_builder/engine.rb
|
95
67
|
- lib/view_partial_form_builder/form_builder.rb
|
96
|
-
- lib/view_partial_form_builder/html_attributes.rb
|
97
68
|
- lib/view_partial_form_builder/lookup_override.rb
|
69
|
+
- lib/view_partial_form_builder/template_proxy.rb
|
98
70
|
- lib/view_partial_form_builder/version.rb
|
99
71
|
homepage: https://github.com/seanpdoyle/view_partial_form_builder
|
100
72
|
licenses:
|
101
73
|
- MIT
|
102
74
|
metadata: {}
|
103
|
-
post_install_message:
|
75
|
+
post_install_message:
|
104
76
|
rdoc_options: []
|
105
77
|
require_paths:
|
106
78
|
- lib
|
@@ -115,8 +87,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
115
87
|
- !ruby/object:Gem::Version
|
116
88
|
version: '0'
|
117
89
|
requirements: []
|
118
|
-
rubygems_version: 3.
|
119
|
-
signing_key:
|
90
|
+
rubygems_version: 3.5.16
|
91
|
+
signing_key:
|
120
92
|
specification_version: 4
|
121
93
|
summary: Construct <form> element fields by combining ActionView::Helpers::FormBuilder
|
122
94
|
with Rails View Partials
|
@@ -1,55 +0,0 @@
|
|
1
|
-
module ViewPartialFormBuilder
|
2
|
-
class HtmlAttributes
|
3
|
-
deprecate merge_token_lists: <<~'WARNING', deprecator: ActiveSupport::Deprecation.new("0.2.0", "ViewPartialFormBuilder")
|
4
|
-
|
5
|
-
As an alternative, merge arguments through String interpolation:
|
6
|
-
|
7
|
-
<%= form.label(method, class: "label #{options.delete(:class)}", **options) %>
|
8
|
-
|
9
|
-
WARNING
|
10
|
-
|
11
|
-
def initialize(**attributes)
|
12
|
-
@attributes = attributes
|
13
|
-
end
|
14
|
-
|
15
|
-
def merge_token_lists(**token_list_attributes)
|
16
|
-
merge(
|
17
|
-
token_list_attributes.reduce({}) do |merged, (key, value)|
|
18
|
-
token_list = Array(attributes.delete(key)).unshift(value)
|
19
|
-
|
20
|
-
merged.merge(key => token_list.flatten.uniq)
|
21
|
-
end
|
22
|
-
)
|
23
|
-
end
|
24
|
-
|
25
|
-
def to_h
|
26
|
-
attributes.to_h
|
27
|
-
end
|
28
|
-
|
29
|
-
def to_hash
|
30
|
-
attributes.to_hash
|
31
|
-
end
|
32
|
-
|
33
|
-
def method_missing(method_name, *arguments, &block)
|
34
|
-
if attributes.respond_to?(method_name)
|
35
|
-
return_value = attributes.public_send(method_name, *arguments, &block)
|
36
|
-
|
37
|
-
if return_value.kind_of?(Hash)
|
38
|
-
HtmlAttributes.new(return_value)
|
39
|
-
else
|
40
|
-
return_value
|
41
|
-
end
|
42
|
-
else
|
43
|
-
super
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def respond_to_missing?(method_name, include_private = false)
|
48
|
-
attributes.respond_to?(method_name) || super
|
49
|
-
end
|
50
|
-
|
51
|
-
private
|
52
|
-
|
53
|
-
attr_reader :attributes
|
54
|
-
end
|
55
|
-
end
|