toolbox 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/Rakefile +57 -0
  2. data/lib/dirs.rb +9 -0
  3. data/lib/toolbox/config.rb +211 -0
  4. data/lib/toolbox/default_controller.rb +393 -0
  5. data/lib/toolbox/helpers.rb +11 -0
  6. data/lib/toolbox/rendering.rb +413 -0
  7. data/lib/toolbox/searching.rb +85 -0
  8. data/lib/toolbox/session_params.rb +63 -0
  9. data/lib/toolbox/sorting.rb +74 -0
  10. data/lib/toolbox/version.rb +4 -0
  11. data/lib/toolbox.rb +29 -0
  12. data/locale/de/LC_MESSAGES/toolbox.mo +0 -0
  13. data/public/images/add.png +0 -0
  14. data/public/images/arrow_down.gif +0 -0
  15. data/public/images/arrow_up.gif +0 -0
  16. data/public/images/close.png +0 -0
  17. data/public/images/edit.gif +0 -0
  18. data/public/images/email.png +0 -0
  19. data/public/images/page.png +0 -0
  20. data/public/images/page_acrobat.png +0 -0
  21. data/public/images/page_add.png +0 -0
  22. data/public/images/page_copy.png +0 -0
  23. data/public/images/page_delete.png +0 -0
  24. data/public/images/page_edit.png +0 -0
  25. data/public/images/page_excel.png +0 -0
  26. data/public/images/page_list.png +0 -0
  27. data/public/images/page_save.png +0 -0
  28. data/public/images/page_word.png +0 -0
  29. data/public/images/remove.png +0 -0
  30. data/public/images/show.gif +0 -0
  31. data/public/images/spinner.gif +0 -0
  32. data/public/javascripts/popup.js +498 -0
  33. data/public/javascripts/toolbox.js +18 -0
  34. data/public/stylesheets/context_menu.css +168 -0
  35. data/public/stylesheets/popup.css +30 -0
  36. data/public/stylesheets/toolbox.css +107 -0
  37. data/view/toolbox/_collection.html.erb +24 -0
  38. data/view/toolbox/_collection_header.html.erb +7 -0
  39. data/view/toolbox/_context_menu.html.erb +17 -0
  40. data/view/toolbox/_dialogs.html.erb +6 -0
  41. data/view/toolbox/_form.html.erb +30 -0
  42. data/view/toolbox/_form_collection_row.html.erb +18 -0
  43. data/view/toolbox/_form_fieldset.html.erb +30 -0
  44. data/view/toolbox/_form_fieldset_row.html.erb +19 -0
  45. data/view/toolbox/_list.html.erb +25 -0
  46. data/view/toolbox/_list_row.html.erb +10 -0
  47. data/view/toolbox/_menu.html.erb +7 -0
  48. data/view/toolbox/_search_field.html.erb +8 -0
  49. data/view/toolbox/_show.html.erb +12 -0
  50. data/view/toolbox/_show_collection_row.html.erb +6 -0
  51. data/view/toolbox/_show_fieldset.html.erb +21 -0
  52. data/view/toolbox/edit.html.erb +5 -0
  53. data/view/toolbox/index.html.erb +3 -0
  54. data/view/toolbox/new.html.erb +9 -0
  55. data/view/toolbox/show.html.erb +39 -0
  56. metadata +178 -0
