vidl-toolbox 0.0.1

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,305 @@
1
+ require File.dirname(__FILE__) << '/config'
2
+
3
+ # Helper method for form builders
4
+ module ActionView
5
+ module Helpers
6
+ class FormBuilder
7
+ def tag_id(method, options = {})
8
+ it = InstanceTag.new(@object_name, method, @template, nil, @object)
9
+ it.send :add_default_name_and_id, options #private method
10
+ options['id']
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ module Toolbox
17
+
18
+
19
+ class Renderer
20
+ attr_reader :widget_config
21
+
22
+ def initialize view, widget_config, dialog = false
23
+ @view = view
24
+ @widget_config = widget_config
25
+ @dialog = dialog
26
+ end
27
+
28
+
29
+ # Renders the label of the widget.
30
+ # If show_model is set to a model name, the model name of this widget
31
+ # will be added in parenthesis if it differs to the value in show_model.
32
+ def label(show_model = nil)
33
+ @widget_config.label ? @view.send(:h, @widget_config.label) : translate_field(show_model) unless @widget_config.suppress_label
34
+ end
35
+
36
+ # Translates a column name of a model using gettext
37
+ # The show_model argument is optional. If true, the model name will also be translated
38
+ # and appended to the column name. Ensure, that the model name is also translated
39
+ # (gettext does not extract this automatically).
40
+ #
41
+ def translate_field(show_model = nil)
42
+ col_name = @widget_config.name.to_s
43
+ model_name = @widget_config.model_name.classify
44
+ a = col_name.split('.')
45
+ if a.length > 1
46
+ model_name = a[-2].classify
47
+ col_name = a[-1]
48
+ end
49
+
50
+ text = @view.send(:s_, model_name + '|' + col_name.humanize)
51
+ text += ' (' + @view.send(:s_, model_name) + ')' if show_model && model_name != show_model
52
+ @view.send(:h, text)
53
+ end
54
+
55
+ end
56
+
57
+ class FieldRenderer < Renderer
58
+ # Generate a sort link for the given field
59
+ # A list can only be sorted by one field.
60
+ # Multiple list on one page can be distinguished by the prefix
61
+ # The field parameter is a field form a list configuration (Symbol, String or Hash)
62
+ # The text is the link text.
63
+ #
64
+ # The following css classes are assigend regarding the current sort direction
65
+ # - no sorting: 'sort-none'
66
+ # - asc sorting: 'sort-asc'
67
+ # - desc sorting: 'sort-desc'
68
+ def sort_link(params, prefix = nil)
69
+ if @widget_config.suppress_sorting
70
+ label
71
+ else
72
+ # see if we are already sorted
73
+ current_dir = Toolbox::Sorting.current(params, prefix, @widget_config.name.to_s)
74
+ case current_dir
75
+ when nil
76
+ new_dir = 'asc'
77
+ class_attr = 'sort-none'
78
+ when 'asc'
79
+ new_dir = 'desc'
80
+ class_attr = 'sort-asc'
81
+ else
82
+ new_dir = nil
83
+ class_attr = 'sort-desc'
84
+ end
85
+ @view.link_to(label, Toolbox::Sorting.params(params, prefix, @widget_config.name.to_s, new_dir), {:class => class_attr})
86
+ end
87
+ end
88
+
89
+ # Get the field value out of a model object
90
+ # If the attribute method is defined and it's a symbol, this method is called on the model object
91
+ # If the attribute method is defined and it's a block (Proc), the block is called with the model object as parameter
92
+ # In all other cases, the field name is interpreted as method and called on the model object
93
+ def value(rec)
94
+ val = rec.send(@widget_config.model_method) if @widget_config.model_method && @widget_config.model_method.is_a?(Symbol)
95
+ val = @widget_config.model_method.call(rec) if @widget_config.model_method && @widget_config.model_method.is_a?(Proc)
96
+ unless val # fallback
97
+ a = @widget_config.name.to_s.split('.')
98
+ a.each do |t|
99
+ rec = rec.send(t)
100
+ break unless rec # stop if nil is returned
101
+ end
102
+ val = rec
103
+ end
104
+ val
105
+ end
106
+
107
+ # Renders the value of an attribute of a given object.
108
+ # Parameters:
109
+ # - object: the object to get the attribute of
110
+ # - html: if true, returns the value in html (escaped etc.)
111
+ # The following options are used:
112
+ # - :model_method => an alternative method or block of the object to get the display value
113
+ # - :hide_empty: returns nil if the display value is empty. Otherwise, an empty string
114
+ # will be returned (or &nbsp; in case of html)
115
+ # - :suppress_link: if the display value is an ActiveRecord usually a link to it will
116
+ # be returned (only if html = true of course). If this option is set, only the string
117
+ # represenation will be returned
118
+ # - :join if the value is an array and :join is defined, the values are joined using the string
119
+ # representation of the :join value. Else, a unnumbered list (ul) is generated
120
+ #
121
+ # If the display value is an instance of Date, it will be formatted using the
122
+ # :local_date format
123
+ def render_value(object, html = true)
124
+ val = value(object)
125
+ if val.is_a? Array
126
+ if val.size > 0
127
+ if @widget_config.join
128
+ val.map { |v| value_text(v, html, object) }.join(@widget_config.join.to_s)
129
+ else
130
+ @view.content_tag 'ul' do
131
+ val.map { |v| @view.content_tag 'li', value_text(v, html, object) }.join
132
+ end
133
+ end
134
+ else # map empty array to nil
135
+ value_text nil, html, object
136
+ end
137
+ else # not an array
138
+ value_text val, html, object
139
+ end
140
+ end
141
+
142
+ protected
143
+ # internal helper to get the text of a value-object
144
+ def value_text (val, html, context) #:nodoc:
145
+ text = val # default
146
+ unless val == nil && @widget_config.hide_empty
147
+ if val
148
+ if @widget_config.trunc && val.to_s.length > @widget_config.trunc
149
+ v = val.to_s
150
+ v = v[0,@widget_config.trunc] + '...'
151
+ text = html ? "<span title=\"#{@view.send(:h, val)}\">#{@view.send(:h, v)}</span>" : v
152
+ else
153
+ text = html ? @view.send(:h, val) : val
154
+ end
155
+ else
156
+ text = html ? '&nbsp;' : ''
157
+ end
158
+ if val.kind_of?(ActiveRecord::Base) && !@widget_config.suppress_link
159
+ if html
160
+ text = @view.send(:link_to, val.to_s, val)
161
+ text += @view.context_menu_link(val, context) unless @widget_config.suppress_context_menu
162
+ else
163
+ text = val.to_s
164
+ end
165
+ end
166
+ text = val.to_s(:local_date) if val.instance_of? Date
167
+ text = val.to_s(:local_time) if val.instance_of? Time
168
+ text = val.to_s(:local_datetime) if val.instance_of? ActiveSupport::TimeWithZone
169
+ text += @widget_config.suffix.to_s if @widget_config.suffix
170
+ end
171
+ text
172
+ end
173
+
174
+ end
175
+
176
+ class ControlRenderer < Renderer
177
+
178
+ def render_control(form, rec, has_error = false)
179
+ options = {}
180
+ options[:class] = 'error' if has_error
181
+ options[:id] = "dialog_#{form.tag_id @widget_config.name}" if @dialog
182
+ case @widget_config.type
183
+ when :select
184
+ form.select @widget_config.name, @widget_config.values, {}, options
185
+ when :collection_select
186
+ form.collection_select @widget_config.name,
187
+ @widget_config.values,
188
+ @widget_config.model_method,
189
+ @widget_config.text_method,
190
+ {},
191
+ options.merge({ :multiple => true })
192
+ when :auto_complete
193
+ t = rec.class.name.underscore
194
+ #id = "#{t}_#{@widget_config.name.to_s}"
195
+ id = options[:id] || form.tag_id(@widget_config.name)
196
+ name = @widget_config.name.to_s.foreign_key.to_sym
197
+ opt = {}
198
+ opt[:id] = "dialog_#{form.tag_id name}" if @dialog
199
+ s = form.hidden_field name, opt
200
+ s += form.text_field @widget_config.name, options.merge(:size => (@widget_config.size || 40))
201
+ s += @view.content_tag("div", "", :id => "#{id}_auto_complete", :class => "auto_complete")
202
+ s += @view.auto_complete_field(id,
203
+ :url => @view.send(@widget_config.url),
204
+ :method => :get,
205
+ :param_name => :autocomplete_query,
206
+ :select => 'autocomplete_name',
207
+ :after_update_element => 'auto_complete_update_hidden'
208
+ )
209
+ s
210
+ when :radio
211
+ s = ''
212
+ @widget_config.values.each do |val|
213
+ s += form.radio_button @widget_config.name, val[1].to_s, options
214
+ s += @view.content_tag('span', val[0])
215
+ end
216
+ s
217
+ when :check_box
218
+ form.check_box @widget_config.name, options
219
+ when :date
220
+ form.calendar_date_select @widget_config.name, options.merge(:size => (@widget_config.size || 15))
221
+ when :textfield
222
+ val = rec.send @widget_config.name
223
+ text = val.to_s
224
+ text = val.to_s(:local_date) if val.instance_of? Date
225
+ text = val.to_s(:local_time) if val.instance_of? Time
226
+ text = val.to_s(:local_datetime) if val.instance_of? ActiveSupport::TimeWithZone
227
+ form.text_field @widget_config.name, options.merge({:size => (@widget_config.size || 40), :value => text})
228
+ else
229
+ raise "Unkown control type #{@widget_config.type}"
230
+ end
231
+ end
232
+
233
+ end
234
+
235
+ class ActionRenderer < Renderer
236
+
237
+ def label
238
+ if @widget_config.label
239
+ @widget_config.label
240
+ else
241
+ t = @widget_config.name.to_s.split '_'
242
+ l = @view.send(:_, t[0].humanize)
243
+ if t.size > 1 # e.g. new_group
244
+ model_name = t[1..-1].join '_'
245
+ l += ' ' + @view.send(:s_, model_name.humanize.downcase)
246
+ end
247
+ l
248
+ end
249
+ end
250
+
251
+ def render_action rec, context, current_action = nil
252
+ t = @widget_config.name.to_s.split '_'
253
+ action = t[0]
254
+ foreign_action = t.size > 1
255
+ if foreign_action # e.g. new_group
256
+ model_name = t[1..-1].join '_'
257
+ else
258
+ model_name = @widget_config.model_name
259
+ return nil if action == current_action
260
+ end
261
+ css_class = "enabled #{action}"
262
+
263
+ case action
264
+ when 'separator'
265
+ @widget_config.name if context
266
+ when 'new'
267
+ # copy the _id params to save the context
268
+ pars = {}
269
+ pars.merge! context if context
270
+ # delete self-reference
271
+ pars.delete model_name + '_id'
272
+ # set the object as parameter
273
+ pars[rec.class.name.underscore + '_id'] = rec #if foreign_action
274
+ url = @view.send("#{action}_#{model_name}_path".to_sym, pars)
275
+ if context || foreign_action
276
+ @view.link_to_remote label, { :url => url, :method => :get }, {:class => css_class }
277
+ else
278
+ @view.link_to label, url, {:class => css_class}
279
+ end
280
+ when 'show'
281
+ @view.link_to label, @view.polymorphic_path(rec), :class => css_class
282
+ when 'destroy'
283
+ msg = @view.send :_, 'Are you sure?'
284
+ if context
285
+ url = @view.polymorphic_path(rec)
286
+ @view.link_to_remote label, { :url => url, :method => :delete, :confirm => msg }, {:class => css_class }
287
+ else
288
+ @view.link_to label, rec, :confirm => msg, :method => :delete, :class => css_class
289
+ end
290
+ when 'list'
291
+ @view.link_to label, @view.send("#{model_name.pluralize}_path".to_sym), :class => css_class
292
+ when 'edit'
293
+ url = @view.edit_polymorphic_path rec
294
+ if context
295
+ @view.link_to_remote label, { :url => url, :method => :get }, {:class => css_class }
296
+ else
297
+ @view.link_to label, url
298
+ end
299
+ else
300
+ url = eval("@view.#{action}_#{model_name}_path(rec)")
301
+ @view.link_to_remote label, { :url => url, :method => :get }, {:class => css_class }
302
+ end # case
303
+ end
304
+ end
305
+ end
@@ -0,0 +1,85 @@
1
+ require 'gettext/rails'
2
+ require File.expand_path("../dirs", File.dirname(__FILE__))
3
+ require File.dirname(__FILE__) << '/config'
4
+ require File.dirname(__FILE__) << '/rendering'
5
+ module Toolbox
6
+ module Searching
7
+
8
+ def self.setup #:nodoc:
9
+ ActionController::Base.send(:extend, ControllerClassMethods)
10
+ ActionController::Base.send(:include, ControllerInstanceMethods)
11
+ ActionView::Base.send(:include, HelperMethods)
12
+ end
13
+
14
+ # Creates a SQL where condition with the given filter and a list of fields
15
+ # filter: the text to search for. Separated multiple value by space
16
+ # widgets_list: an instance of Toolbox::WidgetList. See ControllerClassMethods::search_fields
17
+ # for more information about the syntax.
18
+ # Example:
19
+ # search_field :firstname, :lastname, :address
20
+ # create_search_condition('dav ny')
21
+ # -> (firstname like 'dav' or lastname like 'dav' or address like 'dav')
22
+ # and (firstname like 'ny' or lastname like 'ny' or address like 'ny')
23
+ def self.create_search_condition(filter, widgets_list)
24
+ raise 'widgets_list are not of type Toolbox:WidgetList' unless widgets_list.is_a? Toolbox::WidgetList
25
+ cond_template = []
26
+ widgets_list.widgets.each do |w|
27
+ table = w.model_name.tableize
28
+ col_name = w.name
29
+ a = col_name.to_s.split('.')
30
+ if a.length > 1
31
+ table = a[-2].tableize
32
+ col_name = a[-1]
33
+ end
34
+ cond_template << "#{table}.#{col_name} like ? "
35
+ end
36
+ cond_template = '(' + cond_template.join(' or ') + ')'
37
+ cond = Array.new
38
+ cond.push('')
39
+ filter.squeeze(' ').split(' ').each do |text|
40
+ text = '%' + text + '%'
41
+ cond[0] += ' and ' if !cond[0].empty?
42
+ cond[0] += cond_template
43
+ cond_template.count('?').times do cond.push(text) end
44
+ end
45
+ # in case of empty search text
46
+ cond[0] = '1=1' if cond.length == 1
47
+ cond
48
+ end
49
+
50
+ module ControllerClassMethods
51
+ # Defines the search fields
52
+ # Example:
53
+ # search_field :firstname, :lastname, :address
54
+ # If symbols are given, the model is determined using the controllers name.
55
+ # If you want to search in associated tables, use this format:
56
+ # search_fields :firstname, :lastname, 'orders.desc'
57
+ def search_fields *fields
58
+ write_inheritable_attribute('search_fields', Toolbox::WidgetList.new(controller_name.singularize, fields, Toolbox::FieldConfig))
59
+ end
60
+
61
+ end
62
+
63
+ module ControllerInstanceMethods
64
+
65
+ # Returns the fields (array) defined with Toolbox::Searching::ControllerClassMethods::search_fields for this controller.
66
+ def search_fields
67
+ self.class.read_inheritable_attribute('search_fields') || nil
68
+ end
69
+
70
+ end
71
+
72
+ module HelperMethods
73
+ include GetText::Rails
74
+ bindtextdomain('toolbox', :path => Toolbox::Dirs::LOCALE)
75
+
76
+ def search_field_hint widgets_list
77
+ labels = []
78
+ widgets_list.widgets.each {|w| labels << Toolbox::Renderer.new(self, w).label(controller.model_name) }
79
+
80
+ _('Search in this fields:') + ' ' + labels.join(', ')
81
+ end
82
+ end
83
+ end
84
+
85
+ end
@@ -0,0 +1,63 @@
1
+ require 'gettext/rails'
2
+
3
+ module Toolbox
4
+ module SessionParams
5
+
6
+ def self.setup #:nodoc:
7
+ ActionController::Base.send(:extend, ClassMethods)
8
+ ActionController::Base.send(:include, InstanceMethods)
9
+
10
+ end
11
+
12
+ module ClassMethods
13
+
14
+ # Makes the given parameters "persistend' (per controller).
15
+ # The listed parameters will be stored in the session.
16
+ # In a before filter, the params hash is set with the value from
17
+ # the session, if (and only if) the parameter does not exist in the session.
18
+ # Otherwise the session value is updated.
19
+ def session_params *params
20
+ write_inheritable_attribute('session_params', params)
21
+ end
22
+ end
23
+
24
+ module InstanceMethods #:nodoc:all
25
+
26
+ def self.included(base)
27
+ base.send :before_filter, :set_session_params
28
+ base.send :after_filter, :update_session_params
29
+ end
30
+
31
+ private
32
+
33
+ # update the parameter hash from the session
34
+ def set_session_params
35
+ if self.class.read_inheritable_attribute('session_params')
36
+ create_session_params
37
+ session[:session_params][controller_name].each_key do |field|
38
+ params[field] = session[:session_params][controller_name][field] unless params[field]
39
+ end
40
+ end
41
+ end
42
+ # update the session from the params hash
43
+ def update_session_params
44
+ if p = self.class.read_inheritable_attribute('session_params')
45
+ create_session_params
46
+ p.each do |field|
47
+ if params[field]
48
+ session[:session_params][controller_name][field] = params[field]
49
+ else
50
+ session[:session_params][controller_name].delete(field)
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ def create_session_params
57
+ session[:session_params] = {} unless session[:session_params]
58
+ session[:session_params][controller_name] = {} unless session[:session_params][controller_name]
59
+ end
60
+ end
61
+ end
62
+
63
+ end
@@ -0,0 +1,73 @@
1
+ require File.dirname(__FILE__) << '/config'
2
+ module Toolbox
3
+
4
+ module Sorting
5
+
6
+ def self.quote_order_by(table, field)
7
+ table = ActiveRecord::Base.connection.quote_table_name(table)
8
+ field = ActiveRecord::Base.connection.quote_column_name(field)
9
+ "#{table}.#{field}"
10
+ end
11
+
12
+ # Create an oder-by string
13
+ # Parameters
14
+ # - prefix: an optional prefix used to get the right sort-field from the params hash
15
+ # - params: the parameter hash
16
+ # - widgets: an array of field configuration
17
+ def self.order_by(params, widgets, prefix = nil)
18
+ val = params[params_key(prefix)]
19
+ return nil unless val # no sort parameter set
20
+ field, dir = val.split '-'
21
+ dir = fix_direction dir
22
+ return nil if dir == 'none' # no sort direction
23
+ # find the field in field list
24
+ field = widgets.select{ |w| w == field }.first
25
+ order_by_string = nil
26
+ if field
27
+ if field.order_by
28
+ order_by_string = field.order_by
29
+ else
30
+ order_by_string = quote_order_by(field.model_name.tableize, field.name.to_s)
31
+ end
32
+ order_by_string += " #{dir}"
33
+ end
34
+ order_by_string
35
+ end
36
+
37
+ # inhibit any sql injection
38
+ def self.fix_direction dir #:nodoc:
39
+ dir == 'asc' ? 'asc' : (dir == 'desc' ? 'desc' : 'none')
40
+ end
41
+
42
+ # Get the current sorting direction from the given params hash
43
+ def self.current(params, prefix, field_name) #:nodoc:
44
+ dir = nil
45
+ if val = params[params_key(prefix)]
46
+ f, d = val.split '-'
47
+ dir = fix_direction(d) if f == field_name
48
+ end
49
+ dir
50
+ end
51
+
52
+ # Gets a parameter hash for link generation
53
+ def self.params(params, prefix, field_name, new_dir) #:nodoc:
54
+ if new_dir
55
+ params.merge({params_key(prefix) => "#{field_name}-#{new_dir}"})
56
+ else
57
+ params.delete params_key(prefix)
58
+ params
59
+ end
60
+ end
61
+
62
+ # Get the sort-key for the params hash regarding the prefix
63
+ def self.params_key(prefix) #:nodoc:
64
+ if prefix
65
+ "#{prefix}-sort".to_sym
66
+ else
67
+ :sort
68
+ end
69
+ end
70
+
71
+
72
+ end
73
+ end
@@ -0,0 +1,4 @@
1
+
2
+ module Toolbox
3
+ VERSION = '0.0.1'
4
+ end
data/lib/toolbox.rb ADDED
@@ -0,0 +1,29 @@
1
+ require 'gettext'
2
+ require File.dirname(__FILE__) << '/toolbox/searching'
3
+ require File.dirname(__FILE__) << '/toolbox/sorting'
4
+ require File.dirname(__FILE__) << '/toolbox/session_params'
5
+ require File.dirname(__FILE__) << '/toolbox/helpers'
6
+ require File.dirname(__FILE__) << '/toolbox/default_controller'
7
+ require File.dirname(__FILE__) << '/toolbox/config'
8
+ require File.dirname(__FILE__) << '/toolbox/version'
9
+ require File.dirname(__FILE__) << '/dirs'
10
+
11
+ if Object.const_defined?(:Rails) && File.directory?(Rails.root.to_s + "/public")
12
+
13
+ Toolbox::Searching.setup
14
+ Toolbox::SessionParams.setup
15
+ Toolbox::DefaultController.setup
16
+ ActionController::Base.send(:append_view_path, Toolbox::Dirs::VIEW)
17
+
18
+ # install files
19
+ unless File.exists?(RAILS_ROOT + "/public/javascripts/toolbox-#{Toolbox::VERSION}/toolbox.js")
20
+ ['/public/javascripts', '/public/stylesheets', '/public/images'].each do |dir|
21
+ source = File.join(Toolbox::Dirs::GEM_ROOT, dir)
22
+ appendix = dir.ends_with?('javascripts') ? "toolbox-#{Toolbox::VERSION}" : 'toolbox'
23
+ dest = File.join(RAILS_ROOT, dir, appendix)
24
+ FileUtils.mkdir_p(dest)
25
+ FileUtils.cp(Dir.glob(source + '/*.*'), dest)
26
+ end
27
+ end
28
+ end
29
+
Binary file
@@ -0,0 +1,23 @@
1
+ <%
2
+ no_form = local_assigns[:form].nil?
3
+ rec = collection # just for more readable code
4
+ collection = rec.send(widgetset.collection_config.model_method)
5
+ locals = {:parent => rec, :widgetset => widgetset, :renderers => renderers}
6
+ id = widgetset.collection_config.object_id.to_s + '_' + dom_id(rec)
7
+ unless no_form and collection.empty? and widgetset.collection_config.hide_empty
8
+ field_set_tag widgetset.label do %>
9
+ <table id="<%= id %>">
10
+ <%= render :partial => 'toolbox/collection_header', :locals => locals %>
11
+ <%= render :partial => no_form ? 'toolbox/show_collection_row' : 'toolbox/form_collection_row', :collection => collection, :locals => locals %>
12
+ </table>
13
+ <% unless no_form %>
14
+ <%=
15
+
16
+ link_to_function image_tag('toolbox/add.png', :border => 0) do |page|
17
+ page.insert_html :bottom, id, :partial => 'toolbox/form_collection_row', :object => widgetset.collection_config.type.new, :locals => locals.merge({:auto_id => true})
18
+ end
19
+ %>
20
+ <% end %>
21
+ <% end %>
22
+ <% end %>
23
+
@@ -0,0 +1,7 @@
1
+ <% unless widgetset.collection_config.suppress_table_header %>
2
+ <tr>
3
+ <% renderers.each do |renderer| %>
4
+ <th class="record-title"><%= renderer.label %></th>
5
+ <% end %>
6
+ </tr>
7
+ <% end %>
@@ -0,0 +1,17 @@
1
+ <%
2
+ rec = context_menu
3
+ renderer = widget_list.widgets.map { |a| Toolbox::ActionRenderer.new self, a }
4
+ %>
5
+ <ul>
6
+ <li style="color: darkgray; text-align:center;"><%= s_(rec.class.name.underscore.humanize.downcase) %></li>
7
+ <li class="separator"></li>
8
+ <% renderer.each do |r|
9
+ a = r.render_action rec, context
10
+ if a.is_a? String
11
+ %>
12
+ <li><%= a %></li>
13
+ <% else %>
14
+ <li class="<%= a.to_s %>"></li>
15
+ <% end %>
16
+ <% end %>
17
+ </ul>
@@ -0,0 +1,28 @@
1
+ <% # Aufruf: render :partial => "toolbox/form", :object => @article, :locals => { :fsets => ..., :options => ... } %>
2
+ <%
3
+ rec = form # just for more readable code
4
+ dialog = false unless dialog
5
+ form_method = dialog ? :remote_form_for : :form_for
6
+
7
+ %>
8
+ <% send(form_method, rec) do |frm| %>
9
+ <%= frm.error_messages %>
10
+ <% widgetsets.each do |widgetset|
11
+ renderers = widgetset.widget_list.widgets.map { |w| Toolbox::ControlRenderer.new(self, w, dialog) }
12
+ if widgetset.condition == nil || widgetset.condition.call(rec) %>
13
+ <%= render :partial => widgetset.collection_config ? 'toolbox/collection': 'toolbox/form_fieldset',
14
+ :object => rec,
15
+ :locals => {:form => frm, :widgetset => widgetset, :renderers => renderers} %>
16
+ <% end %>
17
+ <% end %>
18
+ <div class="toolbar">
19
+ <%= frm.submit(rec.new_record?() ? Toolbox::Messages.create : Toolbox::Messages.save, :name => :save) %>
20
+ <% if dialog %>
21
+ <%= button_to_function Toolbox::Messages.cancel, "$('dialog_id').popup.hide()" %>
22
+ <% else %>
23
+ <%= frm.submit Toolbox::Messages.cancel, :name => :cancel %>
24
+ <% end %>
25
+ </div>
26
+ <% end %>
27
+
28
+
@@ -0,0 +1,16 @@
1
+ <%
2
+ rec = form_collection_row # just for more readable code
3
+ parent_object_name = ActionController::RecordIdentifier.singular_class_name(parent)
4
+ collection_attribute_name = Toolbox::Helpers.collection_attribute_name(widgetset.collection_config, rec)
5
+ prefix = "#{parent_object_name}[#{collection_attribute_name}][]"
6
+ has_error = parent.errors.on(widgetset.collection_config.model_method)
7
+ %>
8
+ <% fields_for prefix, rec do |frm| %>
9
+ <tr>
10
+ <% renderers.each do |control_renderer| %>
11
+ <td><%= control_renderer.render_control(frm, rec, has_error) %></td>
12
+ <% end %>
13
+ <td><%= link_to_function image_tag('toolbox/remove.png', :border => 0), "$(this).up('tr').remove()" %>
14
+ </tr>
15
+ <% end %>
16
+
@@ -0,0 +1,19 @@
1
+ <% # renders a fieldset with a normal label: value structure %>
2
+ <%
3
+ rec = form_fieldset # just for more readable code
4
+ frm = form
5
+ field_set_tag widgetset.label do
6
+ %>
7
+ <table border="0">
8
+ <%
9
+ renderers.each do |renderer|
10
+ has_error = rec.errors.on(renderer.widget_config.name)
11
+ %>
12
+ <tr>
13
+ <td><%= frm.label renderer.widget_config.name unless renderer.widget_config.suppress_label %></td>
14
+ <td ><%= renderer.render_control(frm, rec, has_error) %></td>
15
+ </tr>
16
+ <% end %>
17
+ </table>
18
+ <% end %>
19
+