active_scaffold_vho 3.0.26 → 3.0.27

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. data/.gitignore +42 -0
  2. data/Gemfile +1 -10
  3. data/Gemfile.lock +78 -10
  4. data/Rakefile +19 -17
  5. data/active_scaffold_vho.gemspec +14 -324
  6. data/frontends/default/javascripts/jquery/active_scaffold.js +23 -13
  7. data/frontends/default/javascripts/prototype/active_scaffold.js +22 -14
  8. data/frontends/default/stylesheets/stylesheet.css +1 -1
  9. data/frontends/default/views/_list.html.erb +2 -1
  10. data/frontends/default/views/_list_messages.html.erb +2 -2
  11. data/frontends/default/views/_list_pagination.html.erb +3 -6
  12. data/frontends/default/views/_list_record_columns.html.erb +1 -1
  13. data/lib/active_scaffold/actions/list.rb +7 -6
  14. data/lib/active_scaffold/active_record_permissions.rb +25 -0
  15. data/lib/active_scaffold/attribute_params.rb +5 -2
  16. data/lib/active_scaffold/bridges/shared/date_bridge.rb +3 -3
  17. data/lib/active_scaffold/bridges/tiny_mce/public/javascripts/prototype/tiny_mce_bridge.js +1 -1
  18. data/lib/active_scaffold/config/core.rb +8 -1
  19. data/lib/active_scaffold/config/field_search.rb +22 -1
  20. data/lib/active_scaffold/data_structures/column.rb +19 -2
  21. data/lib/active_scaffold/finder.rb +19 -30
  22. data/lib/active_scaffold/helpers/human_condition_helpers.rb +4 -2
  23. data/lib/active_scaffold/helpers/list_column_helpers.rb +9 -2
  24. data/lib/active_scaffold/locale/de.yml +118 -0
  25. data/lib/active_scaffold/locale/en.yml +115 -0
  26. data/lib/active_scaffold/version.rb +1 -1
  27. data/lib/active_scaffold.rb +0 -1
  28. data/test/mock_app/public/stylesheets/active_scaffold/default/stylesheet.css +1 -1
  29. metadata +102 -62
  30. data/lib/active_scaffold/locale/de.rb +0 -120
  31. data/lib/active_scaffold/locale/en.rb +0 -119
@@ -119,7 +119,7 @@ $(document).ready(function() {
119
119
  });