data/Rakefile ADDED
@@ -0,0 +1,57 @@
1
+ require 'rubygems'
2
+ require File.dirname(__FILE__) << "/lib/toolbox/version"
3
+
4
+ spec = Gem::Specification.new do |s|
5
+ s.name = %q{toolbox}
6
+ s.version = Toolbox::VERSION
7
+ s.date = %q{2009-01-29}
8
+ s.authors = ["David Nyffenegger"]
9
+ s.email = %q{vidl@sunrise.ch}
10
+ s.summary = %q{Davids toolbox to speedup development with rails (mainly view).}
11
+ s.homepage = %q{http://github.com/vidl/toolbox}
12
+ s.description = %q{This toolbox goes in the direction of the django admin interface.}
13
+ s.rubyforge_project = %q{toolbox}
14
+ s.files = FileList["[A-Z]*", "{lib,locale,view,public}/**/*"]
15
+
16
+ # rdoc
17
+ s.has_rdoc = true
18
+ #s.extra_rdoc_files = %w(README.rdoc MIT-LICENSE.txt)
19
+
20
+ s.add_dependency "activesupport", ">= 2.1.1"
21
+ s.add_dependency "actionpack", ">= 2.1.1"
22
+ s.add_dependency "actionpack", ">= 2.1.1"
23
+ s.add_dependency "gettext", ">= 2.1.0"
24
+ s.add_dependency "mislav-will_paginate", ">= 2.3.3"
25
+ s.add_dependency "calendar_date_select", ">= 1.15.0"
26
+ s.add_dependency "fastercsv", ">= 1.4.0"
27
+
28
+ end
29
+
30
+ desc "Generate a gemspec file for GitHup"
31
+ task :gemspec do
32
+ File.open("#{spec.name}.gemspec", 'w') do |f|
33
+ f.write spec.to_ruby
34
+ end
35
+ end
36
+
37
+ desc "Create the gem"
38
+ task :gem => [:makemo, :gemspec] do
39
+ `gem build #{spec.name}.gemspec`
40
+ end
41
+
42
+ desc "Generate RDoc"
43
+ task :doc do
44
+ system "hanna -x Rakefile -x spec --title 'Toolbox #{Toolbox::VERSION} API Documentation'"
45
+ end
46
+
47
+ desc "Update pot/po files."
48
+ task :updatepo do
49
+ require 'gettext/tools' #HERE!
50
+ GetText.update_pofiles("#{spec.name}", Dir.glob("{lib}/**/*.{rb,erb,rjs}"), "#{spec.name} #{Toolbox::VERSION}")
51
+ end
52
+
53
+ desc "Create mo-files"
54
+ task :makemo do
55
+ require 'gettext/tools' #HERE!
56
+ GetText.create_mofiles
57
+ end
data/lib/dirs.rb ADDED
@@ -0,0 +1,9 @@
1
+
2
+ module Toolbox
3
+ module Dirs
4
+ GEM_ROOT = File.expand_path("../", File.dirname(__FILE__)) unless defined? GEM_ROOT
5
+ LOCALE = File.join(GEM_ROOT, '/locale') unless defined? LOCALE
6
+ VIEW = File.join(GEM_ROOT, '/view') unless defined? VIEW
7
+
8
+ end
9
+ end
@@ -0,0 +1,211 @@
1
+
2
+ module Toolbox
3
+
4
+ class WidgetList
5
+ attr_reader :widgets
6
+
7
+ def initialize model_name, widgets, type
8
+ @widgets = []
9
+ last = nil
10
+ h = nil
11
+ widgets.each do |widget|
12
+ h = { :name => last, :model_name => model_name}
13
+ if widget.is_a? Hash
14
+ raise 'Before an option hash there must be a widget name (string or symbol)' unless last
15
+ raise 'The item before a option hash must be a string or a symbol' unless last.is_a?(String) || last.is_a?(Symbol)
16
+ h.merge! widget
17
+ end
18
+ @widgets << type.new(h) if last && !last.is_a?(Hash)
19
+ last = widget
20
+ end
21
+ # add the last field, if it's a symbol
22
+ if last && !last.is_a?(Hash)
23
+ h = { :name => last, :model_name => model_name}
24
+ @widgets << type.new(h)
25
+ end
26
+ end
27
+ end
28
+
29
+
30
+ class EditConfig
31
+ attr_reader :controlsets
32
+
33
+ def initialize model_name, config
34
+ @controlsets = []
35
+ config.each do |controlset|
36
+ raise 'The options aggregation_config and collection_config must not be defined toghether' if controlset[:collection_config] and controlset[:aggregation_config]
37
+ h = {}
38
+ h.merge! controlset
39
+ h[:widget_list] = WidgetList.new(model_name, controlset[:widget_list], controlset[:widget_type] || ControlConfig)
40
+ h[:collection_config] = CollectionConfig.new controlset[:collection_config] if controlset[:collection_config]
41
+ h[:aggregation_config] = AggregationConfig.new controlset[:aggregation_config] if controlset[:aggregation_config]
42
+ @controlsets << WidgetSetConfig.new(h)
43
+ end
44
+ end
45
+ end
46
+
47
+ class ShowConfig
48
+ attr_reader :fieldsets
49
+ attr_reader :embedded_lists
50
+ attr_reader :pdf_options
51
+
52
+ def initialize model_name, config
53
+ @fieldsets = []
54
+ config[:fieldsets].each do |fieldset|
55
+ h = {}
56
+ h.merge! fieldset
57
+ h[:widget_list] = WidgetList.new(model_name, fieldset[:widget_list], fieldset[:widget_type] || FieldConfig)
58
+ h[:collection_config] = CollectionConfig.new fieldset[:collection_config] if fieldset[:collection_config]
59
+ @fieldsets << WidgetSetConfig.new(h)
60
+ end
61
+ @embedded_lists = []
62
+ prefixes = {}
63
+ config[:embedded_lists] = config[:embedded_lists] || []
64
+ config[:embedded_lists].each do |list|
65
+ h = {}
66
+ h.merge! list
67
+ h[:collection_config] = CollectionConfig.new list[:collection_config]
68
+ h[:widget_list] = WidgetList.new(h[:collection_config].type.name, list[:widget_list], FieldConfig)
69
+ c = EmbeddedListConfig.new(h)
70
+ raise "Prefix #{c.prefix} is already used by #{prefixes[c.prefix].label}" if prefixes[c.prefix]
71
+ prefixes[c.prefix] = c
72
+ @embedded_lists << c
73
+ end
74
+ @pdf_options = config[:pdf_options] || {}
75
+ end
76
+ end
77
+
78
+ # The base class of the configuration classes.
79
+
80
+ class Config
81
+ protected
82
+ # Use this methods to easily define which options the configuration class supports.
83
+ # This is done by hash, where each key defines a single option by its name.
84
+ # The value is a hash that may contain the following keys:
85
+ # - :required boolean, if true, this option is mandatory, default is false
86
+ # - :type array of class-names. If set, an exception is raised if the given value is not of the specified type
87
+ # - :values array of allowed values. If set, an exception is raised if the given value is not withing the specified values.
88
+ # - :default a default value, that is set, if the option is not given. Otherwise, nil is assgined
89
+ def self.define_options options
90
+ # attr_reader for each option
91
+ options.each_key { |k| attr_reader k }
92
+ write_inheritable_attribute 'options', options || {}
93
+ end
94
+
95
+ # create the constructor out of the options definition
96
+ def initialize vars
97
+ vars.each_pair do |k,v|
98
+ if respond_to? k.to_sym # set only, if there is an accessor
99
+ k = '@' + k.to_s
100
+ instance_variable_set(k.to_sym,v)
101
+ else
102
+ raise "Unkown option #{k.to_s} (#{self.class.name.to_s})"
103
+ end
104
+ end
105
+ # check against the definition
106
+ self.class.read_inheritable_attribute('options').each_pair do |name, opt|
107
+ val = vars[name]
108
+ class_name = "(#{self.class.name.to_s}: #{val.inspect})"
109
+ raise "#{name} is required #{class_name}" if opt[:required] && !val
110
+ raise "#{name} is #{val.class.to_s} and not of #{opt[:type].join(' or ')} #{class_name}" if opt[:type] && val && !opt[:type].include?(val.class)
111
+ raise "#{name} is not in #{opt[:values].join(', ')} #{class_name}" if opt[:values] && val && !opt[:values].include?(val)
112
+ instance_variable_set("@#{name.to_s}".to_sym, opt[:default] || nil) unless val
113
+ end
114
+ end
115
+ end
116
+
117
+ # Holds the configuration for a collection. This defines how to render a widget if it's not a simple
118
+ # type but a collection.
119
+ class CollectionConfig < Config
120
+ define_options :type => { :type => [Class], :required => true},
121
+ :model_method => { :type => [Symbol], :required => true},
122
+ :suppress_table_header => { :default => false},
123
+ :hide_empty => { :default => false}
124
+ end
125
+
126
+ # Holds the configuration for other aggregations than collections.
127
+ class AggregationConfig < Config
128
+ define_options :type => { :type => [Class], :required => true},
129
+ :model_method => { :type => [Symbol], :required => true}
130
+
131
+ end
132
+
133
+ # Holds the configuration for a from control
134
+ class ControlConfig < Config
135
+ define_options :model_method => { :type => [Symbol, Proc]},
136
+ :text_method => { :type => [Symbol]},
137
+ :suppress_label => { :default => false },
138
+ :label => { :type => [String] },
139
+ :name => { :required => true, :type => [Symbol] },
140
+ :model_name => { :required => true, :type => [String] },
141
+ :type => { :type => [Symbol], :default => :textfield,
142
+ :values => [:select, :collection_select, :auto_complete, :textfield,
143
+ :textarea, :radio, :date, :check_box, :filefield, :hidden]},
144
+ :url => { :type => [Symbol]},
145
+ :size => { :type => [Fixnum, String]},
146
+ :values => { :type => [Array]},
147
+ :info => { :type => [String]},
148
+ :css_class => { :type => [String]},
149
+ :disabled => { :default => false, :type => [FalseClass, TrueClass, Proc]}
150
+ end
151
+
152
+ # Holds the configuration for a non-editable field
153
+ class FieldConfig < Config
154
+ define_options :model_method => { :type => [Symbol, Proc]},
155
+ :render_method => { :type => [Symbol, Proc]},
156
+ :hide_empty => { :default => false },
157
+ :suppress_label => { :default => false },
158
+ :suppress_link => { :default => false },
159
+ :suppress_sorting => { :default => false },
160
+ :suppress_context_menu => { :default => false},
161
+ :order_by => { :type => [String, Array] },
162
+ :label => { :type => [String] },
163
+ :join => {},
164
+ :suffix => {},
165
+ :name => { :required => true, :type => [String, Symbol] },
166
+ :model_name => { :required => true, :type => [String] },
167
+ :trunc => { :type => [Fixnum]}
168
+
169
+
170
+ def ==(s)
171
+ (s.is_a?(Hash) && s[:name] && @name.to_s == s[:name].to_s) ||
172
+ (s.is_a?(Symbol) && @name.to_s == s.to_s) ||
173
+ (s.is_a?(String) && @name.to_s == s) ||
174
+ (s.is_a?(FieldConfig) && s.name.to_s == @name.to_s)
175
+ end
176
+ end
177
+
178
+ # Holds the configuration for a set of widgets. Widgets are either controls of a form
179
+ # or un-editable fields.
180
+ class WidgetSetConfig < Config
181
+ define_options :widget_list => { :type => [WidgetList], :required => true},
182
+ :label => { :type => [String], :required => true},
183
+ :collection_config => { :type => [CollectionConfig] },
184
+ :aggregation_config => { :type => [AggregationConfig] },
185
+ :partial => { :type => [String]},
186
+ :widget_type => { :type => [Class], :values => [ControlConfig, FieldConfig]},
187
+ :condition => { :type => [Proc] } # if set, the fieldset is only rendered, if the proc returns true
188
+ end
189
+
190
+ # Holds the configuration for an embedded list
191
+ class EmbeddedListConfig < Config
192
+ define_options :widget_list => { :type => [WidgetList], :required => true},
193
+ :label => { :type => [String], :required => true},
194
+ :collection_config => { :type => [CollectionConfig], :required => true },
195
+ :prefix => { :type => [String], :required => true},
196
+ :include_assoc => { :type => [Array]}
197
+ end
198
+
199
+ class ActionConfig < Config
200
+ define_options :label => { :type => [String] },
201
+ :name => { :required => true, :type => [Symbol] },
202
+ :model_name => { :required => true, :type => [String] },
203
+ :url => {:type => [String]},
204
+ :direct_link => { :type => [TrueClass, FalseClass], :default => false},
205
+ :active => { :type => [Fixnum], :default => 1},
206
+ :css_class => { :type => [String]}
207
+
208
+ end
209
+
210
+
211
+ end
@@ -0,0 +1,393 @@
1
+ require File.expand_path("../dirs", File.dirname(__FILE__))
2
+ require 'fastercsv'
3
+
4
+ module Toolbox
5
+
6
+ #
7
+ # Defines the default action.
8
+ #
9
+ module DefaultController
10
+
11
+ def self.setup #:nodoc:
12
+ ActionController::Base.send(:extend, ClassMethods)
13
+ #ActionController::Base.send(:include, InstanceMethods)
14
+ ActionView::Base.send(:include, HelperMethods)
15
+ end
16
+
17
+ module HelperMethods
18
+ def get_record
19
+ instance_variable_get ('@' + controller.model_name).to_sym
20
+ end
21
+
22
+ def context_menu_link(rec, context = nil)
23
+ if controller.respond_to? :menu_config
24
+ context_records = []
25
+ # get the record in show-mode
26
+ context_records << get_record if get_record.is_a? ActiveRecord::Base
27
+ context_records << context if context
28
+ p = {}
29
+ context_records.each { |r| p["#{r.class.name.to_s}_id".to_sym] = r }
30
+ ctx_url =send("context_menu_#{rec.class.to_s.underscore}_path".to_sym, rec, p)
31
+ link_to_function('&#9660;', "show_context_menu(event, '#{ctx_url}')")
32
+ else
33
+ ''
34
+ end
35
+ end
36
+
37
+ # returns html necessary to load javascript and css to make the toolbox work
38
+ def toolbox_includes()
39
+ return "" if @toolbox_already_included
40
+ @toolbox_already_included = true
41
+
42
+
43
+ js = javascript_include_tag "toolbox-#{Toolbox::VERSION}/toolbox", "toolbox-#{Toolbox::VERSION}/popup"
44
+ cs = stylesheet_link_tag 'toolbox/context_menu', 'toolbox/popup', 'toolbox/toolbox'
45
+ js + "\n" + cs + "\n"
46
+ end
47
+
48
+
49
+ end
50
+
51
+ module ClassMethods
52
+
53
+ # The listed associations are included in when using find together with
54
+ # search fields. Thus if a search field defintion contains "foreign" fields
55
+ # one may include the corresponding association.
56
+ def include_assoc *assoc
57
+ write_inheritable_attribute('include_assoc', assoc)
58
+ end
59
+
60
+ end
61
+
62
+ module InstanceMethods #:nodoc:all
63
+
64
+ def index
65
+ obj = paging
66
+ instance_variable_set :@recs, obj
67
+
68
+ respond_to do |format|
69
+ format.html do
70
+ begin
71
+ render # allow to overwrite the view of an action
72
+ rescue ActionView::MissingTemplate
73
+ render :template => 'toolbox/index'
74
+ end
75
+ end
76
+ format.xml { render :xml => obj }
77
+ end
78
+ end
79
+
80
+ def show
81
+ rec = model_class.find(params[:id])
82
+ set_record rec
83
+
84
+ @show_config = show_config rec
85
+ @embedded_list = nil
86
+ if @show_config.embedded_lists.length > 0
87
+ prefix = params[:list] || @show_config.embedded_lists.first.prefix
88
+ @show_config.embedded_lists.each do |embedded_list|
89
+ @embedded_list = embedded_list if embedded_list.prefix == prefix
90
+ end
91
+ end
92
+
93
+ respond_to do |format|
94
+ format.html do
95
+ begin
96
+ render # allow to overwrite the view of an action
97
+ rescue ActionView::MissingTemplate
98
+ render :template => 'toolbox/show'
99
+ end
100
+ end
101
+ format.xml { render :xml => rec }
102
+ format.pdf { render @show_config.pdf_options }
103
+ format.csv { stream_csv show_csv(rec, params) }
104
+ end
105
+ end
106
+
107
+
108
+ def new
109
+ # Handle dublicate command
110
+ param_name = "#{model_name}_id".to_sym
111
+ attr = {}
112
+ attr = model_class.find(params[param_name]).attributes if params[param_name]
113
+ obj = model_class.new attr
114
+
115
+ set_record obj
116
+
117
+ # context support
118
+ # set all _id fields, if available from params
119
+ params.each_pair do | key,value |
120
+ if key.to_s.ends_with? '_id' and obj.respond_to? key + '='
121
+ obj.send(key + '=', value)
122
+ end
123
+ end
124
+
125
+ respond_to do |format|
126
+ format.html { render :template => 'toolbox/new' }
127
+ format.xml { render :xml => obj }
128
+ format.js do
129
+ render :update do |page|
130
+ locals = {:widgetsets => controller.edit_config(obj).controlsets, :dialog => true }
131
+ page.replace_html 'dialog_id', :partial => "toolbox/form", :object => obj, :locals => locals
132
+ page << "$('dialog_id').popup.show();"
133
+ end
134
+ end
135
+ end
136
+ end
137
+
138
+ def edit
139
+ obj = model_class.find(params[:id])
140
+ set_record obj
141
+
142
+ respond_to do |format|
143
+ format.html { render :template => 'toolbox/edit' }
144
+ format.js do
145
+ render :update do |page|
146
+ locals = {:widgetsets => controller.edit_config(obj).controlsets, :dialog => true }
147
+ page.replace_html 'dialog_id', :partial => "toolbox/form", :object => obj, :locals => locals
148
+ page << "$('dialog_id').popup.show();"
149
+ end
150
+ end
151
+ end
152
+ end
153
+
154
+ def create
155
+ if params[:save] # save or ok clicked
156
+ p = params[model_name.to_sym]
157
+ preprocess_params nil, p
158
+ obj = model_class.new p
159
+ set_record obj
160
+
161
+ respond_to do |format|
162
+ if obj.save
163
+ obj = redirect_create obj if respond_to? :redirect_create
164
+ flash[:notice] = Messages.created % { :object => s_(controller_name.singularize.humanize.downcase)}
165
+ format.html { redirect_to(obj) }
166
+ format.js do
167
+ render :update do
168
+ |page| page << 'window.location.reload();' # TODO improvment?
169
+ end
170
+ end
171
+ format.xml { render :xml => obj, :status => :created, :location => obj }
172
+ else
173
+ format.html { render :template => "toolbox/new" }
174
+ format.xml { render :xml => obj.errors, :status => :unprocessable_entity }
175
+ format.js do
176
+ render :update do |page|
177
+ locals = {:widgetsets => controller.edit_config(obj).controlsets, :dialog => true }
178
+ page.replace_html 'dialog_id', :partial => "toolbox/form", :object => obj, :locals => locals
179
+ end
180
+ end
181
+ end
182
+ end
183
+ else # cancel clicked
184
+ redirect_to eval("#{controller_name}_path")
185
+ end
186
+ end
187
+
188
+
189
+ def update
190
+ obj = model_class.find(params[:id])
191
+ set_record obj
192
+
193
+ if params[:save]
194
+ par = params[model_name.to_sym]
195
+ preprocess_params obj, par
196
+ # Ensure that the the collection attributes exist - create them if not
197
+ # This is needed, if all collection items have been deleted.
198
+ edit_config(obj).controlsets.each do |controlset|
199
+ if controlset.collection_config
200
+ attr = Toolbox::Helpers.collection_attribute_name(controlset.collection_config, obj)
201
+ par[attr] ||= {}
202
+ end
203
+ end
204
+
205
+ respond_to do |format|
206
+ if obj.update_attributes(par)
207
+ flash[:notice] = Messages.updated % { :object => s_(controller_name.singularize.humanize.downcase)}
208
+ format.html { redirect_to(obj) }
209
+ format.xml { head :ok }
210
+ format.js do
211
+ render :update do |page|
212
+ page << 'window.location.reload();' # TODO improve ?
213
+ end
214
+ end
215
+ else
216
+ format.html { render :template => "toolbox/edit" }
217
+ format.xml { render :xml => obj.errors, :status => :unprocessable_entity }
218
+ format.js do
219
+ render :update do |page|
220
+ locals = {:widgetsets => controller.edit_config(obj).controlsets, :dialog => true }
221
+ page.replace_html 'dialog_id', :partial => "toolbox/form", :object => obj, :locals => locals
222
+ end
223
+ end
224
+ end
225
+ end
226
+ else # cancel clicked
227
+ respond_to do |format|
228
+ format.html { redirect_to(obj) }
229
+ format.xml { head :ok }
230
+ end
231
+ end
232
+ end
233
+
234
+ def destroy
235
+ obj = model_class.find(params[:id])
236
+ set_record obj
237
+ obj.destroy
238
+
239
+ respond_to do |format|
240
+ format.html { redirect_to(send(controller_name + '_url')) }
241
+ format.xml { head :ok }
242
+ format.js do
243
+ render :update do |page|
244
+ page << 'window.location.reload();' # TODO: improve?
245
+ end
246
+ end
247
+ end
248
+ end
249
+
250
+ def context_menu
251
+ rec = model_class.find(params[:id])
252
+ set_record rec
253
+ context = {}
254
+ params.select { |k,v| k.ends_with? '_id' }.each {|a| context[a[0]] = a[1] }
255
+ locals = { :context => context, :widget_list => menu_config(rec, context)}
256
+ respond_to do |format|
257
+ format.html { render :partial => "toolbox/context_menu", :object => rec, :locals => locals }
258
+ format.js do
259
+ render :update do |page|
260
+ page.replace_html 'context_menu_id', :partial => "toolbox/context_menu", :object => rec, :locals => locals
261
+ end
262
+ end
263
+ end
264
+ end
265
+
266
+ def model_name
267
+ controller_name.singularize
268
+ end
269
+
270
+ def model_class
271
+ controller_name.classify.constantize
272
+ end
273
+
274
+ def embedded_list_collection rec
275
+ options = {}
276
+ options[:order] = Toolbox::Sorting.order_by params, @embedded_list.widget_list.widgets, @embedded_list.prefix
277
+ options[:include] = @embedded_list.include_assoc if @embedded_list.include_assoc
278
+ rec.send(@embedded_list.collection_config.model_method).find(:all, options)
279
+ end
280
+
281
+ protected
282
+
283
+ def stream_csv options
284
+ field_renderers = options[:widget_list].widgets.map { |f| Toolbox::FieldRenderer.new self, f }
285
+
286
+ csv_string = FasterCSV.generate do |csv|
287
+ # Title
288
+ csv << field_renderers.map { |fr| fr.label(false, false) }
289
+ options[:collection].each do |rec|
290
+ csv << field_renderers.map { |fr| fr.render_value(rec, false) }
291
+ end
292
+ end
293
+ send_data csv_string, :type => "text/csv",
294
+ :filename=> options[:filename],
295
+ :disposition => 'attachment'
296
+ end
297
+
298
+
299
+ # check the consitency between the visible input-field
300
+ # and the invisible id field of autocomplete fields and
301
+ # parses date-fields
302
+ def preprocess_params rec, params
303
+ edit_config(rec).controlsets.each do |controlset|
304
+ controlset.widget_list.widgets.each do |widget|
305
+ case widget.type
306
+ when :auto_complete
307
+ if controlset.collection_config
308
+ # remove autocomplete text field for new or existing entries
309
+ a = Toolbox::Helpers.collection_attribute_name(controlset.collection_config, rec)
310
+ coll = params[a]
311
+ if coll
312
+ coll.each { |p| remove_autocomplete_text p, widget} if coll.is_a? Array
313
+ coll.each_value { |p| remove_autocomplete_text p, widget} if coll.is_a? Hash
314
+ end
315
+ if rec # may also have new entries...
316
+ a = Toolbox::Helpers.collection_attribute_name(controlset.collection_config, nil)
317
+ coll = params[a]
318
+ coll.each { |p| remove_autocomplete_text p, widget} if coll
319
+ end
320
+ else
321
+ remove_autocomplete_text params, widget
322
+ end
323
+ when :date
324
+ #params[widget.name] = Date.strptime(params[widget.name], '%d.%m.%y')
325
+ end
326
+ end
327
+ end
328
+ params
329
+ end
330
+
331
+ # do the paging for the index
332
+ def paging
333
+ filter = (params[:query] || params[:filter] || '')
334
+ cond = Toolbox::Searching.create_search_condition filter, search_fields
335
+ order = Toolbox::Sorting.order_by params, index_config.widgets
336
+ options = { :page => params[:page], :conditions => cond }
337
+ options[:order] = order if order
338
+ options[:include] = include_assoc if include_assoc
339
+ if respond_to? :index_data
340
+ index_data.paginate options
341
+ else
342
+ model_class.paginate options
343
+ end
344
+ end
345
+
346
+ private
347
+
348
+ def remove_autocomplete_text param, widget
349
+ value = param.delete widget.name
350
+ param[widget.name.to_s.foreign_key] = nil if value == '' || value == nil
351
+ end
352
+
353
+ def set_record obj
354
+ instance_variable_set "@#{model_name}".to_sym, obj
355
+ end
356
+
357
+ def include_assoc
358
+ self.class.read_inheritable_attribute('include_assoc')
359
+ end
360
+
361
+ end
362
+
363
+ end
364
+
365
+ # needed for not to conflict with the textdomain from the application controller
366
+ module Messages #:nodoc:all
367
+ include GetText
368
+ bindtextdomain('toolbox', :path => Toolbox::Dirs::LOCALE)
369
+ def self.created
370
+ _('%{object} was successfully created.')
371
+ end
372
+ def self.updated
373
+ _('%{object} was successfully updated.')
374
+ end
375
+
376
+ def self.create
377
+ _('Create')
378
+ end
379
+
380
+ def self.save
381
+ _('Save')
382
+ end
383
+
384
+ def self.cancel
385
+ _('Cancel')
386
+ end
387
+
388
+ def self.nothing_found
389
+ _('Nothing found')
390
+ end
391
+ end
392
+
393
+ end
@@ -0,0 +1,11 @@
1
+
2
+ module Toolbox
3
+ module Helpers
4
+
5
+ def self.collection_attribute_name collection_config, rec
6
+ new_or_existing = rec && !rec.new_record? ? 'existing' : 'new'
7
+ "#{new_or_existing}_#{collection_config.type.name.to_s.underscore}_attributes"
8
+ end
9
+
10
+ end
11
+ end