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.
- data/.gitignore +42 -0
- data/Gemfile +1 -10
- data/Gemfile.lock +78 -10
- data/Rakefile +19 -17
- data/active_scaffold_vho.gemspec +14 -324
- data/frontends/default/javascripts/jquery/active_scaffold.js +23 -13
- data/frontends/default/javascripts/prototype/active_scaffold.js +22 -14
- data/frontends/default/stylesheets/stylesheet.css +1 -1
- data/frontends/default/views/_list.html.erb +2 -1
- data/frontends/default/views/_list_messages.html.erb +2 -2
- data/frontends/default/views/_list_pagination.html.erb +3 -6
- data/frontends/default/views/_list_record_columns.html.erb +1 -1
- data/lib/active_scaffold/actions/list.rb +7 -6
- data/lib/active_scaffold/active_record_permissions.rb +25 -0
- data/lib/active_scaffold/attribute_params.rb +5 -2
- data/lib/active_scaffold/bridges/shared/date_bridge.rb +3 -3
- data/lib/active_scaffold/bridges/tiny_mce/public/javascripts/prototype/tiny_mce_bridge.js +1 -1
- data/lib/active_scaffold/config/core.rb +8 -1
- data/lib/active_scaffold/config/field_search.rb +22 -1
- data/lib/active_scaffold/data_structures/column.rb +19 -2
- data/lib/active_scaffold/finder.rb +19 -30
- data/lib/active_scaffold/helpers/human_condition_helpers.rb +4 -2
- data/lib/active_scaffold/helpers/list_column_helpers.rb +9 -2
- data/lib/active_scaffold/locale/de.yml +118 -0
- data/lib/active_scaffold/locale/en.yml +115 -0
- data/lib/active_scaffold/version.rb +1 -1
- data/lib/active_scaffold.rb +0 -1
- data/test/mock_app/public/stylesheets/active_scaffold/default/stylesheet.css +1 -1
- metadata +102 -62
- data/lib/active_scaffold/locale/de.rb +0 -120
- 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.
|
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
|
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
|
-
|
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
|
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
|
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="
|
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
|
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
|
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
|
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
|
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
|
-
|
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
|
-
|
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="
|
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
|
}
|
@@ -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 => @
|
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 @
|
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"> </p>'.html_safe if @
|
26
|
+
<td class='actions'><%= '<p class="empty-message"> </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
|
4
|
-
<div class="active-scaffold-found"><span class="active-scaffold-records"><%= @
|
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
|
-
|
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.
|
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
|
-
|
77
|
-
|
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
|
-
|
139
|
-
|
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.
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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[:
|
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]
|
286
|
-
|
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
|
-
|
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
|
-
|
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)
|