admin_assistant 0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/README +3 -28
  2. data/Rakefile +18 -10
  3. data/init.rb +1 -0
  4. data/install.rb +5 -1
  5. data/lib/admin_assistant/active_record_column.rb +211 -0
  6. data/lib/admin_assistant/association_target.rb +35 -0
  7. data/lib/admin_assistant/belongs_to_column.rb +186 -0
  8. data/lib/admin_assistant/builder.rb +222 -35
  9. data/lib/admin_assistant/column.rb +266 -297
  10. data/lib/admin_assistant/default_search_column.rb +41 -0
  11. data/lib/admin_assistant/file_column_column.rb +73 -0
  12. data/lib/admin_assistant/form_view.rb +7 -68
  13. data/lib/admin_assistant/helper.rb +4 -2
  14. data/lib/admin_assistant/index.rb +101 -81
  15. data/lib/admin_assistant/paperclip_column.rb +45 -0
  16. data/lib/admin_assistant/polymorphic_belongs_to_column.rb +102 -0
  17. data/lib/admin_assistant/request/autocomplete.rb +47 -0
  18. data/lib/admin_assistant/request/base.rb +176 -0
  19. data/lib/admin_assistant/request/create.rb +27 -0
  20. data/lib/admin_assistant/request/destroy.rb +15 -0
  21. data/lib/admin_assistant/request/edit.rb +11 -0
  22. data/lib/admin_assistant/request/index.rb +26 -0
  23. data/lib/admin_assistant/request/new.rb +19 -0
  24. data/lib/admin_assistant/request/show.rb +24 -0
  25. data/lib/admin_assistant/request/update.rb +44 -0
  26. data/lib/admin_assistant/search.rb +82 -0
  27. data/lib/admin_assistant/show_view.rb +20 -0
  28. data/lib/admin_assistant/virtual_column.rb +61 -0
  29. data/lib/admin_assistant.rb +190 -85
  30. data/lib/javascripts/admin_assistant.js +253 -0
  31. data/lib/stylesheets/activescaffold.css +219 -0
  32. data/lib/stylesheets/default.css +119 -0
  33. data/lib/views/_polymorphic_field_search.html.erb +89 -0
  34. data/lib/views/_restricted_autocompleter.html.erb +53 -0
  35. data/lib/views/autocomplete.html.erb +11 -0
  36. data/lib/views/form.html.erb +6 -3
  37. data/lib/views/index.html.erb +53 -46
  38. data/lib/views/show.html.erb +19 -0
  39. data/vendor/ar_query/MIT-LICENSE +20 -0
  40. data/vendor/ar_query/README +0 -0
  41. data/vendor/ar_query/init.rb +1 -0
  42. data/vendor/ar_query/install.rb +1 -0
  43. data/vendor/ar_query/lib/ar_query.rb +137 -0
  44. data/vendor/ar_query/spec/ar_query_spec.rb +253 -0
  45. data/vendor/ar_query/tasks/ar_query_tasks.rake +0 -0
  46. data/vendor/ar_query/uninstall.rb +1 -0
  47. metadata +39 -16
  48. data/lib/admin_assistant/request.rb +0 -183
  49. data/lib/stylesheets/admin_assistant.css +0 -75
