form_forms 0.1.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.
- data/.gitignore +18 -0
- data/.travis.yml +12 -0
- data/Gemfile +6 -0
- data/LICENSE +22 -0
- data/README.md +239 -0
- data/Rakefile +11 -0
- data/form_forms.gemspec +23 -0
- data/gemfiles/Gemfile.rails3_0 +10 -0
- data/gemfiles/Gemfile.rails3_1 +10 -0
- data/gemfiles/Gemfile.rails3_2 +10 -0
- data/lib/form_forms.rb +10 -0
- data/lib/form_forms/elements.rb +5 -0
- data/lib/form_forms/elements/base_element.rb +189 -0
- data/lib/form_forms/elements/block.rb +28 -0
- data/lib/form_forms/elements/field.rb +32 -0
- data/lib/form_forms/elements/fields.rb +29 -0
- data/lib/form_forms/elements/fieldset.rb +23 -0
- data/lib/form_forms/form_registry.rb +25 -0
- data/lib/form_forms/forms.rb +2 -0
- data/lib/form_forms/forms/base_form.rb +40 -0
- data/lib/form_forms/forms/form.rb +15 -0
- data/lib/form_forms/version.rb +3 -0
- data/test/form_forms/elements/block_test.rb +32 -0
- data/test/form_forms/elements/field_test.rb +98 -0
- data/test/form_forms/elements/fields_test.rb +57 -0
- data/test/form_forms/elements/fieldset_test.rb +53 -0
- data/test/form_forms/form_registry_test.rb +16 -0
- data/test/form_forms/forms/form_test.rb +15 -0
- data/test/support/misc_helpers.rb +15 -0
- data/test/support/mock_controller.rb +22 -0
- data/test/support/models.rb +134 -0
- data/test/test_helper.rb +51 -0
- metadata +131 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
module FormForms
|
2
|
+
module Elements
|
3
|
+
class Block < BaseElement
|
4
|
+
allowed_sub_element :field
|
5
|
+
allowed_sub_element :block
|
6
|
+
allowed_sub_element :fieldset
|
7
|
+
allowed_sub_element :fields
|
8
|
+
allowed_sub_element :table_fields
|
9
|
+
|
10
|
+
def initialize(element, args = {})
|
11
|
+
@element = element.to_sym
|
12
|
+
self.args args
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
property :args
|
17
|
+
|
18
|
+
# Generate a fielset with a legend
|
19
|
+
def render(builder, view)
|
20
|
+
args = eval_property(:args, builder, view)
|
21
|
+
|
22
|
+
view.content_tag(@element, args) do
|
23
|
+
super
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module FormForms
|
2
|
+
module Elements
|
3
|
+
# This represents a single form field. Typically this is the most
|
4
|
+
# low-level part of a form. You can either return a form element with the
|
5
|
+
# help of the passed form builder or just return arbitrary html. The block
|
6
|
+
# is executed in the scope of the view where the form is rendered. You can
|
7
|
+
# use any helpers defined there.
|
8
|
+
#
|
9
|
+
# Note that you might need to mark your values as +html_safe+ to avoid
|
10
|
+
# superfluous escaping in the view.
|
11
|
+
#
|
12
|
+
# Example:
|
13
|
+
#
|
14
|
+
# my_form = Form.new() do |form|
|
15
|
+
# form.field(:subject) {|f| f.input :subject}
|
16
|
+
# form.field(:link) do |f|
|
17
|
+
# content_tag :p do
|
18
|
+
# content_tag(:a, :href => hint_path){ "This is a hint" }
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
class Field
|
23
|
+
def initialize(&generator)
|
24
|
+
@generator = generator
|
25
|
+
end
|
26
|
+
|
27
|
+
def render(builder, view)
|
28
|
+
view.instance_exec(builder, &@generator)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module FormForms
|
2
|
+
module Elements
|
3
|
+
class Fields < BaseElement
|
4
|
+
allowed_sub_element :field
|
5
|
+
allowed_sub_element :block
|
6
|
+
allowed_sub_element :fieldset
|
7
|
+
allowed_sub_element :fields
|
8
|
+
allowed_sub_element :table_fields
|
9
|
+
|
10
|
+
def initialize(association=nil, form_args={})
|
11
|
+
self.association association
|
12
|
+
self.args form_args
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
property :association
|
17
|
+
property :args
|
18
|
+
|
19
|
+
def render(builder, view)
|
20
|
+
association = eval_property(:association, builder, view)
|
21
|
+
form_args = eval_property(:args, builder, view)
|
22
|
+
|
23
|
+
builder.association(association, form_args) do |sub|
|
24
|
+
render_elements(sub, view)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module FormForms
|
2
|
+
module Elements
|
3
|
+
class Fieldset < Block
|
4
|
+
def initialize(fieldset_args={}, &generator)
|
5
|
+
self.legend nil
|
6
|
+
super(:fieldset, fieldset_args, &generator)
|
7
|
+
end
|
8
|
+
|
9
|
+
property :legend
|
10
|
+
|
11
|
+
# Generate a fielset with a legend
|
12
|
+
def render(builder, view)
|
13
|
+
args = eval_property(:args, builder, view)
|
14
|
+
legend = eval_property(:legend, builder, view)
|
15
|
+
|
16
|
+
view.content_tag(:fieldset, args) do
|
17
|
+
view.concat view.content_tag(:legend, legend) unless legend.nil?
|
18
|
+
view.concat render_elements(builder, view)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module FormForms
|
2
|
+
class FormRegistry
|
3
|
+
class << self
|
4
|
+
def [](name)
|
5
|
+
forms[name.to_sym]
|
6
|
+
end
|
7
|
+
|
8
|
+
def []=(name, form)
|
9
|
+
forms[name.to_sym] = form
|
10
|
+
end
|
11
|
+
|
12
|
+
def delete(name)
|
13
|
+
forms.delete(name.to_sym)
|
14
|
+
end
|
15
|
+
|
16
|
+
def keys
|
17
|
+
forms.keys
|
18
|
+
end
|
19
|
+
protected
|
20
|
+
def forms
|
21
|
+
@forms ||= {}
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module FormForms
|
2
|
+
module Forms
|
3
|
+
# The generic top-level form for building a simple_form..
|
4
|
+
#
|
5
|
+
# This class (and all its children) is only usable as a top-level form
|
6
|
+
# as it generates its own form builder object which is passed to its
|
7
|
+
# sub-elements on rendering
|
8
|
+
class BaseForm < FormForms::Elements::BaseElement
|
9
|
+
# +form_args+ are passed to the initializer of the form builder.
|
10
|
+
# They can be used to override its defaults.
|
11
|
+
def initialize(form_args = {})
|
12
|
+
@form_args = form_args
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
# Set the form_args. These are static as we don't have a form yet
|
17
|
+
def args(form_args=nil)
|
18
|
+
if form_args
|
19
|
+
@form_args = form_args
|
20
|
+
else
|
21
|
+
@form_args
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Render the form.
|
26
|
+
# Notice that forms receive an ActiveModel object as its first
|
27
|
+
# parameter, unlike elements which receive the form builder which is
|
28
|
+
# created by a form.
|
29
|
+
def render(model, view)
|
30
|
+
view.simple_form_for(model, self.args) do |builder|
|
31
|
+
render_elements(builder, view)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.register(name, form_args={}, &generator)
|
36
|
+
::FormForms::FormRegistry[name] = self.new(form_args, &generator)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module FormForms
|
2
|
+
module Forms
|
3
|
+
# The generic form for building a simple_form..
|
4
|
+
#
|
5
|
+
# This class is only usable as a top-level form as it generates its own
|
6
|
+
# form builder object
|
7
|
+
class Form < BaseForm
|
8
|
+
allowed_sub_element :field
|
9
|
+
allowed_sub_element :block
|
10
|
+
allowed_sub_element :fieldset
|
11
|
+
allowed_sub_element :fields
|
12
|
+
allowed_sub_element :table_fields
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class FieldsetTest < ActionView::TestCase
|
4
|
+
test "create a block" do
|
5
|
+
with_form_for(@user) do |form|
|
6
|
+
form.block(:red_box, :div, :class => "red_box") do |block|
|
7
|
+
block.field(:credit_card) {|f| f.input :credit_card}
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
assert_select 'form > div.red_box input.string#user_credit_card'
|
12
|
+
end
|
13
|
+
|
14
|
+
test "allow nesting of blocks" do
|
15
|
+
with_form_for(@user) do |form|
|
16
|
+
form.block(:main, :div, :id => 'main') do |outer|
|
17
|
+
outer.fieldset(:payment, :id => "payment") do |inner|
|
18
|
+
inner.legend "These are some fields"
|
19
|
+
inner.field(:credit_card) {|f| f.input :credit_card}
|
20
|
+
end
|
21
|
+
|
22
|
+
outer.field(:name) {|f| f.input :name}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
assert_no_select 'fieldset#main > legend'
|
27
|
+
assert_select 'form > div#main > div > input.string#user_name'
|
28
|
+
|
29
|
+
assert_select 'form > div#main > fieldset#payment > legend', "These are some fields"
|
30
|
+
assert_select 'form > div#main > fieldset#payment input.string#user_credit_card'
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class FieldTest < ActionView::TestCase
|
4
|
+
test "render a simple_form field" do
|
5
|
+
with_form_for(@user) do |form|
|
6
|
+
form.field(:name) {|f| f.input :name}
|
7
|
+
form.field(:description) {|f| f.input :description}
|
8
|
+
end
|
9
|
+
|
10
|
+
assert_select 'input.string#user_name'
|
11
|
+
assert_select 'textarea.text#user_description'
|
12
|
+
end
|
13
|
+
|
14
|
+
test "render a custom field" do
|
15
|
+
with_form_for(@user) do |form|
|
16
|
+
form.field(:something) {|f| '<span id="foo">Something</span>'.html_safe}
|
17
|
+
end
|
18
|
+
|
19
|
+
assert_select 'span#foo', "Something"
|
20
|
+
end
|
21
|
+
|
22
|
+
test "escape unsafe output" do
|
23
|
+
with_form_for(@user) do |form|
|
24
|
+
form.field(:something) {|f| '<span id="foo">Something</span>'}
|
25
|
+
end
|
26
|
+
|
27
|
+
assert_no_select 'span#foo'
|
28
|
+
assert_select 'form', /<span id="foo">Something<\/span>/
|
29
|
+
end
|
30
|
+
|
31
|
+
test "allow the usage of view helpers" do
|
32
|
+
with_form_for(@user) do |form|
|
33
|
+
form.field(:something) {|f| content_tag(:span){"Something"}}
|
34
|
+
end
|
35
|
+
|
36
|
+
assert_select 'span', "Something"
|
37
|
+
end
|
38
|
+
|
39
|
+
test "allow appending elements" do
|
40
|
+
with_form_for(@user) do |form|
|
41
|
+
form.field(:name) {|f| f.input :name}
|
42
|
+
form.field(:description) {|f| f.input :description}
|
43
|
+
|
44
|
+
form.field_after(:name, :credit_card) {|f| f.input :credit_card}
|
45
|
+
form.field_last(:active) {|f| f.input :active}
|
46
|
+
end
|
47
|
+
|
48
|
+
# the first div in a form contains some hidden fields
|
49
|
+
assert_select 'form > div:nth-of-type(2) > input.string#user_name'
|
50
|
+
assert_select 'form > div:nth-of-type(3) > input.string#user_credit_card'
|
51
|
+
assert_select 'form > div:nth-of-type(4) > textarea.text#user_description'
|
52
|
+
assert_select 'form > div:nth-of-type(5) > input.boolean#user_active'
|
53
|
+
end
|
54
|
+
|
55
|
+
test "allow prepending elements" do
|
56
|
+
with_form_for(@user) do |form|
|
57
|
+
form.field(:name) {|f| f.input :name}
|
58
|
+
form.field(:description) {|f| f.input :description}
|
59
|
+
|
60
|
+
form.field_first(:active) {|f| f.input :active}
|
61
|
+
form.field_before(:description, :credit_card) {|f| f.input :credit_card}
|
62
|
+
end
|
63
|
+
|
64
|
+
# the first div in a form contains some hidden fields
|
65
|
+
assert_select 'form > div:nth-of-type(2) > input.boolean#user_active'
|
66
|
+
assert_select 'form > div:nth-of-type(3) > input.string#user_name'
|
67
|
+
assert_select 'form > div:nth-of-type(4) > input.string#user_credit_card'
|
68
|
+
assert_select 'form > div:nth-of-type(5) > textarea.text#user_description'
|
69
|
+
end
|
70
|
+
|
71
|
+
test "check existence of elements when inserting" do
|
72
|
+
assert_raise ArgumentError do
|
73
|
+
with_form_for(@user) do |form|
|
74
|
+
form.field(:name) {|f| f.input :name}
|
75
|
+
form.field_before(:description, :credit_card) {|f| f.input :credit_card}
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
assert_raise ArgumentError do
|
80
|
+
with_form_for(@user) do |form|
|
81
|
+
form.field(:name) {|f| f.input :name}
|
82
|
+
form.field_after(:description, :credit_card) {|f| f.input :credit_card}
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
test "delete field" do
|
88
|
+
with_form_for(@user) do |form|
|
89
|
+
form.field(:name) {|f| f.input :name}
|
90
|
+
form.field(:description) {|f| f.input :description}
|
91
|
+
|
92
|
+
form.delete(:description)
|
93
|
+
end
|
94
|
+
|
95
|
+
assert_select 'input.string#user_name'
|
96
|
+
assert_no_select 'textarea.text#user_description'
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require File.expand_path('../../../test_helper', __FILE__)
|
2
|
+
|
3
|
+
class FieldsTest < ActionView::TestCase
|
4
|
+
test "render a sub-form" do
|
5
|
+
with_form_for(@user) do |form|
|
6
|
+
form.field(:name) {|f| f.input :name}
|
7
|
+
|
8
|
+
form.fields(:tags, :tags, :collection => Tag.all) do |tags|
|
9
|
+
tags.field(:name) {|f| f.input :name}
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
assert_select 'input.string#user_name'
|
14
|
+
|
15
|
+
assert_select 'input.string#user_tags_attributes_0_name'
|
16
|
+
assert_select 'input[type=hidden]#user_tags_attributes_0_id'
|
17
|
+
|
18
|
+
assert_select 'input.string#user_tags_attributes_2_name'
|
19
|
+
assert_select 'input[type=hidden]#user_tags_attributes_2_id'
|
20
|
+
end
|
21
|
+
|
22
|
+
test "pass the collection tag as a proc" do
|
23
|
+
with_form_for(@user) do |form|
|
24
|
+
form.field(:name) {|f| f.input :name}
|
25
|
+
|
26
|
+
args = lambda{|f| {:collection => Tag.all} }
|
27
|
+
form.fields(:tags, :tags, args) do |tags|
|
28
|
+
tags.field(:name) {|f| f.input :name}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
assert_select 'input.string#user_name'
|
33
|
+
|
34
|
+
assert_select 'input.string#user_tags_attributes_0_name'
|
35
|
+
assert_select 'input[type=hidden]#user_tags_attributes_0_id'
|
36
|
+
|
37
|
+
assert_select 'input.string#user_tags_attributes_2_name'
|
38
|
+
assert_select 'input[type=hidden]#user_tags_attributes_2_id'
|
39
|
+
end
|
40
|
+
|
41
|
+
test "append field to sub-form" do
|
42
|
+
with_form_for(@user) do |form|
|
43
|
+
form.field(:name) {|f| f.input :name}
|
44
|
+
|
45
|
+
form.fields(:tags, :tags, :collection => Tag.all) do |tags|
|
46
|
+
tags.field(:name) {|f| f.input :name}
|
47
|
+
end
|
48
|
+
|
49
|
+
form.fields(:tags).field(:id) {|f| f.input :id}
|
50
|
+
end
|
51
|
+
|
52
|
+
assert_select 'input.string#user_name'
|
53
|
+
|
54
|
+
assert_select 'input.string#user_tags_attributes_0_name'
|
55
|
+
assert_select 'input.string#user_tags_attributes_0_id'
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class FieldsetTest < ActionView::TestCase
|
4
|
+
test "create a fieldset" do
|
5
|
+
with_form_for(@user) do |form|
|
6
|
+
form.fieldset(:payment, :id => "payment") do |fieldset|
|
7
|
+
fieldset.legend "These are some fields"
|
8
|
+
fieldset.field(:credit_card) {|f| f.input :credit_card}
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
assert_select 'form > fieldset#payment legend', "These are some fields"
|
13
|
+
assert_select 'form > fieldset#payment input.string#user_credit_card'
|
14
|
+
end
|
15
|
+
|
16
|
+
test "allow nesting of fieldsets" do
|
17
|
+
with_form_for(@user) do |form|
|
18
|
+
form.fieldset(:main, :id => 'main') do |outer|
|
19
|
+
outer.fieldset(:payment, :id => "payment") do |inner|
|
20
|
+
inner.legend "These are some fields"
|
21
|
+
inner.field(:credit_card) {|f| f.input :credit_card}
|
22
|
+
end
|
23
|
+
|
24
|
+
outer.field(:name) {|f| f.input :name}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
assert_no_select 'fieldset#main > legend'
|
29
|
+
assert_select 'form > fieldset#main > div > input.string#user_name'
|
30
|
+
|
31
|
+
assert_select 'form > fieldset#main > fieldset#payment > legend', "These are some fields"
|
32
|
+
assert_select 'form > fieldset#main > fieldset#payment input.string#user_credit_card'
|
33
|
+
end
|
34
|
+
|
35
|
+
test "dynamically set args and legend" do
|
36
|
+
with_form_for(@user) do |form|
|
37
|
+
form.fieldset(:main) do |fieldset|
|
38
|
+
# static syntax
|
39
|
+
fieldset.args :id => 'main'
|
40
|
+
fieldset.legend "These are some fields"
|
41
|
+
end
|
42
|
+
|
43
|
+
form.fieldset(:block) do |fieldset|
|
44
|
+
# dynamic block syntax
|
45
|
+
fieldset.args{|f| {:id => 'block'} }
|
46
|
+
fieldset.legend{|f| "This is a #{f.object.class.name.underscore}"}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
assert_select 'form > fieldset#main > legend', 'These are some fields'
|
51
|
+
assert_select 'form > fieldset#block > legend', 'This is a user'
|
52
|
+
end
|
53
|
+
end
|