active_scaffold_vho 3.0.26 → 3.0.27

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 (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)