120
120
  $('a.as_cancel').live('ajax:beforeSend', function(event, xhr, settings) {
121
121
  var as_cancel = $(this);
122
- var action_link = ActiveScaffold.ActionLink.get($(this));
122
+ var action_link = ActiveScaffold.find_action_link(as_cancel);
123
123
  var refresh_data = as_cancel.attr('data-refresh');
124
124
 
125
125
  if (action_link && action_link.position && refresh_data === 'true' && action_link.refresh_url) {
@@ -159,19 +159,27 @@ $(document).ready(function() {
159
159
  ActiveScaffold.report_500_response(as_scaffold);
160
160
  return true;
161
161
  });
162
- $('a.as_paginate').live('ajax:before',function(event) {
162
+ $('div.active-scaffold-footer .pagination a').live('ajax:before',function(event) {
163
163
  var as_paginate = $(this);
164
+ var loading_indicator = as_paginate.closest('.pagination').find('img.loading-indicator').first();
164
165
  var history_controller_id = as_paginate.attr('data-page-history');
165
166
  if (history_controller_id) addActiveScaffoldPageToHistory(as_paginate.attr('href'), history_controller_id);
166
- as_paginate.prevAll('img.loading-indicator').css('visibility','visible');
167
+
168
+ if (loading_indicator == null || loading_indicator.length == 0) {
169
+ var table_loading_indicator = as_paginate.closest('div.active-scaffold').find('div.actions img.loading-indicator').first();
170
+ loading_indicator = table_loading_indicator.clone();
171
+ loading_indicator.attr('id', null);
172
+ as_paginate.closest('.pagination').prepend(loading_indicator);
173
+ }
174
+ loading_indicator.css('visibility','visible');
167
175
  return true;
168
176
  });
169
- $('a.as_paginate').live('ajax:failure', function(event) {
177
+ $('div.active-scaffold-footer .pagination a').live('ajax:failure', function(event) {
170
178
  var as_scaffold = $(this).closest('.active-scaffold');
171
179
  ActiveScaffold.report_500_response(as_scaffold);
172
180
  return true;
173
181
  });
174
- $('a.as_paginate').live('ajax:complete', function(event) {
182
+ $('div.active-scaffold-footer .pagination a').live('ajax:complete', function(event) {
175
183
  $(this).prevAll('img.loading-indicator').css('visibility','hidden');
176
184
  return true;
177
185
  });
@@ -661,7 +669,7 @@ var ActiveScaffold = {
661
669
  },
662
670
 
663
671
  report_500_response: function(active_scaffold_id) {
664
- server_error = $(active_scaffold_id).find('td.messages-container p.server-error');
672
+ server_error = $(active_scaffold_id).find('td.messages-container p.server-error').filter(":first");
665
673
  if (!$(server_error).is(':visible')) {
666
674
  server_error.show();
667
675
  }
@@ -1099,7 +1107,7 @@ ActiveScaffold.ActionLink.Abstract = Class.extend({
1099
1107
  this.adapter.addClass('as_adapter');
1100
1108
  this.adapter.data('action_link', this);
1101
1109
  },
1102
- wrap_with_adapter_html: function(content) {
1110
+ wrap_with_adapter_html: function(content, should_refresh_data) {
1103
1111
  // players_view class missing
1104
1112
  var id_string = null;
1105
1113
  var close_label = this.scaffold().attr('data-closelabel');
@@ -1115,7 +1123,7 @@ ActiveScaffold.ActionLink.Abstract = Class.extend({
1115
1123
  id_string = this.target.attr('id').replace('list', 'nested');
1116
1124
  }
1117
1125
 
1118
- return '<tr class="inline-adapter" id="' + id_string + '"><td colspan="99" class="inline-adapter-cell"><div class="' + this.action + '-view ' + controller + '-view view"><a class="inline-adapter-close as_cancel" title="' + close_label + '" data-remote="true" data-refresh="false" href="">' + close_label +'</a>' + content + '</div></td></tr>'
1126
+ return '<tr class="inline-adapter" id="' + id_string + '"><td colspan="99" class="inline-adapter-cell"><div class="' + this.action + '-view ' + controller + '-view view"><a class="inline-adapter-close as_cancel" title="' + close_label + '" data-remote="true" data-refresh="' + should_refresh_data + '" href="">' + close_label +'</a>' + content + '</div></td></tr>'
1119
1127
  }
1120
1128
  });
1121
1129
 
@@ -1153,6 +1161,7 @@ ActiveScaffold.ActionLink.Record = ActiveScaffold.ActionLink.Abstract.extend({
1153
1161
  },
1154
1162
 
1155
1163
  insert: function(content) {
1164
+ var should_refresh_data = (typeof(this.refresh_ur)== 'undefined');
1156
1165
  this.close_previous_adapter();
1157
1166
 
1158
1167
  if (this.position == 'replace') {
@@ -1161,12 +1170,12 @@ ActiveScaffold.ActionLink.Record = ActiveScaffold.ActionLink.Abstract.extend({
1161
1170
  }
1162
1171
 
1163
1172
  if (this.position == 'after') {
1164
- this.target.after(this.wrap_with_adapter_html(content));
1173
+ this.target.after(this.wrap_with_adapter_html(content, should_refresh_data));
1165
1174
  ActiveScaffold.trigger_load_events(this.target.next().find('[data-as_load]'));
1166
1175
  this.set_adapter(this.target.next());
1167
1176
  }
1168
1177
  else if (this.position == 'before') {
1169
- this.target.before(this.wrap_with_adapter_html(content));
1178
+ this.target.before(this.wrap_with_adapter_html(content, should_refresh_data));
1170
1179
  ActiveScaffold.trigger_load_events(this.target.prev().find('[data-as_load]'));
1171
1180
  this.set_adapter(this.target.prev());
1172
1181
  }
@@ -1201,12 +1210,13 @@ ActiveScaffold.ActionLink.Record = ActiveScaffold.ActionLink.Abstract.extend({
1201
1210
  },
1202
1211
 
1203
1212
  set_opened: function() {
1213
+ var should_refresh_data = (typeof(this.refresh_ur)== 'undefined');
1204
1214
  if (this.position == 'after') {
1205
- var new_adapter = ActiveScaffold.replace(this.target.next(), this.wrap_with_adapter_html(this.target.next().children(':first-child').html()), true);
1215
+ var new_adapter = ActiveScaffold.replace(this.target.next(), this.wrap_with_adapter_html(this.target.next().children(':first-child').html(), should_refresh_data), true);
1206
1216
  this.set_adapter(new_adapter);
1207
1217
  }
1208
1218
  else if (this.position == 'before') {
1209
- var new_adapter = ActiveScaffold.replace(this.target.prev(), this.wrap_with_adapter_html(this.target.prev().children(':first-child').html()), true);
1219
+ var new_adapter = ActiveScaffold.replace(this.target.prev(), this.wrap_with_adapter_html(this.target.prev().children(':first-child').html(), should_refresh_data), true);
1210
1220
  this.set_adapter(new_adapter);
1211
1221
  }
1212
1222
  this.disable();
@@ -1227,7 +1237,7 @@ ActiveScaffold.Actions.Table = ActiveScaffold.Actions.Abstract.extend({
1227
1237
  ActiveScaffold.ActionLink.Table = ActiveScaffold.ActionLink.Abstract.extend({
1228
1238
  insert: function(content) {
1229
1239
  if (this.position == 'top') {
1230
- this.target.prepend(this.wrap_with_adapter_html(content));
1240
+ this.target.prepend(this.wrap_with_adapter_html(content, false));
1231
1241
  ActiveScaffold.trigger_load_events(this.target.children().first().find('[data-as_load]'));
1232
1242
  this.set_adapter(this.target.children().first());
1233
1243
  }
@@ -209,21 +209,27 @@ document.observe("dom:loaded", function() {
209
209
  }
210
210
  return true;
211
211
  });
212
- document.on('ajax:before', 'a.as_paginate', function(event) {
212
+ document.on('ajax:before', 'div.active-scaffold-footer .pagination a', function(event) {
213
213
  var as_paginate = event.findElement();
214
- var loading_indicator = as_paginate.up().down('img.loading-indicator');
214
+ var loading_indicator = as_paginate.up(1).down('img.loading-indicator');
215
215
  var history_controller_id = as_paginate.readAttribute('data-page-history');
216
216
 
217
217
  if (history_controller_id) addActiveScaffoldPageToHistory(as_paginate.readAttribute('href'), history_controller_id);
218
- if (loading_indicator) loading_indicator.style.visibility = 'visible';
218
+ if (loading_indicator == null) {
219
+ var table_loading_indicator = as_paginate.up('div.active-scaffold').down('div.actions').down('img.loading-indicator');
220
+ loading_indicator = table_loading_indicator.cloneNode(true);
221
+ loading_indicator.id = null;
222
+ as_paginate.up(1).insert({top: loading_indicator});
223
+ }
224
+ loading_indicator.style.visibility = 'visible';
219
225
  return true;
220
226
  });
221
- document.on('ajax:failure', 'a.as_paginate', function(event) {
227
+ document.on('ajax:failure', 'div.active-scaffold-footer .pagination a', function(event) {
222
228
  var as_scaffold = event.findElement('.active-scaffold');
223
229
  ActiveScaffold.report_500_response(as_scaffold);
224
230
  return true;
225
231
  });
226
- document.on('ajax:complete', 'a.as_paginate', function(event) {
232
+ document.on('ajax:complete', 'div.active-scaffold-footer .pagination a', function(event) {
227
233
  var as_paginate = event.findElement();
228
234
  var loading_indicator = as_paginate.up().down('img.loading-indicator');
229
235
 
@@ -354,12 +360,12 @@ document.observe("dom:loaded", function() {
354
360
  });
355
361
  document.on('ajax:before', 'form.as_form', function(event) {
356
362
  var as_form = event.findElement('form');
357
- element.fire('as:form_submit');
363
+ as_form.fire('as:form_submit');
358
364
  return true;
359
365
  });
360
366
  document.on('submit', 'form.as_form[data-remote!="true"]', function(event) {
361
367
  var as_form = event.findElement('form');
362
- element.fire('as:form_submit');
368
+ as_form.fire('as:form_submit');
363
369
  return true;
364
370
  });
365
371
  ActiveScaffold.trigger_load_events($$('[data-as_load]'));
@@ -934,7 +940,7 @@ ActiveScaffold.ActionLink.Abstract = Class.create({
934
940
  this.adapter.store('action_link', this);
935
941
  },
936
942
 
937
- wrap_with_adapter_html: function(content) {
943
+ wrap_with_adapter_html: function(content, should_refresh_data) {
938
944
  // players_view class missing
939
945
  var id_string = null;
940
946
  var close_label = this.scaffold().readAttribute('data-closelabel');
@@ -950,7 +956,7 @@ ActiveScaffold.ActionLink.Abstract = Class.create({
950
956
  id_string = this.target.readAttribute('id').replace('list', 'nested');
951
957
  }
952
958
 
953
- return '<tr class="inline-adapter" id="' + id_string + '"><td colspan="99" class="inline-adapter-cell"><div class="' + this.action + '-view ' + controller + '-view view"><a class="inline-adapter-close as_cancel" title="' + close_label + '" data-remote="true" data-refresh="false" href="">' + close_label +'</a>' + content + '</div></td></tr>'
959
+ return '<tr class="inline-adapter" id="' + id_string + '"><td colspan="99" class="inline-adapter-cell"><div class="' + this.action + '-view ' + controller + '-view view"><a class="inline-adapter-close as_cancel" title="' + close_label + '" data-remote="true" data-refresh="' + should_refresh_data + '" href="">' + close_label +'</a>' + content + '</div></td></tr>'
954
960
  }
955
961
  });
956
962
 
@@ -983,6 +989,7 @@ ActiveScaffold.ActionLink.Record = Class.create(ActiveScaffold.ActionLink.Abstra
983
989
  },
984
990
 
985
991
  insert: function(content) {
992
+ var should_refresh_data = (typeof(this.refresh_ur)== 'undefined');
986
993
  this.close_previous_adapter();
987
994
 
988
995
  if (this.position == 'replace') {
@@ -991,12 +998,12 @@ ActiveScaffold.ActionLink.Record = Class.create(ActiveScaffold.ActionLink.Abstra
991
998
  }
992
999
 
993
1000
  if (this.position == 'after') {
994
- this.target.insert({after:this.wrap_with_adapter_html(content)});
1001
+ this.target.insert({after:this.wrap_with_adapter_html(content, should_refresh_data)});
995
1002
  ActiveScaffold.trigger_load_events(this.target.next().select('[data-as_load]'));
996
1003
  this.set_adapter(this.target.next());
997
1004
  }
998
1005
  else if (this.position == 'before') {
999
- this.target.insert({before:this.wrap_with_adapter_html(content)});
1006
+ this.target.insert({before:this.wrap_with_adapter_html(content, should_refresh_data)});
1000
1007
  ActiveScaffold.trigger_load_events(this.target.previous().select('[data-as_load]'));
1001
1008
  this.set_adapter(this.target.previous());
1002
1009
  }
@@ -1029,12 +1036,13 @@ ActiveScaffold.ActionLink.Record = Class.create(ActiveScaffold.ActionLink.Abstra
1029
1036
  },
1030
1037
 
1031
1038
  set_opened: function() {
1039
+ var should_refresh_data = (typeof(this.refresh_ur)== 'undefined');
1032
1040
  if (this.position == 'after') {
1033
- var new_adapter = ActiveScaffold.replace(this.target.next(), this.wrap_with_adapter_html(this.target.next().childElements().first().innerHTML), true);
1041
+ var new_adapter = ActiveScaffold.replace(this.target.next(), this.wrap_with_adapter_html(this.target.next().childElements().first().innerHTML, should_refresh_data), true);
1034
1042
  this.set_adapter(new_adapter);
1035
1043
  }
1036
1044
  else if (this.position == 'before') {
1037
- var new_adapter = ActiveScaffold.replace(this.target.previous(), this.wrap_with_adapter_html(this.target.previous().childElements().first().innerHTML), true);
1045
+ var new_adapter = ActiveScaffold.replace(this.target.previous(), this.wrap_with_adapter_html(this.target.previous().childElements().first().innerHTML, should_refresh_data), true);
1038
1046
  this.set_adapter(new_adapter);
1039
1047
  }
1040
1048
  this.disable();
@@ -1055,7 +1063,7 @@ ActiveScaffold.Actions.Table = Class.create(ActiveScaffold.Actions.Abstract, {
1055
1063
  ActiveScaffold.ActionLink.Table = Class.create(ActiveScaffold.ActionLink.Abstract, {
1056
1064
  insert: function(content) {
1057
1065
  if (this.position == 'top') {
1058
- this.target.insert({top:this.wrap_with_adapter_html(content)});
1066
+ this.target.insert({top:this.wrap_with_adapter_html(content, false)});
1059
1067
  ActiveScaffold.trigger_load_events(this.target.immediateDescendants().first().select('[data-as_load]'));
1060
1068
  this.set_adapter(this.target.immediateDescendants().first());
1061
1069
  }
@@ -528,7 +528,7 @@ background-color: #005CB8;
528
528
  color: #ccc;
529
529
  }
530
530
 
531
- .active-scaffold-footer .active-scaffold-pagination {
531
+ .active-scaffold-footer .pagination {
532
532
  float: right;
533
533
  white-space: nowrap;
534
534
  margin-right: 5px;
@@ -8,7 +8,7 @@
8
8
  <%= render :partial => 'list_messages', :locals => {:columns => columns} %>
9
9
  <tbody class="records" id="<%= active_scaffold_tbody_id %>">
10
10
  <% if !@records.empty? -%>
11
- <%= render :partial => 'list_record', :collection => @page.items, :locals => { :hidden => false, :columns => columns, :action_links => active_scaffold_config.action_links.member} %>
11
+ <%= render :partial => 'list_record', :collection => @records, :locals => { :hidden => false, :columns => columns, :action_links => active_scaffold_config.action_links.member} %>
12
12
  <% end -%>
13
13
  <% if columns.any? {|c| c.calculation?} -%>
14
14
  <%= render :partial => 'list_calculations', :locals => {:columns => columns} %>
@@ -16,3 +16,4 @@
16
16
  </tbody>
17
17
  </table>
18
18
  <%= render :partial => 'list_pagination' %>
19
+ <% save_current_page_num %>
@@ -11,7 +11,7 @@
11
11
  <p class="filtered-message" <%= ' style="display:none;" '.html_safe unless @filtered %>>
12
12
  <%= @filtered.is_a?(Array) ? render(:partial => 'human_conditions', :locals => {:columns => @filtered}) : as_(active_scaffold_config.list.filtered_message) %>
13
13
  </p>
14
- <p id="<%= empty_message_id %>" class="empty-message" <%= ' style="display:none;" '.html_safe unless @page.items.empty? %>>
14
+ <p id="<%= empty_message_id %>" class="empty-message" <%= ' style="display:none;" '.html_safe unless @records.empty? %>>
15
15
  <%= as_(active_scaffold_config.list.no_entries_message) %>
16
16
  </p>
17
17
  </td>
@@ -23,7 +23,7 @@
23
23
  action_links.add(search_link) -%>
24
24
  <%= render :partial => 'list_actions', :locals => {:record => record, :url_options => params_for(:escape => false, :search => ''), :action_links => action_links.member} %>
25
25
  <% else %>
26
- <td class='actions'><%= '<p class="empty-message">&nbsp;</p>'.html_safe if @page.items.empty? %></td>
26
+ <td class='actions'><%= '<p class="empty-message">&nbsp;</p>'.html_safe if @records.empty? %></td>
27
27
  <% end -%>
28
28
 
29
29
  </tr>
@@ -1,11 +1,8 @@
1
1
  <% if active_scaffold_config.list.pagination -%>
2
2
  <div class="active-scaffold-footer">
3
- <% unless @page.pager.infinite? -%>
4
- <div class="active-scaffold-found"><span class="active-scaffold-records"><%= @page.pager.count -%></span> <%=as_(:found, :count => @page.pager.count) %></div>
3
+ <% unless active_scaffold_config.list.pagination == :infinite -%>
4
+ <div class="active-scaffold-found"><span class="active-scaffold-records"><%= @records.total_count -%></span> <%=as_(:found, :count => @records.total_count) %></div>
5
5
  <% end -%>
6
- <div class="active-scaffold-pagination">
7
- <%= render :partial => 'list_pagination_links', :locals => { :current_page => @page } if @page.pager.infinite? || @page.pager.number_of_pages > 1 %>
8
- </div>
9
- <br clear="both" /><%# a hack for the Rico Corner problem %>
6
+ <%= paginate @records, :window => active_scaffold_config.list.page_links_window, :params => params_for(:action => :index), :remote => true %>
10
7
  </div>
11
8
  <% end -%>
@@ -1,5 +1,5 @@
1
1
  <% columns.each do |column| %>
2
- <% authorized = record.authorized_for?(:crud_type => :read, :column => column.name) -%>
2
+ <% authorized = record.authorized_for_read_column?(column.name) -%>
3
3
  <% column_value = authorized ? get_column_value(record, column) : active_scaffold_config.list.empty_field_text -%>
4
4
 
5
5
  <td class="<%= column_class(column, column_value, record) %>" >
@@ -3,6 +3,7 @@ module ActiveScaffold::Actions
3
3
  def self.included(base)
4
4
  base.before_filter :list_authorized_filter, :only => [:index, :row]
5
5
  base.helper_method :list_columns
6
+ base.helper_method :save_current_page_num
6
7
  end
7
8
 
8
9
  def index
@@ -73,12 +74,8 @@ module ActiveScaffold::Actions
73
74
  })
74
75
  end
75
76
 
76
- page = find_page(options);
77
- if page.items.blank? && !page.pager.infinite?
78
- page = page.pager.last
79
- active_scaffold_config.list.user.page = page.number
80
- end
81
- @page, @records = page, page.items
77
+ @records = find_page(options);
78
+ @records
82
79
  end
83
80
 
84
81
  def each_record_in_page
@@ -174,6 +171,10 @@ module ActiveScaffold::Actions
174
171
  (default_formats + active_scaffold_config.formats).uniq
175
172
  end
176
173
 
174
+ def save_current_page_num
175
+ active_scaffold_config.list.user.page = @records.current_page unless active_scaffold_config.list.pagination == false
176
+ end
177
+
177
178
  private
178
179
  def list_authorized_filter
179
180
  raise ActiveScaffold::ActionNotAllowed unless list_authorized?
@@ -64,6 +64,7 @@ module ActiveRecordPermissions
64
64
  def self.included(base)
65
65
  base.extend SecurityMethods
66
66
  base.send :include, SecurityMethods
67
+ base.class_attribute :auth_column_read_methods
67
68
  end
68
69
 
69
70
  # Because any class-level queries get delegated to the instance level via a new record,
@@ -110,6 +111,30 @@ module ActiveRecordPermissions
110
111
  return ActiveRecordPermissions.default_permission
111
112
  end
112
113
 
114
+ def authorized_for_read_column?(column)
115
+ self.class.auth_column_read_methods ||= {}
116
+ methods = self.class.auth_column_read_methods[column]
117
+ if methods.nil?
118
+ method = column_and_crud_type_security_method(column, :read)
119
+ methods = if method && respond_to?(method)
120
+ [method]
121
+ else
122
+ [column_security_method(column),
123
+ crud_type_security_method(:read)].compact.select {|m| respond_to?(m)}
124
+ end
125
+ self.class.auth_column_read_methods[column] = methods
126
+ end
127
+
128
+ # if any method returns false, then return false
129
+ return false if methods.any? {|m| !send(m)}
130
+
131
+ # if any method actually exists then it must've returned true, so return true
132
+ return true unless methods.empty?
133
+
134
+ # if no method exists, return the default permission
135
+ return ActiveRecordPermissions.default_permission
136
+ end
137
+
113
138
  private
114
139
 
115
140
  def column_security_method(column)
@@ -135,8 +135,11 @@ module ActiveScaffold
135
135
  # convert empty strings into nil. this works better with 'null => true' columns (and validations),
136
136
  # and 'null => false' columns should just convert back to an empty string.
137
137
  # ... but we can at least check the ConnectionAdapter::Column object to see if nulls are allowed
138
- value = nil if value.is_a? String and value.empty? and !column.column.nil? and column.column.null
139
- value
138
+ if value.is_a? String and value.empty? and !column.column.nil? and column.column.null
139
+ nil
140
+ else
141
+ column.stripped_value(value)
142
+ end
140
143
  end
141
144
  end
142
145
 
@@ -73,13 +73,13 @@ module ActiveScaffold
73
73
  range_type, range = value[:range].downcase.split('_')
74
74
  format = active_scaffold_human_condition_date_bridge_range_format(range_type, range)
75
75
  from, to = controller.class.date_bridge_from_to(column, value)
76
- "#{column.active_record_class.human_attribute_name(column.name)} = #{as_(value[:range].downcase).downcase} (#{I18n.l(from, :format => format)})"
76
+ "#{column.active_record_class.human_attribute_name(column.name)} = #{as_(value[:range].downcase).downcase} (#{I18n.l(from, :format => format)})" unless from.nil?
77
77
  when 'PAST', 'FUTURE'
78
78
  from, to = controller.class.date_bridge_from_to(column, value)
79
- "#{column.active_record_class.human_attribute_name(column.name)} #{as_('BETWEEN'.downcase).downcase} #{I18n.l(from)} - #{I18n.l(to)}"
79
+ "#{column.active_record_class.human_attribute_name(column.name)} #{as_('BETWEEN'.downcase).downcase} #{I18n.l(from)} - #{I18n.l(to)}" unless from.nil? || to.nil?
80
80
  else
81
81
  from, to = controller.class.date_bridge_from_to(column, value)
82
- "#{column.active_record_class.human_attribute_name(column.name)} #{as_(value[:opt].downcase).downcase} #{I18n.l(from)} #{value[:opt] == 'BETWEEN' ? '- ' + I18n.l(to) : ''}"
82
+ "#{column.active_record_class.human_attribute_name(column.name)} #{as_(value[:opt].downcase).downcase} #{I18n.l(from)} #{value[:opt] == 'BETWEEN' ? '- ' + I18n.l(to) : ''}" unless from.nil? || (value[:opt] == 'BETWEEN' && to.nil?)
83
83
  end
84
84
  end
85
85
 
@@ -7,7 +7,7 @@ document.on('as:form_loaded', 'form.as_form', function(event) {
7
7
  });
8
8
  document.on('as:form_submit', 'form.as_form', function(event) {
9
9
  var as_form = event.findElement('form');
10
- if (as_form.has('textarea.mceEditor').length > 0) {
10
+ if (as_form.select('textarea.mceEditor').length > 0) {
11
11
  tinyMCE.triggerSave();
12
12
  }
13
13
  return true;
@@ -167,7 +167,14 @@ module ActiveScaffold::Config
167
167
  klass = "ActiveScaffold::Config::#{titled_name}".constantize rescue nil
168
168
  if klass
169
169
  if @actions.include? underscored_name
170
- return @action_configs[underscored_name] ||= klass.new(self)
170
+ @action_configs[name] ||= klass.new(self)
171
+ eigenclass = class << self; self; end
172
+ eigenclass.class_eval do
173
+ define_method(name) do
174
+ @action_configs[name]
175
+ end
176
+ end
177
+ return send(name)
171
178
  else
172
179
  raise "#{titled_name} is not enabled. Please enable it or remove any references in your configuration (e.g. config.#{underscored_name}.columns = [...])."
173
180
  end
@@ -6,6 +6,7 @@ module ActiveScaffold::Config
6
6
  @core = core_config
7
7
 
8
8
  @text_search = self.class.text_search
9
+ @or_delimiter = self.class.or_delimiter
9
10
 
10
11
  # start with the ActionLink defined globally
11
12
  @link = self.class.link.clone
@@ -28,6 +29,11 @@ module ActiveScaffold::Config
28
29
  cattr_accessor :text_search
29
30
  @@text_search = :full
30
31
 
32
+ # delimiter to seperate or search string such us: name = Paul,Bernd,Klaus
33
+ # will search for Paul Or Bernd Or Klaus
34
+ cattr_accessor :or_delimiter
35
+ @@or_delimiter = ','
36
+
31
37
  # instance-level configuration
32
38
  # ----------------------------
33
39
 
@@ -50,18 +56,33 @@ module ActiveScaffold::Config
50
56
  # * false: LIKE ?
51
57
  # Default is :full
52
58
  attr_accessor :text_search
59
+
60
+ attr_accessor :or_delimiter
53
61
 
54
62
  # the ActionLink for this action
55
63
  attr_accessor :link
56
64
 
57
65
  # rarely searched columns may be placed in a hidden subgroup
58
- def optional_columns=(optionals)
66
+ def optional_columns=(optionals)
59
67
  @optional_columns= Array(optionals)
60
68
  end
61
69
 
62
70
  def optional_columns
63
71
  @optional_columns ||= []
64
72
  end
73
+
74
+ # columns which should support or searches
75
+ # eg like 'x' or ... like 'y'
76
+ def or_columns=(or_columns)
77
+ @or_columns = Array(or_columns)
78
+ end
79
+
80
+ def or_columns
81
+ unless @or_columns
82
+ self.or_columns = @core.columns.collect{|c| c.name if @core.columns._inheritable.include?(c.name) and c.searchable? and c.column and c.column.text?}.compact
83
+ end
84
+ @or_columns
85
+ end
65
86
 
66
87
  # default search params
67
88
  # default_params = {:title => {"from"=>"test", "to"=>"", "opt"=>"%?%"}}
@@ -181,6 +181,17 @@ module ActiveScaffold::DataStructures
181
181
  # to modify the default order of columns
182
182
  attr_accessor :weight
183
183
 
184
+ # whether the field should be stripped when search values or form values are read for this value
185
+ attr_writer :stripable
186
+ def stripable?
187
+ @stripable
188
+ end
189
+
190
+ def stripped_value(value)
191
+ stripable? ? value.strip : value
192
+ end
193
+
194
+
184
195
  # to set how many associated records a column with plural association must show in list
185
196
  cattr_accessor :associated_limit
186
197
  @@associated_limit = 3
@@ -228,6 +239,11 @@ module ActiveScaffold::DataStructures
228
239
  def plural_association?
229
240
  self.association and [:has_many, :has_and_belongs_to_many].include? self.association.macro
230
241
  end
242
+
243
+ def belongs_to_association?
244
+ self.association && self.association.macro == :belongs_to
245
+ end
246
+
231
247
  def through_association?
232
248
  self.association and self.association.options[:through]
233
249
  end
@@ -278,6 +294,7 @@ module ActiveScaffold::DataStructures
278
294
  @options = {:format => :i18n_number} if @column.try(:number?)
279
295
  @form_ui = :checkbox if @column and @column.type == :boolean
280
296
  @form_ui = :textarea if @column and @column.type == :text
297
+ @stripable = true if @column and @column.text?
281
298
  @allow_add_existing = true
282
299
  @form_ui = self.class.association_form_ui if @association && self.class.association_form_ui
283
300
 
@@ -311,7 +328,7 @@ module ActiveScaffold::DataStructures
311
328
  self.sort = false
312
329
  else
313
330
  if self.singular_association?
314
- self.sort = {:method => "#{self.name}.to_label"}
331
+ self.sort = {:method => "#{self.name}.nil? ? '' : #{self.name}.to_label"}
315
332
  elsif self.plural_association?
316
333
  self.sort = {:method => "#{self.name}.join(',')"}
317
334
  else
@@ -322,7 +339,7 @@ module ActiveScaffold::DataStructures
322
339
 
323
340
  def initialize_search_sql
324
341
  self.search_sql = unless self.virtual?
325
- if association.nil?
342
+ if association.nil? || self.belongs_to_association?
326
343
  self.field.to_s
327
344
  elsif !self.polymorphic_association?
328
345
  [association.klass.table_name, association.klass.primary_key].collect! do |str|
@@ -83,21 +83,28 @@ module ActiveScaffold
83
83
  end
84
84
  end
85
85
 
86
+
86
87
  def condition_for_range(column, value, like_pattern = nil)
87
88
  if !value.is_a?(Hash)
88
89
  if column.column.nil? || column.column.text?
89
- ["#{column.search_sql} #{ActiveScaffold::Finder.like_operator} ?", like_pattern.sub('?', value)]
90
+ ["#{column.search_sql} #{ActiveScaffold::Finder.like_operator} ?", like_pattern.sub('?', column.stripped_value(value))]
90
91
  else
91
92
  ["#{column.search_sql} = ?", column.column.type_cast(value)]
92
93
  end
93
94
  elsif value[:from].blank?
94
95
  nil
95
96
  elsif ActiveScaffold::Finder::StringComparators.values.include?(value[:opt])
96
- ["#{column.search_sql} #{ActiveScaffold::Finder.like_operator} ?", value[:opt].sub('?', value[:from])]
97
+ if(active_scaffold_config.field_search.or_columns.include? column.name)
98
+ search_values = column.stripped_value(value[:from]).split(active_scaffold_config.field_search.or_delimiter).compact
99
+ sql_prepared_statement = search_values.collect {|search_value| "#{column.search_sql} #{ActiveScaffold::Finder.like_operator} ?"}.join(' OR ')
100
+ [sql_prepared_statement] + search_values.collect{|search_value| value[:opt].sub('?', column.stripped_value(search_value))}
101
+ else
102
+ ["#{column.search_sql} #{ActiveScaffold::Finder.like_operator} ?", value[:opt].sub('?', column.stripped_value(value[:from]))]
103
+ end
97
104
  elsif value[:opt] == 'BETWEEN'
98
- ["#{column.search_sql} BETWEEN ? AND ?", value[:from], value[:to]]
105
+ ["#{column.search_sql} BETWEEN ? AND ?", column.stripped_value(value[:from]), column.stripped_value(value[:to])]
99
106
  elsif ActiveScaffold::Finder::NumericComparators.include?(value[:opt])
100
- ["#{column.search_sql} #{value[:opt]} ?", value[:from]]
107
+ ["#{column.search_sql} #{value[:opt]} ?", column.stripped_value(value[:from])]
101
108
  else
102
109
  nil
103
110
  end
@@ -243,7 +250,7 @@ module ActiveScaffold
243
250
  return record
244
251
  end
245
252
 
246
- # returns a Paginator::Page (not from ActiveRecord::Paginator) for the given parameters
253
+ # returns a records relation for the current page
247
254
  # options may include:
248
255
  # * :sorting - a Sorting DataStructure (basically an array of hashes of field => direction, e.g. [{:field1 => 'asc'}, {:field2 => 'desc'}]). please note that multi-column sorting has some limitations: if any column in a multi-field sort uses method-based sorting, it will be ignored. method sorting only works for single-column sorting.
249
256
  # * :per_page
@@ -256,6 +263,7 @@ module ActiveScaffold
256
263
  full_includes = (active_scaffold_includes.blank? ? nil : active_scaffold_includes)
257
264
  options[:per_page] ||= 999999999
258
265
  options[:page] ||= 1
266
+ #TODO not supported by kaminari
259
267
  options[:count_includes] ||= full_includes unless search_conditions.nil?
260
268
 
261
269
  klass = beginning_of_chain
@@ -264,37 +272,19 @@ module ActiveScaffold
264
272
  finder_options = { :order => options[:sorting].try(:clause),
265
273
  :where => search_conditions,
266
274
  :joins => joins_for_finder,
267
- :includes => options[:count_includes]}
275
+ :includes => add_association_to_includes_for_sorting(options[:sorting], full_includes)}
268
276
 
269
277
 
270
278
  finder_options.merge! custom_finder_options
271
279
 
272
- # NOTE: we must use :include in the count query, because some conditions may reference other tables
273
- count_query = append_to_query(klass, finder_options.reject{|k, v| [:select, :order].include?(k)})
274
- count = count_query.count unless options[:pagination] == :infinite
275
-
276
- # Converts count to an integer if ActiveRecord returned an OrderedHash
277
- # that happens when finder_options contains a :group key
278
- count = count.length if count.is_a? ActiveSupport::OrderedHash
279
-
280
- full_includes = add_association_to_includes_for_sorting(options[:sorting], full_includes)
281
-
282
- finder_options.merge! :includes => full_includes
283
-
284
280
  # we build the paginator differently for method- and sql-based sorting
285
- if options[:sorting] and options[:sorting].sorts_by_method?
286
- pager = ::Paginator.new(count, options[:per_page]) do |offset, per_page|
287
- sorted_collection = sort_collection_by_column(append_to_query(klass, finder_options).all, *options[:sorting].first)
288
- sorted_collection = sorted_collection.slice(offset, per_page) if options[:pagination]
289
- sorted_collection
290
- end
281
+ records = if options[:sorting] && options[:sorting].sorts_by_method?
282
+ Kaminari.paginate_array(sort_collection_by_column(append_to_query(klass, finder_options).all, *options[:sorting].first))
291
283
  else
292
- pager = ::Paginator.new(count, options[:per_page]) do |offset, per_page|
293
- finder_options.merge!(:offset => offset, :limit => per_page) if options[:pagination]
294
- append_to_query(klass, finder_options).all
295
- end
284
+ append_to_query(klass, finder_options)
296
285
  end
297
- pager.page(options[:page])
286
+ records = records.page(options[:page]).per(options[:per_page]) if options[:pagination]
287
+ records
298
288
  end
299
289
 
300
290
  # if someone excludes association from includes in configuration
@@ -349,7 +339,6 @@ module ActiveScaffold
349
339
 
350
340
  # TODO: this should reside on the column, not the controller
351
341
  def sort_collection_by_column(collection, column, order)
352
- Rails.logger.info("das hier ja was bin im sort_collection")
353
342
  sorter = column.sort[:method]
354
343
  collection = collection.sort_by { |record|
355
344
  value = (sorter.is_a? Proc) ? record.instance_eval(&sorter) : record.instance_eval(sorter)