form_forms 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Holger Just
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,239 @@
|
|
1
|
+
# FormForms [![Build Status](https://secure.travis-ci.org/meineerde/form_forms.png)](http://travis-ci.org/meineerde/form_forms) [![Dependency Status](https://gemnasium.com/meineerde/form_forms.png?travis)](https://gemnasium.com/meineerde/form_forms)
|
2
|
+
|
3
|
+
Configurable forms for Rails 3, based on the excellent
|
4
|
+
[simple_form](https://github.com/plataformatec/simple_form) gem.
|
5
|
+
|
6
|
+
The goal of this gem is to provide forms (as in views) which are flexible
|
7
|
+
enough to fulfill their intended usage but be able to be configured by
|
8
|
+
plugins. Thus plugins can easily add, delete and edit form fields without
|
9
|
+
having to override whole views (which are almost impossible to patch) or
|
10
|
+
having to monkey patch existing code which is hard to maintain.
|
11
|
+
|
12
|
+
form_forms is originally intended to be used with the simple_form gem and uses
|
13
|
+
its API in several of its shipped element definitions. While it is possible
|
14
|
+
to not use those and provide custom definitions, we require simple_form as
|
15
|
+
a dependency right now.
|
16
|
+
|
17
|
+
# Installation
|
18
|
+
|
19
|
+
Add this line to your application's Gemfile:
|
20
|
+
|
21
|
+
gem 'form_forms'
|
22
|
+
|
23
|
+
and then run `bundle install`.
|
24
|
+
|
25
|
+
Or install it yourself using
|
26
|
+
|
27
|
+
gem install form_forms
|
28
|
+
|
29
|
+
# Usage
|
30
|
+
|
31
|
+
form_forms is built around the idea that a Rails application is able to
|
32
|
+
define arbitrary forms using a simple yet powerful DSL. These form
|
33
|
+
definitions are typically contained in the `lib` directory and are loaded
|
34
|
+
during initialization. During rendering of a request, the view simply
|
35
|
+
retrieves an existing form definition and renders that form by parameterizing
|
36
|
+
it with some data object (e.g. an ActiveRecord model instance).
|
37
|
+
|
38
|
+
To handle several forms, form_forms ships with a simple registry. If you
|
39
|
+
need a more powerful system, you are of course free to handle your form
|
40
|
+
objects in any other way.
|
41
|
+
|
42
|
+
## Defining Forms
|
43
|
+
|
44
|
+
FormForms::Registry[:my_form] = FormForms::Form.new() do |form|
|
45
|
+
form.field(:subject) {|f| f.input :subject}
|
46
|
+
form.field(:link) do |f|
|
47
|
+
content_tag :p do
|
48
|
+
content_tag(:a, :href => hint_path){ "This is a hint" }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
This will register a new form object under the name `:my_form` which will
|
54
|
+
render two fields: an input field for the `subject` attribute of the passed
|
55
|
+
model instance and a "static" hint. Each fields definition has a block which
|
56
|
+
defines what will actually be rendered. This block will be executed in the
|
57
|
+
context of the current view which allows you to use any helper methods you
|
58
|
+
have defined in your application.
|
59
|
+
|
60
|
+
Each of the fields is identified with a name, passed as the first parameter
|
61
|
+
to the field definition. Using this name, plugins can later change or remove
|
62
|
+
individual fields. As such, the name of each field has to be unique on each
|
63
|
+
level of the form.
|
64
|
+
|
65
|
+
The form can be rendered in a view by using something like this:
|
66
|
+
|
67
|
+
<%= FormForms::Registry[:my_form].render(@model, self) %>
|
68
|
+
|
69
|
+
The render method takes two parameters: the model object that should be used
|
70
|
+
as the base object for the form and a view instance (which can be almost
|
71
|
+
always passed as `self`). The view instance is used to render the form fields.
|
72
|
+
|
73
|
+
## Adapting an existing form from plugins
|
74
|
+
|
75
|
+
Once a form is defined, it fields can be added, changed, and removed later on.
|
76
|
+
|
77
|
+
New fields can be added either before or after already existing elements:
|
78
|
+
|
79
|
+
FormForms::Registry[:my_form].field_before(:description, :name) {|f| f.input :name}
|
80
|
+
FormForms::Registry[:my_form].field_after(:credit_card, :ccv) {|f| f.input :ccv}
|
81
|
+
|
82
|
+
This will insert the new field `:name` before the already defined field
|
83
|
+
`:description` and insert the field `:ccv` after the existing `:credit_card`
|
84
|
+
field. You can also insert elements at the very beginning and the very end of
|
85
|
+
the elements list:
|
86
|
+
|
87
|
+
FormForms::Registry[:my_form].field_first(:salutation) {|f| f.input :salutation}
|
88
|
+
FormForms::Registry[:my_form].field_last(:accept_terms) {|f| f.input :accept_terms}
|
89
|
+
|
90
|
+
Each of the element types defines the five methods
|
91
|
+
|
92
|
+
* `form.<type>`
|
93
|
+
* `form.<type>_first`
|
94
|
+
* `form.<type>_before`
|
95
|
+
* `form.<type>_after`
|
96
|
+
* `form.<type>_last` (an alias to `form.<type>`)
|
97
|
+
|
98
|
+
Each of the methods accepts all parameters of the respective element type.
|
99
|
+
Only the `form.<type>_before` and `form.<type>_after` methods take the name of
|
100
|
+
the element that should act as the respective index as the first argument.
|
101
|
+
|
102
|
+
Finally, there is the `form.delete` method which simply takes the name of an
|
103
|
+
element as its parameter. It complete deletes this element from the element
|
104
|
+
list, preventing it from rendering:
|
105
|
+
|
106
|
+
FormForms::Registry[:my_form].delete(:salutation)
|
107
|
+
|
108
|
+
# Element Types
|
109
|
+
|
110
|
+
form_forms already ships with different element types which allow you to
|
111
|
+
create most of the common form elements. These elements are used to define
|
112
|
+
the actual form body.
|
113
|
+
|
114
|
+
## `field`
|
115
|
+
|
116
|
+
The most basic element type is a `field` which is rendered to a basic form
|
117
|
+
field or a snipped of static code. Fields are the most basic form of elements
|
118
|
+
and typically made of the bulk of the form definition.
|
119
|
+
|
120
|
+
For the definition, they take a `name` which is used for identifying the
|
121
|
+
field in the form as well as a generator block to render the field. The name,
|
122
|
+
always being the first attribute is *only* used for identifying the element
|
123
|
+
later on and is not passed to the generator block during rendering and thus
|
124
|
+
can be chosen arbitrarily. It must only be unique in the current scope.
|
125
|
+
Generally, it is advisable to chose a name similar to the model field that is
|
126
|
+
actually rendered.
|
127
|
+
|
128
|
+
The block receives one argument during rendering: the form builder, i.e. the
|
129
|
+
simple_form object. Alternatively to a block, you can also directly pass a
|
130
|
+
string which will be emitted as-is. The usual HTML escape rules apply, i.e.
|
131
|
+
you have to use `html_save` correctly to avoid rendering unsafe data.
|
132
|
+
|
133
|
+
## `fieldset`
|
134
|
+
|
135
|
+
A fieldset is used to group fields in a single form. During rendering, this
|
136
|
+
elements will create an HTML `<fieldset>` tag and a `<legend>`. As a fieldset
|
137
|
+
naturally contains other fields, its generator block can be used to define
|
138
|
+
fields.
|
139
|
+
|
140
|
+
FormForms::Registry[:user] = FormForms::Form.new() do |form|
|
141
|
+
form.field(:street) {|f| f.input :street }
|
142
|
+
form.field(:city) {|f| f.input :city }
|
143
|
+
form.fieldset(:payment, :id => "payment") do |fieldset|
|
144
|
+
fieldset.legend "Credit Card Data"
|
145
|
+
fieldset.field(:credit_card) {|f| f.input :credit_card}
|
146
|
+
fieldset.field(:ccv) {|f| f.input :ccv}
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
The fieldset element creates a new scope (or sub-form) which can be
|
151
|
+
arbitrarily nested. Apart from all the other elements types, it has a special
|
152
|
+
sub element: the `legend`. It doesn't take a name as its first parameter.
|
153
|
+
Instead, it just takes a string or a generator block (similar to a `field`)
|
154
|
+
which is used to render the content of the `<legend>` tag of the fieldset.
|
155
|
+
|
156
|
+
The fieldset tag receives one additional (optional) hash argument which
|
157
|
+
allows to define additional options (e.g. additional HTML attributes) for the
|
158
|
+
the fieldset tag. All options supported by Rails' `content_tag` helper are
|
159
|
+
allowed here.
|
160
|
+
|
161
|
+
## `block`
|
162
|
+
|
163
|
+
A `block` creates a sub-form which nests form elements inside a HTML block
|
164
|
+
(e.g. a `<div>`) which is sometimes necessary to further group elements and
|
165
|
+
markup the form using custom CSS rules. This element works similar to the
|
166
|
+
`fieldset` described above.
|
167
|
+
|
168
|
+
FormForms::Registry[:user] = FormForms::Form.new() do |form|
|
169
|
+
form.field(:street) {|f| f.input :street }
|
170
|
+
form.block(:box, :class => "red-and-blinky") do |block|
|
171
|
+
block.field(:sell_your_soul) {|f| f.input :sell_your_soul}
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
## `fields`
|
176
|
+
|
177
|
+
Using fields, you can create sub-forms for association of the model object.
|
178
|
+
This allows you to create forms for nested elements.
|
179
|
+
|
180
|
+
FormForms::Registry[:user] = FormForms::Form.new() do |form|
|
181
|
+
form.field(:name) {|f| f.input :name}
|
182
|
+
|
183
|
+
args = lambda{|f| {:collection => Tag.all} }
|
184
|
+
form.fields(:tags, :tags, args) do |tags|
|
185
|
+
tags.field(:name) {|f| f.input :name}
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
The fields element type takes four arguments. The first is the name of the
|
190
|
+
element as usual. The second is the name of the association which is to be
|
191
|
+
rendered. For the example above, the `User` model is defined as follows:
|
192
|
+
|
193
|
+
class User < ActiveRecord::Base
|
194
|
+
has_many :tags
|
195
|
+
end
|
196
|
+
|
197
|
+
The third argument is an options hash which is passed to association render
|
198
|
+
function of simple_form. In our example, we pass the `:collection` attribute
|
199
|
+
which instructs simple_form to render a select box containing the elements of
|
200
|
+
the passed collection.
|
201
|
+
|
202
|
+
Here we have to do a little trick. If we simple pass the array here as in
|
203
|
+
|
204
|
+
form.fields(:tags, :tags, :collection => Tag.all) do |tags|
|
205
|
+
|
206
|
+
the `Tags.all` would be evaluated just once, during the initialization of the
|
207
|
+
application. New tags would not be included. To fix this, we pass a
|
208
|
+
lambda block which is evaluated each time again during the form rendering.
|
209
|
+
This lambda is expected to return an array of options to the `association`
|
210
|
+
method of simple_form.
|
211
|
+
|
212
|
+
# Development
|
213
|
+
|
214
|
+
Install dependencies with
|
215
|
+
|
216
|
+
bundle install
|
217
|
+
|
218
|
+
then run tests with
|
219
|
+
|
220
|
+
bundle exec rake
|
221
|
+
|
222
|
+
## Contributing
|
223
|
+
|
224
|
+
1. Fork it
|
225
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
226
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
227
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
228
|
+
5. Create new Pull Request
|
229
|
+
|
230
|
+
# License
|
231
|
+
|
232
|
+
> take my code with you<br/>
|
233
|
+
> and do whatever you want<br/>
|
234
|
+
> but please don’t blame me<br/>
|
235
|
+
|
236
|
+
[License Haiku](http://www.aaronsw.com/weblog/000360)
|
237
|
+
|
238
|
+
This library is licensed under the MIT license. See the `LICENSE` file for
|
239
|
+
more details.
|
data/Rakefile
ADDED
data/form_forms.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/form_forms/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Holger Just"]
|
6
|
+
gem.email = ["hjust@meine-er.de"]
|
7
|
+
gem.description = %q{Configurable forms for Rails}
|
8
|
+
gem.summary = %q{Configurable forms for Rails}
|
9
|
+
gem.homepage = "https://github.com/meineerde/form_forms"
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "form_forms"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Formforms::VERSION
|
17
|
+
|
18
|
+
gem.add_dependency "activesupport", "~> 3.0"
|
19
|
+
gem.add_dependency "actionpack", "~> 3.0"
|
20
|
+
gem.add_dependency "simple_form"
|
21
|
+
|
22
|
+
gem.add_development_dependency "activemodel", "~> 3.0"
|
23
|
+
end
|
data/lib/form_forms.rb
ADDED
@@ -0,0 +1,189 @@
|
|
1
|
+
require 'active_support/core_ext/string'
|
2
|
+
|
3
|
+
module FormForms
|
4
|
+
module Elements
|
5
|
+
# The generic base class for the FormForms
|
6
|
+
class BaseElement
|
7
|
+
def initialize(*)
|
8
|
+
@elements = []
|
9
|
+
@generators = {}
|
10
|
+
|
11
|
+
yield self
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :elements
|
15
|
+
|
16
|
+
# Render all of the elements of the current FormForm in their defined
|
17
|
+
# order. This method is expected to be called by sub-classes in the
|
18
|
+
# rendering chain. The parameters are a form builder object and an
|
19
|
+
# action view instance.
|
20
|
+
#
|
21
|
+
# The form builder is typically created by a "special" FormForm class
|
22
|
+
# and passed on to its sub-elements. See +FormForms::Forms::Form+
|
23
|
+
# for an implementation of such a special form.
|
24
|
+
def render(builder, view)
|
25
|
+
render_elements(builder, view)
|
26
|
+
end
|
27
|
+
|
28
|
+
def delete(name)
|
29
|
+
@elements.delete(name)
|
30
|
+
@generators.delete(name)
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
|
36
|
+
# Allow the passed form type as a sub-element of the current form.
|
37
|
+
# Sub-elements must have a unique name inside the current form scope.
|
38
|
+
# They can be of any allowed type.
|
39
|
+
#
|
40
|
+
# Elements can be added to the form using the generated +type+,
|
41
|
+
# +type_before+, and +type_after+ methods. Element definitions can be
|
42
|
+
# overridden by setting the element again with the same name.
|
43
|
+
#
|
44
|
+
# Example:
|
45
|
+
#
|
46
|
+
# class MyForm < BaseForm
|
47
|
+
# allowed_sub_element(:field)
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# my_form = MyForm.new() do |form|
|
51
|
+
# form.field(:subject) {|f| f.input :subject}
|
52
|
+
# form.field(:description) {|f| f.text_field :description}
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# my_form.field_before(:description, :name) {|f| f.input :name}
|
56
|
+
#
|
57
|
+
# my_form.elements
|
58
|
+
# # => [:subject, :name, :description]
|
59
|
+
|
60
|
+
def self.allowed_sub_element(type, klass=nil)
|
61
|
+
klass ||= "::FormForms::Elements::#{type.to_s.classify}"
|
62
|
+
|
63
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
64
|
+
def #{type}(name, *args, &block)
|
65
|
+
name = name.to_sym
|
66
|
+
|
67
|
+
if block_given?
|
68
|
+
element(name, #{klass}.new(*args, &block))
|
69
|
+
else
|
70
|
+
@generators[name]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
alias_method :#{type}_last, :#{type}
|
74
|
+
|
75
|
+
def #{type}_first(name, *args, &block)
|
76
|
+
element_before(nil, name.to_sym, #{klass}.new(*args, &block))
|
77
|
+
end
|
78
|
+
|
79
|
+
def #{type}_before(before, name, *args, &block)
|
80
|
+
element_before(before.to_sym, name.to_sym, #{klass}.new(*args, &block))
|
81
|
+
end
|
82
|
+
|
83
|
+
def #{type}_after(after, name, *args, &block)
|
84
|
+
element_after(after.to_sym, name.to_sym, #{klass}.new(*args, &block))
|
85
|
+
end
|
86
|
+
RUBY
|
87
|
+
end
|
88
|
+
|
89
|
+
# Define a property of the element. Properties can either be given as
|
90
|
+
# a block, similar to the fields, or as a static object. Internally,
|
91
|
+
# we always use the block form.
|
92
|
+
def self.property(name, instance_variable=nil)
|
93
|
+
instance_variable ||= name
|
94
|
+
|
95
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
96
|
+
def #{name}(param=indicator=true, &generator) # def legend(param=indicator=true, &generator
|
97
|
+
if block_given? # if block_given?
|
98
|
+
@#{instance_variable} = generator # @legend = generator
|
99
|
+
elsif indicator.nil? # elsif indicator.nil? # parameter was given
|
100
|
+
@#{instance_variable} = param # @legend = param
|
101
|
+
else # else
|
102
|
+
@#{instance_variable} # @legend
|
103
|
+
end # end
|
104
|
+
end # end
|
105
|
+
RUBY
|
106
|
+
end
|
107
|
+
|
108
|
+
# Get the actual value of a parameter. If the parameter was set with a
|
109
|
+
# block or a lambda, evaluate the lambda in the context of the view
|
110
|
+
# and return the result. This can be used for delayed evaluation of
|
111
|
+
# parameter arguments.
|
112
|
+
def eval_property(name, builder, view)
|
113
|
+
property = self.send(name.to_sym)
|
114
|
+
if property.is_a?(Proc)
|
115
|
+
view.instance_exec(builder, &property)
|
116
|
+
else
|
117
|
+
property
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# Append a generic element to the end of the elements list. This method
|
122
|
+
# is supposed tpo be called by the generated public methods of each
|
123
|
+
# sub-element type.
|
124
|
+
def element(name, generator)
|
125
|
+
@elements << name unless @elements.include? name
|
126
|
+
@generators[name] = generator
|
127
|
+
end
|
128
|
+
|
129
|
+
# Insert an element directly after an existing alement. The element
|
130
|
+
# +name+ can not be defined in the current form scope yet. The +after+
|
131
|
+
# element has to exist or be nil. If it is nil, the new element is
|
132
|
+
# appended to the end of the element list.
|
133
|
+
def element_after(after, name, generator)
|
134
|
+
if @elements.include? name
|
135
|
+
# Only allow new elements. Existing fields can be changed with #element
|
136
|
+
raise ArgumentError.new("#{name} is already registered.")
|
137
|
+
end
|
138
|
+
|
139
|
+
after_index = @elements.index(after)
|
140
|
+
if !after.nil? && after_index.nil?
|
141
|
+
# This method makes only sense if the before element actually exists
|
142
|
+
raise ArgumentError.new("#{after} is not registered. I can't insert after it.")
|
143
|
+
elsif after.nil? || after_index == @elements.length-1
|
144
|
+
# Append at the end
|
145
|
+
element(name, generator)
|
146
|
+
else
|
147
|
+
# Perform an insert
|
148
|
+
@elements.insert(after_index+1, name)
|
149
|
+
@generators[name] = generator
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# Inserts an element directly before an existing alement. The element
|
154
|
+
# +name+ can not be defined in the current form scope yet. The +before+
|
155
|
+
# element has to exist or be nil. If it is nil, the new element is added
|
156
|
+
# at the very beginning of the list.
|
157
|
+
def element_before(before, name, generator)
|
158
|
+
before_index = @elements.index(before)
|
159
|
+
|
160
|
+
if @elements.include? name
|
161
|
+
# Only allow new elements. Existing fields can be changed with #element
|
162
|
+
raise ArgumentError.new("#{name} is already registered.")
|
163
|
+
elsif !before.nil? && before_index.nil?
|
164
|
+
# This method makes only sense if the before element actually exists
|
165
|
+
raise ArgumentError.new("#{before} is not registered. I can't insert before it.")
|
166
|
+
end
|
167
|
+
|
168
|
+
# Perform an insert
|
169
|
+
if before.nil?
|
170
|
+
# insert at the beginning of the list
|
171
|
+
@elements.unshift(name)
|
172
|
+
else
|
173
|
+
# insert the element before the named one
|
174
|
+
@elements.insert(before_index, name)
|
175
|
+
end
|
176
|
+
@generators[name] = generator
|
177
|
+
end
|
178
|
+
|
179
|
+
# Render all elements in the current
|
180
|
+
def render_elements(builder, view, before="", after="\n")
|
181
|
+
@elements.each do |name|
|
182
|
+
view.concat before
|
183
|
+
view.concat @generators[name].render(builder, view)
|
184
|
+
view.concat after
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|