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
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 [](http://travis-ci.org/meineerde/form_forms) [](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
|