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.
@@ -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,2 @@
1
+ require 'form_forms/forms/base_form'
2
+ require 'form_forms/forms/form'
@@ -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,3 @@
1
+ module Formforms
2
+ VERSION = "0.1.0"
3
+ 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', /&lt;span id=&quot;foo&quot;&gt;Something&lt;\/span&gt;/
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