toolbox 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.
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