@@ -0,0 +1,176 @@
1
+ class AdminAssistant
2
+ module Request
3
+ class Base
4
+ def initialize(admin_assistant, controller)
5
+ @admin_assistant, @controller = admin_assistant, controller
6
+ end
7
+
8
+ def action
9
+ @controller.action_name
10
+ end
11
+
12
+ def model_class
13
+ @admin_assistant.model_class
14
+ end
15
+
16
+ def model_class_symbol
17
+ model_class.name.underscore.to_sym
18
+ end
19
+
20
+ def params_for_save
21
+ ParamsForSave.new(@controller, @record, model_class_symbol)
22
+ end
23
+
24
+ def redirect_after_save
25
+ url_params = if @controller.respond_to?(:destination_after_save)
26
+ @controller.send(
27
+ :destination_after_save, @record, @controller.params
28
+ )
29
+ end
30
+ url_params ||= {:action => 'index'}
31
+ @controller.send :redirect_to, url_params
32
+ end
33
+
34
+ def after_template_file(template_name)
35
+ File.join(
36
+ RAILS_ROOT, 'app/views/', @controller.controller_path,
37
+ "_after_#{template_name}.html.erb"
38
+ )
39
+ end
40
+
41
+ def before_template_file(template_name)
42
+ File.join(
43
+ RAILS_ROOT, 'app/views/', @controller.controller_path,
44
+ "_before_#{template_name}.html.erb"
45
+ )
46
+ end
47
+
48
+ def render_template_file(template_name = action, opts_plus = {})
49
+ html = ''
50
+ html << render_to_string_if_exists(
51
+ before_template_file(template_name), opts_plus
52
+ )
53
+ html << render_to_string(
54
+ AdminAssistant.template_file(template_name), opts_plus
55
+ )
56
+ html << render_to_string_if_exists(
57
+ after_template_file(template_name), opts_plus
58
+ )
59
+ render_as_text_opts = {:text => html, :layout => true}.merge(opts_plus)
60
+ @controller.send :render, render_as_text_opts
61
+ end
62
+
63
+ def render_to_string(template_file, options_plus)
64
+ after_template_opts = {
65
+ :file => template_file, :layout => false
66
+ }.merge options_plus
67
+ @controller.send :render_to_string, after_template_opts
68
+ end
69
+
70
+ def render_to_string_if_exists(template_file, opts_plus)
71
+ if File.exist?(template_file)
72
+ render_to_string(template_file, opts_plus)
73
+ else
74
+ ''
75
+ end
76
+ end
77
+
78
+ def save
79
+ if @controller.respond_to?(:before_save)
80
+ @controller.send(:before_save, @record)
81
+ end
82
+ result = @record.save
83
+ if result && @controller.respond_to?(:after_save)
84
+ @controller.send(:after_save, @record)
85
+ end
86
+ result
87
+ end
88
+ end
89
+
90
+ class ParamsForSave < Hash
91
+ def initialize(controller, record, model_class_symbol)
92
+ super()
93
+ @controller, @record, @model_class_symbol =
94
+ controller, record, model_class_symbol
95
+ build_from_split_params
96
+ destroy_params.each do |k,v|
97
+ if whole_params[k].blank?
98
+ self[k] = nil
99
+ mname = "destroy_#{k}_in_attributes"
100
+ if controller.respond_to?(mname)
101
+ controller.send(mname, self)
102
+ end
103
+ end
104
+ end
105
+ build_from_whole_params
106
+ end
107
+
108
+ def build_from_split_params
109
+ bases = split_params.map { |k, v| k.gsub(/\([0-9]+i\)$/, '') }.uniq
110
+ bases.each do |b|
111
+ h = {}
112
+ split_params.each { |k, v|
113
+ h[k] = split_params.delete(k) if k =~ /#{b}\([0-9]+i\)$/
114
+ }
115
+ from_form_method = "#{b}_from_form".to_sym
116
+ if @controller.respond_to?(from_form_method)
117
+ self[b] = @controller.send(from_form_method, h)
118
+ elsif @record.respond_to?("#{b}=")
119
+ self.merge! h
120
+ end
121
+ end
122
+ end
123
+
124
+ def build_from_whole_params
125
+ whole_params.each do |k, v|
126
+ from_form_method = "#{k}_from_form".to_sym
127
+ if @controller.respond_to?(from_form_method)
128
+ self[k] = @controller.send(from_form_method, v)
129
+ elsif @record.respond_to?("#{k}=")
130
+ unless destroy_params[k] && v.blank?
131
+ column = @record.class.columns.detect { |c| c.name == k }
132
+ if column && column.type == :boolean
133
+ if v == '1'
134
+ v = true
135
+ elsif v == '0'
136
+ v = false
137
+ else
138
+ v = nil
139
+ end
140
+ end
141
+ self[k] = v
142
+ end
143
+ end
144
+ end
145
+ end
146
+
147
+ def destroy_params
148
+ dp = {}
149
+ @controller.params[@model_class_symbol].each do |k,v|
150
+ if k =~ %r|(.*)\(destroy\)|
151
+ dp[$1] = v
152
+ end
153
+ end
154
+ dp
155
+ end
156
+
157
+ def split_params
158
+ sp = {}
159
+ @controller.params[@model_class_symbol].each do |k,v|
160
+ sp[k] = v if k =~ /\([0-9]+i\)$/
161
+ end
162
+ sp
163
+ end
164
+
165
+ def whole_params
166
+ wp = {}
167
+ @controller.params[@model_class_symbol].each do |k,v|
168
+ unless k =~ /\([0-9]+i\)$/ || k =~ %r|(.*)\(destroy\)|
169
+ wp[k] = v
170
+ end
171
+ end
172
+ wp
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,27 @@
1
+ class AdminAssistant
2
+ module Request
3
+ class Create < Base
4
+ def call
5
+ @record = model_class.new
6
+ @record.attributes = params_for_save
7
+ if save
8
+ redirect_after_save
9
+ else
10
+ @controller.instance_variable_set :@record, @record
11
+ render_template_file 'form'
12
+ end
13
+ end
14
+
15
+ def save
16
+ if @controller.respond_to?(:before_create)
17
+ @controller.send(:before_create, @record)
18
+ end
19
+ result = super
20
+ if @controller.respond_to?(:after_create)
21
+ @controller.send(:after_create, @record)
22
+ end
23
+ result
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,15 @@
1
+ class AdminAssistant
2
+ module Request
3
+ class Destroy < Base
4
+ def call
5
+ @record = model_class.find @controller.params[:id]
6
+ if @admin_assistant.custom_destroy
7
+ @admin_assistant.custom_destroy.call @record
8
+ else
9
+ @record.destroy
10
+ end
11
+ @controller.send :render, :text => ''
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ class AdminAssistant
2
+ module Request
3
+ class Edit < Base
4
+ def call
5
+ @record = model_class.find @controller.params[:id]
6
+ @controller.instance_variable_set :@record, @record
7
+ render_template_file 'form'
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,26 @@
1
+ class AdminAssistant
2
+ module Request
3
+ class Index < Base
4
+ def call
5
+ controller_methods = {}
6
+ possible_methods = [
7
+ :conditions_for_index, :extra_right_column_links_for_index
8
+ ]
9
+ possible_methods.each do |mname|
10
+ if @controller.respond_to?(mname)
11
+ controller_methods[mname] = @controller.method mname
12
+ end
13
+ end
14
+ index = AdminAssistant::Index.new(
15
+ @admin_assistant, @controller.params, controller_methods
16
+ )
17
+ @controller.instance_variable_set :@index, index
18
+ render_template_file
19
+ end
20
+
21
+ def columns
22
+ @admin_assistant.index_settings.columns
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,19 @@
1
+ class AdminAssistant
2
+ module Request
3
+ class New < Base
4
+ def call
5
+ @record = model_class.new
6
+ @admin_assistant.form_settings.columns_for_new.each do |column|
7
+ if block = @admin_assistant.form_settings[column].default
8
+ @record.send("#{column}=", block.call(@controller))
9
+ end
10
+ end
11
+ if @controller.params[model_class_symbol]
12
+ @record.attributes = params_for_save
13
+ end
14
+ @controller.instance_variable_set :@record, @record
15
+ render_template_file 'form'
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,24 @@
1
+ class AdminAssistant
2
+ module Request
3
+ class Show < Base
4
+ def call
5
+ @record = model_class.find @controller.params[:id]
6
+ @controller.instance_variable_set :@record, @record
7
+ @controller.send(
8
+ :render,
9
+ :file => AdminAssistant.template_file('show'), :layout => true,
10
+ :locals => {:request => self}
11
+ )
12
+ end
13
+
14
+ def model_class_name(record)
15
+ if block = @admin_assistant.show_settings.model_class_name_block
16
+ block.call record
17
+ else
18
+ @admin_assistant.model_class_name
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+
@@ -0,0 +1,44 @@
1
+ class AdminAssistant
2
+ module Request
3
+ class Update < Base
4
+ def call
5
+ @record = model_class.find @controller.params[:id]
6
+ @record.attributes = params_for_save
7
+ if save
8
+ if @controller.params[:from]
9
+ render_response_to_ajax_toggle
10
+ else
11
+ redirect_after_save
12
+ end
13
+ else
14
+ @controller.instance_variable_set :@record, @record
15
+ render_template_file 'form'
16
+ end
17
+ end
18
+
19
+ def render_response_to_ajax_toggle
20
+ @controller.params[:from] =~ /#{model_class.name.underscore}_\d+_(.*)/
21
+ field_name = $1
22
+ index = AdminAssistant::Index.new @admin_assistant
23
+ erb = <<-ERB
24
+ <%= index.view(self).columns.detect { |c| c.name == field_name }.
25
+ ajax_toggle_inner_html(record) %>
26
+ ERB
27
+ @controller.send(
28
+ :render,
29
+ :inline => erb,
30
+ :locals => {
31
+ :index => index, :field_name => field_name, :record => @record
32
+ }
33
+ )
34
+ end
35
+
36
+ def save
37
+ if @controller.respond_to?(:before_update)
38
+ @controller.send(:before_update, @record)
39
+ end
40
+ super
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,82 @@
1
+ class AdminAssistant
2
+ class Search
3
+ attr_reader :params
4
+
5
+ def initialize(admin_assistant, params)
6
+ @admin_assistant, @params = admin_assistant, params
7
+ @params ||= {}
8
+ @attributes = HashWithIndifferentAccess.new
9
+ columns.each do |c|
10
+ c.verify_for_search
11
+ c.attributes_for_search_object(@params).each do |key, value|
12
+ @attributes[key] = value
13
+ end
14
+ end
15
+ end
16
+
17
+ def [](name)
18
+ @params[name]
19
+ end
20
+
21
+ def add_to_query(ar_query)
22
+ unless @params.empty?
23
+ ar_query.add_condition do |cond|
24
+ if match_any_conditions?
25
+ cond.boolean_join = :or
26
+ end
27
+ columns.each do |column|
28
+ column.add_to_query_condition cond, self
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ def columns
35
+ column_names = settings.column_names
36
+ if column_names.empty?
37
+ [DefaultSearchColumn.new(
38
+ @admin_assistant.model_class,
39
+ :fields_to_include => settings.default_search_includes
40
+ )]
41
+ else
42
+ column_names.map { |column_name|
43
+ @admin_assistant.column(column_name.to_s)
44
+ }
45
+ end
46
+ end
47
+
48
+ def column_views(action_view)
49
+ columns.map { |c|
50
+ c.search_view action_view, @admin_assistant, :search => self
51
+ }
52
+ end
53
+
54
+ def id
55
+ @attributes[:id] if @attributes.has_key?(:id)
56
+ end
57
+
58
+ def match_all_conditions?
59
+ !match_any_conditions?
60
+ end
61
+
62
+ def match_any_conditions?
63
+ @params["(all_or_any)"] == 'any'
64
+ end
65
+
66
+ def method_missing(meth, *args)
67
+ if @attributes.has_key?(meth)
68
+ @attributes[meth]
69
+ else
70
+ super
71
+ end
72
+ end
73
+
74
+ def model_class
75
+ @admin_assistant.model_class
76
+ end
77
+
78
+ def settings
79
+ @admin_assistant.search_settings
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,20 @@
1
+ class AdminAssistant
2
+ class ShowView
3
+ def initialize(record, admin_assistant, action_view)
4
+ @record, @admin_assistant, @action_view =
5
+ record, admin_assistant, action_view
6
+ end
7
+
8
+ def column_html(column)
9
+ column.html @record
10
+ end
11
+
12
+ def columns
13
+ column_names = @admin_assistant.show_settings.column_names ||
14
+ @admin_assistant.model_class.columns.map(&:name)
15
+ @admin_assistant.accumulate_columns(column_names).map { |c|
16
+ c.show_view @action_view, @admin_assistant
17
+ }
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,61 @@
1
+ class AdminAssistant
2
+ class VirtualColumn < Column
3
+ attr_reader :model_class, :name
4
+
5
+ def initialize(name, model_class, admin_assistant)
6
+ @name, @model_class = name.to_s, model_class
7
+ @search_settings = admin_assistant.search_settings[name]
8
+ end
9
+
10
+ def add_to_query_condition(ar_query_condition, search)
11
+ if conditions = @search_settings.conditions.call(search.send(@name))
12
+ ar_query_condition.sqls << conditions
13
+ end
14
+ end
15
+
16
+ def attributes_for_search_object(search_params)
17
+ value = if search_params[@name.to_s] == 'true'
18
+ true
19
+ elsif search_params[@name.to_s] == 'false'
20
+ false
21
+ else
22
+ nil
23
+ end
24
+ {@name => value}
25
+ end
26
+
27
+ def contains?(column_name)
28
+ column_name.to_s == @name
29
+ end
30
+
31
+ def field_type
32
+ @search_settings.field_type
33
+ end
34
+
35
+ def verify_for_search
36
+ unless @search_settings.conditions
37
+ raise "Virtual search column #{@name.to_sym.inspect} needs a conditions block"
38
+ end
39
+ end
40
+
41
+ class FormView < AdminAssistant::Column::View
42
+ include AdminAssistant::Column::FormViewMethods
43
+
44
+ def default_html(form)
45
+ input_name = "#{@column.model_class.name.underscore}[#{name}]"
46
+ if @input
47
+ if @input == :check_box
48
+ fv = value form.object
49
+ check_box_and_hidden_tags(input_name, fv)
50
+ end
51
+ else
52
+ @action_view.send(:text_field_tag, input_name, string(form.object))
53
+ end
54
+ end
55
+ end
56
+
57
+ class SearchView < AdminAssistant::Column::View
58
+ include AdminAssistant::Column::SimpleColumnSearchViewMethods
59
+ end
60
+ end
61
+ end