template_form 0.4.3
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 +7 -0
- data/.gitignore +9 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +178 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/template_form.rb +24 -0
- data/lib/template_form/base_input.rb +85 -0
- data/lib/template_form/checkbox_input.rb +7 -0
- data/lib/template_form/date_input.rb +5 -0
- data/lib/template_form/errors.rb +7 -0
- data/lib/template_form/file_input.rb +7 -0
- data/lib/template_form/form_builder.rb +59 -0
- data/lib/template_form/form_helper.rb +31 -0
- data/lib/template_form/grouped_select_input.rb +76 -0
- data/lib/template_form/select_input.rb +87 -0
- data/lib/template_form/templates/bulma/select_input.html.erb +31 -0
- data/lib/template_form/templates/bulma/text_input.html.erb +23 -0
- data/lib/template_form/templates/bulma/textarea_input.html.erb +24 -0
- data/lib/template_form/templates/bulma_horizontal/checkbox_input.html.erb +29 -0
- data/lib/template_form/templates/bulma_horizontal/date_input.html.erb +35 -0
- data/lib/template_form/templates/bulma_horizontal/grouped_select_input.html.erb +39 -0
- data/lib/template_form/templates/bulma_horizontal/select_input.html.erb +37 -0
- data/lib/template_form/templates/bulma_horizontal/text_input.html.erb +29 -0
- data/lib/template_form/templates/bulma_horizontal/textarea_input.html.erb +29 -0
- data/lib/template_form/text_input.rb +7 -0
- data/lib/template_form/textarea_input.rb +7 -0
- data/lib/template_form/version.rb +3 -0
- data/template_form.gemspec +30 -0
- metadata +144 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: db33072169a06cf9c413c7344703d7f0ecec5a370e837e3d3fe3b75f72af3db4
|
|
4
|
+
data.tar.gz: 8eab8b70bae6bf35de91d7de20400381fb10512a05e0687fca726b784e3ecbf4
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 4b49e409abf1686d12586aa8aa2b4f709a6feb36a888f6cd00f26d7577702a26aad076dc606ff7e4363f4e9ed3fb8fe550eb379ea72137c4ba729c5d7f794322
|
|
7
|
+
data.tar.gz: 438cb38f9938e9787efbc5d47da96d1aad7c554268f659c819752122cdad6ae85f2b356fcea62999b36a8e86dd6c670c872822396833bdbafdccb8b98f10fb74
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2017 Andy Stewart
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# Template Form - a Rails form builder where you bring your own HTML
|
|
2
|
+
|
|
3
|
+
Template Form makes defining the HTML your form inputs generate as simple as possible: you just write it out. Most other form builders, e.g. Simple Form, add a layer of indirection and make you use their own DSL.
|
|
4
|
+
|
|
5
|
+
Templates are grouped so you can for example define both vertical and horizontal forms, or Bootstrap and Tailwind forms, in the same Rails app.
|
|
6
|
+
|
|
7
|
+
Right now Template Form includes templates for [Bulma](https://bulma.io/documentation/form/) but in time it will include templates for all the popular CSS frameworks.
|
|
8
|
+
|
|
9
|
+
Template Form works with all template engines supported by [Tilt](https://github.com/rtomayko/tilt).
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Installation
|
|
13
|
+
|
|
14
|
+
Add it to your Gemfile:
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
gem 'template_form'
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
And then `bundle install`.
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### Example
|
|
24
|
+
|
|
25
|
+
Let's say you use Bulma. Here's what your view might look like:
|
|
26
|
+
|
|
27
|
+
```erb
|
|
28
|
+
<%= template_form_with model: Post.new do |f| %>
|
|
29
|
+
<%= f.input :title %>
|
|
30
|
+
<%= f.input :body %>
|
|
31
|
+
<% end %>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
This will be rendered as:
|
|
35
|
+
|
|
36
|
+
```html
|
|
37
|
+
<form action="/users" method="post" data-remote="true">
|
|
38
|
+
|
|
39
|
+
<div class="field">
|
|
40
|
+
<label class="label" for="post_title">Title</label>
|
|
41
|
+
<div class="control">
|
|
42
|
+
<input class="input" type="text" name="post[title]" id="post_title">
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<div class="field">
|
|
47
|
+
<label class="label" for="post_body">Title</label>
|
|
48
|
+
<div class="control">
|
|
49
|
+
<textarea class="textarea" name="post[body]" id="post_body"></textarea>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
</form>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Now let's say you want a horizontal form instead. The only change you need to make is to specify the form type:
|
|
57
|
+
|
|
58
|
+
```diff
|
|
59
|
+
- <%= template_form_with model: Post.new do |f| %>
|
|
60
|
+
+ <%= template_form_with model: Post.new, form_type: :bulma_horizontal do |f| %>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
And then you will get this HTML instead:
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
```html
|
|
67
|
+
<form action="/users" method="post" data-remote="true">
|
|
68
|
+
|
|
69
|
+
<div class="field is-horizontal">
|
|
70
|
+
<div class="field-label is-normal">
|
|
71
|
+
<label class="label" for="post_title">Title</label>
|
|
72
|
+
</div>
|
|
73
|
+
<div class="field-body">
|
|
74
|
+
<div class="field">
|
|
75
|
+
<div class="control">
|
|
76
|
+
<input class="input" type="text" name="post[title]" id="post_title">
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
|
|
82
|
+
<div class="field is-horizontal">
|
|
83
|
+
<div class="field-label is-normal">
|
|
84
|
+
<label class="label" for="post_body">Body</label>
|
|
85
|
+
</div>
|
|
86
|
+
<div class="field-body">
|
|
87
|
+
<div class="field">
|
|
88
|
+
<div class="control">
|
|
89
|
+
<textarea class="textarea" name="post[body]" id="post_body"></textarea>
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
</form>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
### Defining your templates
|
|
100
|
+
|
|
101
|
+
Your templates live at `/app/forms/<FORM TYPE>/` where `<FORM TYPE>` is a name that makes sense to you, and the value that you use with the `:form_type` option to `#template_form_with`.
|
|
102
|
+
|
|
103
|
+
They should have these names:
|
|
104
|
+
|
|
105
|
+
- `text_input.html.erb`
|
|
106
|
+
- `textarea_input.html.erb`
|
|
107
|
+
- `select_input.html.erb`
|
|
108
|
+
- `grouped_select_input.html.erb`
|
|
109
|
+
- `checkbox_input.html.erb`
|
|
110
|
+
- `date_input.html.erb`
|
|
111
|
+
|
|
112
|
+
Use whatever extension goes with your template engine.
|
|
113
|
+
|
|
114
|
+
Inside each template you can use the normal Rails form helpers. Here's the template for Bulma's [text input](https://github.com/airblade/template_form/blob/master/lib/template_form/templates/bulma/text_input.html.erb):
|
|
115
|
+
|
|
116
|
+
```erb
|
|
117
|
+
<div class="field <%= options.delete(:field_class) %>">
|
|
118
|
+
|
|
119
|
+
<% if has_label %>
|
|
120
|
+
<%- label_options[:class] << ' label' %>
|
|
121
|
+
<%- label_options[:class] << ' required' if options.delete(:required) %>
|
|
122
|
+
<%= label attribute_name, label_text, label_options %>
|
|
123
|
+
<% end %>
|
|
124
|
+
|
|
125
|
+
<div class="control <%= options.delete(:control_class) %>">
|
|
126
|
+
<%- options[:class] << ' input' %>
|
|
127
|
+
<%- options[:class] << ' is-danger' if errors[attribute_name].present? %>
|
|
128
|
+
<%= text_field attribute_name, options %>
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
<%- if hint_text.present? %>
|
|
132
|
+
<p class="help"><%= hint_text %></p>
|
|
133
|
+
<%- end %>
|
|
134
|
+
|
|
135
|
+
<%- if errors[attribute_name].present? %>
|
|
136
|
+
<p class="help is-danger"><%= errors.full_messages_for(attribute_name).to_sentence %></p>
|
|
137
|
+
<%- end %>
|
|
138
|
+
|
|
139
|
+
</div>
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
The methods available inside the template are defined in the corresponding [models](https://github.com/airblade/template_form/blob/master/lib/template_form/)' `#render` method. For example, here is the [text input](https://github.com/airblade/template_form/blob/c80b445a5a50e836635fd1bdf010d32f49902604/lib/template_form/base_input.rb#L28-L42)'s:
|
|
143
|
+
|
|
144
|
+
```ruby
|
|
145
|
+
def render
|
|
146
|
+
template.render(
|
|
147
|
+
builder,
|
|
148
|
+
attribute_name: attribute_name,
|
|
149
|
+
|
|
150
|
+
has_label: has_label,
|
|
151
|
+
label_text: label_text,
|
|
152
|
+
label_options: label_options,
|
|
153
|
+
|
|
154
|
+
hint_text: hint_text,
|
|
155
|
+
|
|
156
|
+
options: options,
|
|
157
|
+
errors: errors
|
|
158
|
+
).html_safe
|
|
159
|
+
end
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Attribute types and form inputs
|
|
163
|
+
|
|
164
|
+
Template Form looks up the type for the attribute, falling back to `:string` if it can't find one. Then it uses the corresponding form input.
|
|
165
|
+
|
|
166
|
+
Attribute type | Form input
|
|
167
|
+
--|--
|
|
168
|
+
`:string` | `TextInput`
|
|
169
|
+
`:text` | `TextareaInput`
|
|
170
|
+
`:date` | `DateInput`
|
|
171
|
+
`:boolean` | `CheckboxInput`
|
|
172
|
+
`:file` | `FileInput`
|
|
173
|
+
`:select` | `SelectInput`
|
|
174
|
+
`:grouped_select` | `GroupedSelectInput`
|
|
175
|
+
|
|
176
|
+
You can specify a type to use with `:as`, e.g. `<%= f.input :reason, as: :text %>`.
|
|
177
|
+
|
|
178
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "template_form"
|
|
5
|
+
|
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
|
8
|
+
|
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
|
10
|
+
# require "pry"
|
|
11
|
+
# Pry.start
|
|
12
|
+
|
|
13
|
+
require "irb"
|
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require 'template_form/version'
|
|
2
|
+
require 'template_form/form_helper'
|
|
3
|
+
|
|
4
|
+
module TemplateForm
|
|
5
|
+
|
|
6
|
+
def self.field_error_proc
|
|
7
|
+
noop_field_error_proc
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def self.form_type
|
|
11
|
+
@form_type || :bulma
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.form_type=(val)
|
|
15
|
+
@form_type = val
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def self.noop_field_error_proc
|
|
21
|
+
Proc.new { |html_tag, instance| html_tag }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
require 'pathname'
|
|
2
|
+
|
|
3
|
+
module TemplateForm
|
|
4
|
+
class BaseInput
|
|
5
|
+
|
|
6
|
+
def initialize(builder, attribute_name, options)
|
|
7
|
+
@builder = builder
|
|
8
|
+
@attribute_name = attribute_name
|
|
9
|
+
|
|
10
|
+
@form_type = options.delete(:form_type) || builder.form_type
|
|
11
|
+
|
|
12
|
+
# Use the `:label` option to override the default label text.
|
|
13
|
+
# Use `label: false` to indicate no label should be shown (check `has_label` in the template).
|
|
14
|
+
@has_label = !(options.has_key?(:label) && options[:label] == false)
|
|
15
|
+
@label_text = options.delete(:label) || ''
|
|
16
|
+
@label_options = Hash.new { |h,k| h[k] = '' }.update(options.delete(:label_options) || {})
|
|
17
|
+
|
|
18
|
+
@hint_text = options.delete(:hint) || ''
|
|
19
|
+
|
|
20
|
+
data_attributes = (options.delete(:data) || {}).transform_keys { |k| "data-#{k}" }
|
|
21
|
+
|
|
22
|
+
@options = options
|
|
23
|
+
@options.merge! data_attributes
|
|
24
|
+
@options[:class] ||= ''
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def render
|
|
29
|
+
template.render(
|
|
30
|
+
builder,
|
|
31
|
+
attribute_name: attribute_name,
|
|
32
|
+
|
|
33
|
+
has_label: has_label,
|
|
34
|
+
label_text: label_text,
|
|
35
|
+
label_options: label_options,
|
|
36
|
+
|
|
37
|
+
hint_text: hint_text,
|
|
38
|
+
|
|
39
|
+
options: options,
|
|
40
|
+
errors: errors
|
|
41
|
+
).html_safe
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
attr_reader *%i[
|
|
48
|
+
form_type
|
|
49
|
+
builder
|
|
50
|
+
attribute_name
|
|
51
|
+
|
|
52
|
+
has_label
|
|
53
|
+
label_text
|
|
54
|
+
label_options
|
|
55
|
+
|
|
56
|
+
hint_text
|
|
57
|
+
|
|
58
|
+
options
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
def errors
|
|
62
|
+
builder.object ? builder.object.errors : {}
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def template
|
|
66
|
+
Tilt.new template_file
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def template_file
|
|
70
|
+
name = self.class.name.demodulize.underscore # TemplateForm::TextInput -> text_input
|
|
71
|
+
f = paths(name).map { |p| Pathname.glob(p).first }.detect &:itself
|
|
72
|
+
f or raise TemplateForm::MissingTemplateError, "No template found at: #{paths(name).join ', '}"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def paths(name)
|
|
76
|
+
locations.map { |p| p / form_type.to_s / "#{name}.html.*" }
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def locations
|
|
80
|
+
[ Pathname.new("#{Rails.root}/app/forms"),
|
|
81
|
+
Pathname.new("#{__dir__}/templates") ]
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
require 'action_pack'
|
|
2
|
+
require 'action_view'
|
|
3
|
+
require 'template_form/errors'
|
|
4
|
+
require 'template_form/base_input'
|
|
5
|
+
require 'template_form/checkbox_input'
|
|
6
|
+
require 'template_form/grouped_select_input'
|
|
7
|
+
require 'template_form/select_input'
|
|
8
|
+
require 'template_form/text_input'
|
|
9
|
+
require 'template_form/textarea_input'
|
|
10
|
+
require 'template_form/date_input'
|
|
11
|
+
require 'template_form/file_input'
|
|
12
|
+
|
|
13
|
+
module TemplateForm
|
|
14
|
+
class FormBuilder < ::ActionView::Helpers::FormBuilder
|
|
15
|
+
|
|
16
|
+
attr_reader :form_type
|
|
17
|
+
|
|
18
|
+
def initialize(*)
|
|
19
|
+
super
|
|
20
|
+
# Do not remove `:form_type` from `options`. It has to stay so
|
|
21
|
+
# when `fields_for()` instantiates a new form builder for each
|
|
22
|
+
# associated record, the second and subsequent ones have the
|
|
23
|
+
# correct form type.
|
|
24
|
+
@form_type = options[:form_type] || TemplateForm.form_type
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def input(attribute_name, options = {})
|
|
28
|
+
attribute_type = options.delete(:as) ||
|
|
29
|
+
(@object.respond_to?(:type_for_attribute) && @object.type_for_attribute(attribute_name).type) ||
|
|
30
|
+
:string
|
|
31
|
+
|
|
32
|
+
options[:type] ||= 'password' if attribute_name.match(/password/)
|
|
33
|
+
|
|
34
|
+
input_for(attribute_type).new(self, attribute_name, options).render
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def hidden(attribute_name, options = {})
|
|
39
|
+
hidden_field attribute_name, options
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def input_for(attribute_type)
|
|
46
|
+
case attribute_type
|
|
47
|
+
when :string then TextInput
|
|
48
|
+
when :text then TextareaInput
|
|
49
|
+
when :date then DateInput
|
|
50
|
+
when :boolean then CheckboxInput
|
|
51
|
+
when :file then FileInput
|
|
52
|
+
when :select then SelectInput
|
|
53
|
+
when :grouped_select then GroupedSelectInput
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require 'template_form/form_builder'
|
|
2
|
+
|
|
3
|
+
module TemplateForm
|
|
4
|
+
module FormHelper
|
|
5
|
+
|
|
6
|
+
def template_form_with(model: nil, scope: nil, url: nil, format: nil, **options, &block)
|
|
7
|
+
options[:builder] = TemplateForm::FormBuilder
|
|
8
|
+
|
|
9
|
+
with_template_form_field_error_proc do
|
|
10
|
+
form_with model: model, scope: scope, url: url, format: format, **options, &block
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def with_template_form_field_error_proc
|
|
17
|
+
default_field_error_proc = ActionView::Base.field_error_proc
|
|
18
|
+
begin
|
|
19
|
+
ActionView::Base.field_error_proc = TemplateForm.field_error_proc
|
|
20
|
+
yield
|
|
21
|
+
ensure
|
|
22
|
+
ActionView::Base.field_error_proc = default_field_error_proc
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
ActiveSupport.on_load(:action_view) do
|
|
30
|
+
include TemplateForm::FormHelper
|
|
31
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
require 'tilt'
|
|
2
|
+
|
|
3
|
+
module TemplateForm
|
|
4
|
+
class GroupedSelectInput < BaseInput
|
|
5
|
+
|
|
6
|
+
OPTION_KEYS = %i[ include_blank prompt index disabled selected ]
|
|
7
|
+
|
|
8
|
+
def initialize(builder, attribute_name, options)
|
|
9
|
+
@builder = builder
|
|
10
|
+
@attribute_name = attribute_name
|
|
11
|
+
|
|
12
|
+
@form_type = options.delete(:form_type) || builder.form_type
|
|
13
|
+
|
|
14
|
+
@collection = options.delete(:collection).to_a
|
|
15
|
+
|
|
16
|
+
# Use the `:label` option to override the default label text.
|
|
17
|
+
# Use `label: false` to indicate no label should be shown (check `has_label` in the template).
|
|
18
|
+
@has_label = !(options.has_key?(:label) && options[:label] == false)
|
|
19
|
+
@label_text = options.delete(:label) || ''
|
|
20
|
+
@label_options = Hash.new { |h,k| h[k] = '' }.update(options.delete(:label_options) || {})
|
|
21
|
+
|
|
22
|
+
@hint_text = options.delete(:hint) || ''
|
|
23
|
+
|
|
24
|
+
@group_method = options.delete(:group_method) || :last
|
|
25
|
+
@group_label_method = options.delete(:group_label_method) || :first
|
|
26
|
+
@option_key_method = options.delete :option_key_method
|
|
27
|
+
@option_value_method = options.delete :option_value_method
|
|
28
|
+
|
|
29
|
+
data_attributes = (options.delete(:data) || {}).transform_keys { |k| "data-#{k}" }
|
|
30
|
+
|
|
31
|
+
@options = options.select { |k,_| OPTION_KEYS.include? k }
|
|
32
|
+
|
|
33
|
+
@html_options = options.reject { |k,_| OPTION_KEYS.include? k }
|
|
34
|
+
@html_options.merge! data_attributes
|
|
35
|
+
@html_options[:class] ||= ''
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def render
|
|
39
|
+
template.render(
|
|
40
|
+
builder,
|
|
41
|
+
attribute_name: attribute_name,
|
|
42
|
+
collection: collection,
|
|
43
|
+
|
|
44
|
+
has_label: has_label,
|
|
45
|
+
label_text: label_text,
|
|
46
|
+
label_options: label_options,
|
|
47
|
+
|
|
48
|
+
hint_text: hint_text,
|
|
49
|
+
|
|
50
|
+
options: options,
|
|
51
|
+
html_options: html_options,
|
|
52
|
+
|
|
53
|
+
errors: errors,
|
|
54
|
+
|
|
55
|
+
group_method: group_method,
|
|
56
|
+
group_label_method: group_label_method,
|
|
57
|
+
option_key_method: option_key_method,
|
|
58
|
+
option_value_method: option_value_method
|
|
59
|
+
).html_safe
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
attr_reader *%i[
|
|
65
|
+
collection
|
|
66
|
+
|
|
67
|
+
html_options
|
|
68
|
+
|
|
69
|
+
group_method
|
|
70
|
+
group_label_method
|
|
71
|
+
option_key_method
|
|
72
|
+
option_value_method
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
require 'tilt'
|
|
2
|
+
|
|
3
|
+
module TemplateForm
|
|
4
|
+
class SelectInput < BaseInput
|
|
5
|
+
|
|
6
|
+
OPTION_KEYS = %i[ include_blank prompt index disabled selected ]
|
|
7
|
+
|
|
8
|
+
def initialize(builder, attribute_name, options)
|
|
9
|
+
@builder = builder
|
|
10
|
+
@attribute_name = attribute_name
|
|
11
|
+
|
|
12
|
+
@form_type = options.delete(:form_type) || builder.form_type
|
|
13
|
+
|
|
14
|
+
@collection = options.delete(:collection).to_a
|
|
15
|
+
|
|
16
|
+
# Use the `:label` option to override the default label text.
|
|
17
|
+
# Use `label: false` to indicate no label should be shown (check `has_label` in the template).
|
|
18
|
+
@has_label = !(options.has_key?(:label) && options[:label] == false)
|
|
19
|
+
@label_text = options.delete(:label) || ''
|
|
20
|
+
@label_options = Hash.new { |h,k| h[k] = '' }.update(options.delete(:label_options) || {})
|
|
21
|
+
|
|
22
|
+
@hint_text = options.delete(:hint) || ''
|
|
23
|
+
|
|
24
|
+
@value_method = options.delete(:value_method) || default_value_method
|
|
25
|
+
@text_method = options.delete(:text_method) || default_text_method
|
|
26
|
+
|
|
27
|
+
data_attributes = (options.delete(:data) || {}).transform_keys { |k| "data-#{k}" }
|
|
28
|
+
|
|
29
|
+
@options = options.select { |k,_| OPTION_KEYS.include? k }
|
|
30
|
+
|
|
31
|
+
@html_options = options.reject { |k,_| OPTION_KEYS.include? k }
|
|
32
|
+
@html_options.merge! data_attributes
|
|
33
|
+
@html_options[:class] ||= ''
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def render
|
|
37
|
+
template.render(
|
|
38
|
+
builder,
|
|
39
|
+
attribute_name: attribute_name,
|
|
40
|
+
collection: collection,
|
|
41
|
+
|
|
42
|
+
has_label: has_label,
|
|
43
|
+
label_text: label_text,
|
|
44
|
+
label_options: label_options,
|
|
45
|
+
|
|
46
|
+
hint_text: hint_text,
|
|
47
|
+
|
|
48
|
+
options: options,
|
|
49
|
+
html_options: html_options,
|
|
50
|
+
|
|
51
|
+
errors: errors,
|
|
52
|
+
|
|
53
|
+
value_method: value_method,
|
|
54
|
+
text_method: text_method
|
|
55
|
+
).html_safe
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
|
|
60
|
+
attr_reader *%i[
|
|
61
|
+
collection
|
|
62
|
+
|
|
63
|
+
html_options
|
|
64
|
+
|
|
65
|
+
value_method
|
|
66
|
+
text_method
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
def default_text_method
|
|
70
|
+
case collection.first
|
|
71
|
+
when String then :to_s
|
|
72
|
+
when Array then :first
|
|
73
|
+
when nil then :to_s # it won't be called because collection is empty
|
|
74
|
+
else raise NotImplementedError, "first collection element is a #{collection.first.class.name}"
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def default_value_method
|
|
79
|
+
case collection.first
|
|
80
|
+
when String then :to_s
|
|
81
|
+
when Array then :last
|
|
82
|
+
when nil then :to_s # it won't be called because collection is empty
|
|
83
|
+
else raise NotImplementedError, "first collection element is a #{collection.first.class.name}"
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<div class="field <%= options.delete(:field_class) %>">
|
|
2
|
+
|
|
3
|
+
<% if has_label %>
|
|
4
|
+
<%- label_options[:class] << ' label' %>
|
|
5
|
+
<%- label_options[:class] << ' required' if html_options.delete(:required) %>
|
|
6
|
+
<%= label attribute_name, label_text, label_options %>
|
|
7
|
+
<% end %>
|
|
8
|
+
|
|
9
|
+
<div class="control <%= options.delete(:control_class) %>">
|
|
10
|
+
<%- html_options[:class] << ' select' %>
|
|
11
|
+
<%- html_options[:class] << ' is-danger' if errors[attribute_name].present? %>
|
|
12
|
+
<div class="<%= html_options[:class] %>">
|
|
13
|
+
<%= collection_select(
|
|
14
|
+
attribute_name,
|
|
15
|
+
collection,
|
|
16
|
+
value_method,
|
|
17
|
+
text_method,
|
|
18
|
+
options,
|
|
19
|
+
html_options) %>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<%- if hint_text.present? %>
|
|
24
|
+
<p class="help"><%= hint_text %></p>
|
|
25
|
+
<%- end %>
|
|
26
|
+
|
|
27
|
+
<%- if errors[attribute_name].present? %>
|
|
28
|
+
<p class="help is-danger"><%= errors.full_messages_for(attribute_name).to_sentence %></p>
|
|
29
|
+
<%- end %>
|
|
30
|
+
|
|
31
|
+
</div>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<div class="field <%= options.delete(:field_class) %>">
|
|
2
|
+
|
|
3
|
+
<% if has_label %>
|
|
4
|
+
<%- label_options[:class] << ' label' %>
|
|
5
|
+
<%- label_options[:class] << ' required' if options.delete(:required) %>
|
|
6
|
+
<%= label attribute_name, label_text, label_options %>
|
|
7
|
+
<% end %>
|
|
8
|
+
|
|
9
|
+
<div class="control <%= options.delete(:control_class) %>">
|
|
10
|
+
<%- options[:class] << ' input' %>
|
|
11
|
+
<%- options[:class] << ' is-danger' if errors[attribute_name].present? %>
|
|
12
|
+
<%= text_field attribute_name, options %>
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
<%- if hint_text.present? %>
|
|
16
|
+
<p class="help"><%= hint_text %></p>
|
|
17
|
+
<%- end %>
|
|
18
|
+
|
|
19
|
+
<%- if errors[attribute_name].present? %>
|
|
20
|
+
<p class="help is-danger"><%= errors.full_messages_for(attribute_name).to_sentence %></p>
|
|
21
|
+
<%- end %>
|
|
22
|
+
|
|
23
|
+
</div>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<div class="field <%= options.delete(:field_class) %>">
|
|
2
|
+
|
|
3
|
+
<% if has_label %>
|
|
4
|
+
<%- label_options[:class] << ' label' %>
|
|
5
|
+
<%- label_options[:class] << ' required' if options.delete(:required) %>
|
|
6
|
+
<%= label attribute_name, label_text, label_options %>
|
|
7
|
+
<% end %>
|
|
8
|
+
|
|
9
|
+
<div class="control">
|
|
10
|
+
<%- options[:class] << ' textarea' %>
|
|
11
|
+
<%- options[:class] << ' is-danger' if errors[attribute_name].present? %>
|
|
12
|
+
<%= text_area attribute_name, options %>
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
<%- if hint_text.present? %>
|
|
16
|
+
<p class="help"><%= hint_text %></p>
|
|
17
|
+
<%- end %>
|
|
18
|
+
|
|
19
|
+
<%- if errors[attribute_name].present? %>
|
|
20
|
+
<p class="help is-danger"><%= errors.full_messages_for(attribute_name).to_sentence %></p>
|
|
21
|
+
<%- end %>
|
|
22
|
+
|
|
23
|
+
</div>
|
|
24
|
+
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<div class="field is-horizontal <%= options.delete(:field_class) %>">
|
|
2
|
+
|
|
3
|
+
<% if has_label %>
|
|
4
|
+
<div class="field-label">
|
|
5
|
+
<%- label_options[:class] << ' label' %>
|
|
6
|
+
<%- label_options[:class] << ' required' if options.delete(:required) %>
|
|
7
|
+
<%= label attribute_name, label_text, label_options %>
|
|
8
|
+
</div>
|
|
9
|
+
<% end %>
|
|
10
|
+
|
|
11
|
+
<div class="field-body">
|
|
12
|
+
<div class="field">
|
|
13
|
+
<div class="control <%= options.delete(:control_class) %>">
|
|
14
|
+
<label class="checkbox">
|
|
15
|
+
<%= check_box attribute_name, options %>
|
|
16
|
+
</label>
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<%- if hint_text.present? %>
|
|
20
|
+
<p class="help"><%= hint_text %></p>
|
|
21
|
+
<%- end %>
|
|
22
|
+
|
|
23
|
+
<%- if errors[attribute_name].present? %>
|
|
24
|
+
<p class="help is-danger"><%= errors.full_messages_for(attribute_name).to_sentence %></p>
|
|
25
|
+
<%- end %>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
</div>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<div class="field is-horizontal <%= options.delete(:field_class) %>">
|
|
2
|
+
|
|
3
|
+
<% if has_label %>
|
|
4
|
+
<div class="field-label <%= options.delete(:field_label_class) || 'is-normal' %>">
|
|
5
|
+
<%- label_options[:class] << ' label' %>
|
|
6
|
+
<%- label_options[:class] << ' required' if options.delete(:required) %>
|
|
7
|
+
<%= label attribute_name, label_text, label_options %>
|
|
8
|
+
</div>
|
|
9
|
+
<% end %>
|
|
10
|
+
|
|
11
|
+
<div class="field-body">
|
|
12
|
+
<%#
|
|
13
|
+
Use an extra nested field so the help text appears where expected
|
|
14
|
+
rather than as another addon.
|
|
15
|
+
https://github.com/jgthms/bulma/issues/640#issuecomment-415231212
|
|
16
|
+
%>
|
|
17
|
+
<div class="field">
|
|
18
|
+
<div class="control <%= options.delete(:control_class) %>">
|
|
19
|
+
<%- options[:class] << ' input' %>
|
|
20
|
+
<%- options[:class] << ' is-danger' if errors[attribute_name].present? %>
|
|
21
|
+
<%= text_field attribute_name, options %>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<%- if hint_text.present? %>
|
|
25
|
+
<p class="help"><%= hint_text %></p>
|
|
26
|
+
<%- end %>
|
|
27
|
+
|
|
28
|
+
<%- if errors[attribute_name].present? %>
|
|
29
|
+
<p class="help is-danger"><%= errors.full_messages_for(attribute_name).to_sentence %></p>
|
|
30
|
+
<%- end %>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
</div>
|
|
35
|
+
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<div class="field is-horizontal <%= options.delete(:field_class) %>">
|
|
2
|
+
|
|
3
|
+
<% if has_label %>
|
|
4
|
+
<div class="field-label <%= options.delete(:field_label_class) || 'is-normal' %>">
|
|
5
|
+
<%- label_options[:class] << ' label' %>
|
|
6
|
+
<%- label_options[:class] << ' required' if html_options.delete(:required) %>
|
|
7
|
+
<%= label attribute_name, label_text, label_options %>
|
|
8
|
+
</div>
|
|
9
|
+
<% end %>
|
|
10
|
+
|
|
11
|
+
<div class="field-body">
|
|
12
|
+
<div class="field <%= options.delete(:field_body_field_class) %>">
|
|
13
|
+
<div class="control <%= options.delete(:control_class) %>">
|
|
14
|
+
<%- html_options[:class] << ' select' %>
|
|
15
|
+
<%- html_options[:class] << ' is-danger' if errors[attribute_name].present? %>
|
|
16
|
+
<div class="<%= html_options[:class] %>">
|
|
17
|
+
<%= grouped_collection_select(
|
|
18
|
+
attribute_name,
|
|
19
|
+
collection,
|
|
20
|
+
group_method,
|
|
21
|
+
group_label_method,
|
|
22
|
+
option_key_method,
|
|
23
|
+
option_value_method,
|
|
24
|
+
options,
|
|
25
|
+
html_options) %>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<%- if hint_text.present? %>
|
|
30
|
+
<p class="help"><%= hint_text %></p>
|
|
31
|
+
<%- end %>
|
|
32
|
+
|
|
33
|
+
<%- if errors[attribute_name].present? %>
|
|
34
|
+
<p class="help is-danger"><%= errors.full_messages_for(attribute_name).to_sentence %></p>
|
|
35
|
+
<%- end %>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
</div>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<div class="field is-horizontal <%= options.delete(:field_class) %>">
|
|
2
|
+
|
|
3
|
+
<% if has_label %>
|
|
4
|
+
<div class="field-label <%= options.delete(:field_label_class) || 'is-normal' %>">
|
|
5
|
+
<%- label_options[:class] << ' label' %>
|
|
6
|
+
<%- label_options[:class] << ' required' if html_options.delete(:required) %>
|
|
7
|
+
<%= label attribute_name, label_text, label_options %>
|
|
8
|
+
</div>
|
|
9
|
+
<% end %>
|
|
10
|
+
|
|
11
|
+
<div class="field-body">
|
|
12
|
+
<div class="field <%= options.delete(:field_body_field_class) %>">
|
|
13
|
+
<div class="control <%= options.delete(:control_class) %>">
|
|
14
|
+
<%- html_options[:class] << ' select' %>
|
|
15
|
+
<%- html_options[:class] << ' is-danger' if errors[attribute_name].present? %>
|
|
16
|
+
<div class="<%= html_options[:class] %>">
|
|
17
|
+
<%= collection_select(
|
|
18
|
+
attribute_name,
|
|
19
|
+
collection,
|
|
20
|
+
value_method,
|
|
21
|
+
text_method,
|
|
22
|
+
options,
|
|
23
|
+
html_options) %>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<%- if hint_text.present? %>
|
|
28
|
+
<p class="help"><%= hint_text %></p>
|
|
29
|
+
<%- end %>
|
|
30
|
+
|
|
31
|
+
<%- if errors[attribute_name].present? %>
|
|
32
|
+
<p class="help is-danger"><%= errors.full_messages_for(attribute_name).to_sentence %></p>
|
|
33
|
+
<%- end %>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
</div>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<div class="field is-horizontal <%= options.delete(:field_class) %>">
|
|
2
|
+
|
|
3
|
+
<% if has_label %>
|
|
4
|
+
<div class="field-label <%= options.delete(:field_label_class) || 'is-normal' %>">
|
|
5
|
+
<%- label_options[:class] << ' label' %>
|
|
6
|
+
<%- label_options[:class] << ' required' if options.delete(:required) %>
|
|
7
|
+
<%= label attribute_name, label_text, label_options %>
|
|
8
|
+
</div>
|
|
9
|
+
<% end %>
|
|
10
|
+
|
|
11
|
+
<div class="field-body">
|
|
12
|
+
<div class="field">
|
|
13
|
+
<div class="control <%= options.delete(:control_class) %>">
|
|
14
|
+
<%- options[:class] << ' input' %>
|
|
15
|
+
<%- options[:class] << ' is-danger' if errors[attribute_name].present? %>
|
|
16
|
+
<%= text_field attribute_name, options %>
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<%- if hint_text.present? %>
|
|
20
|
+
<p class="help"><%= hint_text %></p>
|
|
21
|
+
<%- end %>
|
|
22
|
+
|
|
23
|
+
<%- if errors[attribute_name].present? %>
|
|
24
|
+
<p class="help is-danger"><%= errors.full_messages_for(attribute_name).to_sentence %></p>
|
|
25
|
+
<%- end %>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
</div>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<div class="field is-horizontal <%= options.delete(:field_class) %>">
|
|
2
|
+
|
|
3
|
+
<% if has_label %>
|
|
4
|
+
<div class="field-label <%= options.delete(:field_label_class) || 'is-normal' %>">
|
|
5
|
+
<%- label_options[:class] << ' label' %>
|
|
6
|
+
<%- label_options[:class] << ' required' if options.delete(:required) %>
|
|
7
|
+
<%= label attribute_name, label_text, label_options %>
|
|
8
|
+
</div>
|
|
9
|
+
<% end %>
|
|
10
|
+
|
|
11
|
+
<div class="field-body">
|
|
12
|
+
<div class="field">
|
|
13
|
+
<div class="control <%= options.delete(:control_class) %>">
|
|
14
|
+
<%- options[:class] << ' textarea' %>
|
|
15
|
+
<%- options[:class] << ' is-danger' if errors[attribute_name].present? %>
|
|
16
|
+
<%= text_area attribute_name, options %>
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<%- if hint_text.present? %>
|
|
20
|
+
<p class="help"><%= hint_text %></p>
|
|
21
|
+
<%- end %>
|
|
22
|
+
|
|
23
|
+
<%- if errors[attribute_name].present? %>
|
|
24
|
+
<p class="help is-danger"><%= errors.full_messages_for(attribute_name).to_sentence %></p>
|
|
25
|
+
<%- end %>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
</div>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'template_form/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "template_form"
|
|
8
|
+
spec.version = TemplateForm::VERSION
|
|
9
|
+
spec.authors = ['Andy Stewart']
|
|
10
|
+
spec.email = ['boss@airbladesoftware.com']
|
|
11
|
+
|
|
12
|
+
spec.summary = 'A template-based form builder for Rails.'
|
|
13
|
+
spec.description = 'A template-based form builder for Rails.'
|
|
14
|
+
spec.homepage = 'https://github.com/airblade/template_form'
|
|
15
|
+
spec.license = 'MIT'
|
|
16
|
+
|
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
|
18
|
+
f.match(%r{^(test|spec|features)/})
|
|
19
|
+
end
|
|
20
|
+
spec.bindir = "exe"
|
|
21
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
22
|
+
spec.require_paths = ["lib"]
|
|
23
|
+
|
|
24
|
+
spec.add_dependency 'actionpack', '> 5.0'
|
|
25
|
+
spec.add_dependency 'tilt', '~> 2.0'
|
|
26
|
+
|
|
27
|
+
spec.add_development_dependency "bundler"
|
|
28
|
+
spec.add_development_dependency "rake"
|
|
29
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
|
30
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: template_form
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.4.3
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Andy Stewart
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: exe
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2020-09-15 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: actionpack
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '5.0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '5.0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: tilt
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '2.0'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '2.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: bundler
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: rake
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '0'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: minitest
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '5.0'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '5.0'
|
|
83
|
+
description: A template-based form builder for Rails.
|
|
84
|
+
email:
|
|
85
|
+
- boss@airbladesoftware.com
|
|
86
|
+
executables: []
|
|
87
|
+
extensions: []
|
|
88
|
+
extra_rdoc_files: []
|
|
89
|
+
files:
|
|
90
|
+
- ".gitignore"
|
|
91
|
+
- ".travis.yml"
|
|
92
|
+
- Gemfile
|
|
93
|
+
- LICENSE.txt
|
|
94
|
+
- README.md
|
|
95
|
+
- Rakefile
|
|
96
|
+
- bin/console
|
|
97
|
+
- bin/setup
|
|
98
|
+
- lib/template_form.rb
|
|
99
|
+
- lib/template_form/base_input.rb
|
|
100
|
+
- lib/template_form/checkbox_input.rb
|
|
101
|
+
- lib/template_form/date_input.rb
|
|
102
|
+
- lib/template_form/errors.rb
|
|
103
|
+
- lib/template_form/file_input.rb
|
|
104
|
+
- lib/template_form/form_builder.rb
|
|
105
|
+
- lib/template_form/form_helper.rb
|
|
106
|
+
- lib/template_form/grouped_select_input.rb
|
|
107
|
+
- lib/template_form/select_input.rb
|
|
108
|
+
- lib/template_form/templates/bulma/select_input.html.erb
|
|
109
|
+
- lib/template_form/templates/bulma/text_input.html.erb
|
|
110
|
+
- lib/template_form/templates/bulma/textarea_input.html.erb
|
|
111
|
+
- lib/template_form/templates/bulma_horizontal/checkbox_input.html.erb
|
|
112
|
+
- lib/template_form/templates/bulma_horizontal/date_input.html.erb
|
|
113
|
+
- lib/template_form/templates/bulma_horizontal/grouped_select_input.html.erb
|
|
114
|
+
- lib/template_form/templates/bulma_horizontal/select_input.html.erb
|
|
115
|
+
- lib/template_form/templates/bulma_horizontal/text_input.html.erb
|
|
116
|
+
- lib/template_form/templates/bulma_horizontal/textarea_input.html.erb
|
|
117
|
+
- lib/template_form/text_input.rb
|
|
118
|
+
- lib/template_form/textarea_input.rb
|
|
119
|
+
- lib/template_form/version.rb
|
|
120
|
+
- template_form.gemspec
|
|
121
|
+
homepage: https://github.com/airblade/template_form
|
|
122
|
+
licenses:
|
|
123
|
+
- MIT
|
|
124
|
+
metadata: {}
|
|
125
|
+
post_install_message:
|
|
126
|
+
rdoc_options: []
|
|
127
|
+
require_paths:
|
|
128
|
+
- lib
|
|
129
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
130
|
+
requirements:
|
|
131
|
+
- - ">="
|
|
132
|
+
- !ruby/object:Gem::Version
|
|
133
|
+
version: '0'
|
|
134
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
135
|
+
requirements:
|
|
136
|
+
- - ">="
|
|
137
|
+
- !ruby/object:Gem::Version
|
|
138
|
+
version: '0'
|
|
139
|
+
requirements: []
|
|
140
|
+
rubygems_version: 3.1.2
|
|
141
|
+
signing_key:
|
|
142
|
+
specification_version: 4
|
|
143
|
+
summary: A template-based form builder for Rails.
|
|
144
|
+
test_files: []
|