active_scaffold 3.3.3 → 3.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +39 -0
- data/README.md +5 -3
- data/app/assets/images/active_scaffold/refresh.png +0 -0
- data/app/assets/javascripts/jquery/active_scaffold.js +182 -91
- data/app/assets/javascripts/jquery/date_picker_bridge.js.erb +14 -16
- data/app/assets/javascripts/jquery/draggable_lists.js +33 -26
- data/app/assets/javascripts/jquery/jquery.editinplace.js +3 -3
- data/app/assets/javascripts/prototype/active_scaffold.js +61 -19
- data/app/assets/stylesheets/active_scaffold_colors.css.scss +4 -0
- data/app/assets/stylesheets/active_scaffold_images.css.scss +3 -0
- data/app/assets/stylesheets/active_scaffold_layout.css +23 -2
- data/app/views/active_scaffold_overrides/_add_existing_form.html.erb +1 -3
- data/app/views/active_scaffold_overrides/_base_form.html.erb +7 -5
- data/app/views/active_scaffold_overrides/_field_search.html.erb +1 -2
- data/app/views/active_scaffold_overrides/_form.html.erb +6 -4
- data/app/views/active_scaffold_overrides/_form_association.html.erb +4 -3
- data/app/views/active_scaffold_overrides/_form_association_footer.html.erb +5 -5
- data/app/views/active_scaffold_overrides/_form_association_record.html.erb +8 -6
- data/app/views/active_scaffold_overrides/_horizontal_subform_header.html.erb +3 -2
- data/app/views/active_scaffold_overrides/_list.html.erb +8 -6
- data/app/views/active_scaffold_overrides/_list_column_headings.html.erb +1 -4
- data/app/views/active_scaffold_overrides/_list_pagination.html.erb +4 -4
- data/app/views/active_scaffold_overrides/_list_pagination_links.html.erb +1 -1
- data/app/views/active_scaffold_overrides/_list_record.html.erb +3 -3
- data/app/views/active_scaffold_overrides/_refresh_list.js.erb +8 -1
- data/app/views/active_scaffold_overrides/_search.html.erb +7 -13
- data/app/views/active_scaffold_overrides/_show_columns.html.erb +1 -1
- data/app/views/active_scaffold_overrides/on_create.js.erb +4 -4
- data/app/views/active_scaffold_overrides/render_field_inplace.html.erb +1 -1
- data/app/views/active_scaffold_overrides/row.js.erb +1 -1
- data/config/locales/de.yml +106 -95
- data/config/locales/en.yml +108 -97
- data/config/locales/es.yml +109 -98
- data/config/locales/fr.yml +108 -97
- data/config/locales/hu.yml +109 -98
- data/config/locales/ja.yml +100 -89
- data/config/locales/ru.yml +115 -104
- data/lib/active_scaffold.rb +18 -294
- data/lib/active_scaffold/actions/common_search.rb +50 -17
- data/lib/active_scaffold/actions/core.rb +93 -22
- data/lib/active_scaffold/actions/create.rb +15 -6
- data/lib/active_scaffold/actions/field_search.rb +68 -60
- data/lib/active_scaffold/actions/list.rb +49 -28
- data/lib/active_scaffold/actions/nested.rb +14 -6
- data/lib/active_scaffold/actions/search.rb +36 -35
- data/lib/active_scaffold/actions/show.rb +9 -4
- data/lib/active_scaffold/actions/subform.rb +1 -1
- data/lib/active_scaffold/actions/update.rb +22 -7
- data/lib/active_scaffold/active_record_permissions.rb +125 -118
- data/lib/active_scaffold/attribute_params.rb +84 -66
- data/lib/active_scaffold/bridges.rb +3 -3
- data/lib/active_scaffold/bridges/ancestry/ancestry_bridge.rb +10 -5
- data/lib/active_scaffold/bridges/cancan.rb +2 -1
- data/lib/active_scaffold/bridges/cancan/cancan_bridge.rb +13 -2
- data/lib/active_scaffold/bridges/carrierwave/form_ui.rb +11 -6
- data/lib/active_scaffold/bridges/chosen/helpers.rb +2 -2
- data/lib/active_scaffold/bridges/country_helper/country_helper_bridge.rb +45 -29
- data/lib/active_scaffold/bridges/date_picker/ext.rb +11 -6
- data/lib/active_scaffold/bridges/date_picker/helper.rb +5 -1
- data/lib/active_scaffold/bridges/dragonfly/form_ui.rb +10 -5
- data/lib/active_scaffold/bridges/dragonfly/list_ui.rb +6 -1
- data/lib/active_scaffold/bridges/file_column/form_ui.rb +12 -11
- data/lib/active_scaffold/bridges/paperclip/form_ui.rb +14 -6
- data/lib/active_scaffold/bridges/paperclip/list_ui.rb +1 -1
- data/lib/active_scaffold/bridges/record_select/helpers.rb +15 -12
- data/lib/active_scaffold/bridges/shared/date_bridge.rb +7 -8
- data/lib/active_scaffold/bridges/tiny_mce.rb +5 -3
- data/lib/active_scaffold/bridges/tiny_mce/helpers.rb +4 -5
- data/lib/active_scaffold/config/base.rb +4 -0
- data/lib/active_scaffold/config/core.rb +12 -5
- data/lib/active_scaffold/config/delete.rb +0 -2
- data/lib/active_scaffold/config/field_search.rb +1 -4
- data/lib/active_scaffold/config/form.rb +0 -2
- data/lib/active_scaffold/config/list.rb +31 -1
- data/lib/active_scaffold/config/search.rb +0 -3
- data/lib/active_scaffold/config/show.rb +0 -6
- data/lib/active_scaffold/config/subform.rb +1 -0
- data/lib/active_scaffold/configurable.rb +2 -2
- data/lib/active_scaffold/constraints.rb +11 -14
- data/lib/active_scaffold/core.rb +277 -0
- data/lib/active_scaffold/data_structures/action_columns.rb +18 -2
- data/lib/active_scaffold/data_structures/action_link.rb +25 -6
- data/lib/active_scaffold/data_structures/action_links.rb +9 -4
- data/lib/active_scaffold/data_structures/actions.rb +1 -1
- data/lib/active_scaffold/data_structures/column.rb +6 -6
- data/lib/active_scaffold/data_structures/columns.rb +2 -2
- data/lib/active_scaffold/data_structures/nested_info.rb +5 -1
- data/lib/active_scaffold/data_structures/sorting.rb +15 -5
- data/lib/active_scaffold/delayed_setup.rb +30 -0
- data/lib/active_scaffold/engine.rb +25 -0
- data/lib/active_scaffold/extensions/action_view_rendering.rb +1 -1
- data/lib/active_scaffold/extensions/left_outer_joins.rb +61 -21
- data/lib/active_scaffold/extensions/localize.rb +1 -1
- data/lib/active_scaffold/extensions/name_option_for_datetime.rb +13 -8
- data/lib/active_scaffold/extensions/paginator_extensions.rb +5 -1
- data/lib/active_scaffold/extensions/reverse_associations.rb +1 -0
- data/lib/active_scaffold/extensions/routing_mapper.rb +1 -1
- data/lib/active_scaffold/extensions/unsaved_record.rb +4 -6
- data/lib/active_scaffold/finder.rb +79 -27
- data/lib/active_scaffold/helpers/association_helpers.rb +48 -18
- data/lib/active_scaffold/helpers/controller_helpers.rb +19 -10
- data/lib/active_scaffold/helpers/form_column_helpers.rb +185 -87
- data/lib/active_scaffold/helpers/human_condition_helpers.rb +2 -1
- data/lib/active_scaffold/helpers/id_helpers.rb +14 -8
- data/lib/active_scaffold/helpers/list_column_helpers.rb +65 -56
- data/lib/active_scaffold/helpers/pagination_helpers.rb +5 -1
- data/lib/active_scaffold/helpers/search_column_helpers.rb +21 -18
- data/lib/active_scaffold/helpers/view_helpers.rb +102 -64
- data/lib/active_scaffold/responds_to_parent.rb +39 -64
- data/lib/active_scaffold/tableless.rb +129 -10
- data/lib/active_scaffold/version.rb +2 -2
- data/test/bridges/bridge_test.rb +1 -1
- data/test/bridges/date_picker_test.rb +2 -2
- data/test/bridges/paperclip_test.rb +10 -8
- data/test/bridges/tiny_mce_test.rb +2 -2
- data/test/company.rb +22 -10
- data/test/config/base_test.rb +1 -1
- data/test/config/core_test.rb +8 -6
- data/test/config/create_test.rb +6 -6
- data/test/config/delete_test.rb +4 -4
- data/test/config/field_search_test.rb +6 -6
- data/test/config/list_test.rb +7 -7
- data/test/config/nested_test.rb +8 -7
- data/test/config/search_test.rb +7 -7
- data/test/config/show_test.rb +5 -5
- data/test/config/subform_test.rb +1 -1
- data/test/config/update_test.rb +5 -4
- data/test/data_structures/action_columns_test.rb +15 -16
- data/test/data_structures/action_link_test.rb +10 -10
- data/test/data_structures/action_links_test.rb +6 -6
- data/test/data_structures/actions_test.rb +4 -4
- data/test/data_structures/association_column_test.rb +4 -4
- data/test/data_structures/column_test.rb +9 -9
- data/test/data_structures/columns_test.rb +7 -7
- data/test/data_structures/error_message_test.rb +2 -4
- data/test/data_structures/set_test.rb +13 -13
- data/test/data_structures/sorting_test.rb +8 -8
- data/test/data_structures/standard_column_test.rb +2 -2
- data/test/data_structures/validation_reflection_test.rb +8 -8
- data/test/data_structures/virtual_column_test.rb +5 -5
- data/test/extensions/active_record_test.rb +1 -1
- data/test/helpers/form_column_helpers_test.rb +5 -5
- data/test/helpers/list_column_helpers_test.rb +2 -1
- data/test/helpers/pagination_helpers_test.rb +1 -1
- data/test/misc/active_record_permissions_test.rb +23 -4
- data/test/misc/attribute_params_test.rb +304 -136
- data/test/misc/calculation_test.rb +55 -0
- data/test/misc/configurable_test.rb +22 -21
- data/test/misc/constraints_test.rb +10 -7
- data/test/misc/convert_numbers_format_test.rb +149 -0
- data/test/misc/finder_test.rb +17 -13
- data/test/misc/lang_test.rb +1 -1
- data/test/misc/tableless_test.rb +18 -0
- data/test/mock_app/app/controllers/addresses_controller.rb +4 -0
- data/test/mock_app/app/controllers/buildings_controller.rb +4 -0
- data/test/mock_app/app/controllers/cars_controller.rb +4 -0
- data/test/mock_app/app/controllers/contacts_controller.rb +4 -0
- data/test/mock_app/app/controllers/floors_controller.rb +6 -0
- data/test/mock_app/app/controllers/people_controller.rb +4 -0
- data/test/mock_app/app/models/address.rb +3 -0
- data/test/mock_app/app/models/building.rb +8 -0
- data/test/mock_app/app/models/car.rb +3 -0
- data/test/mock_app/app/models/contact.rb +3 -0
- data/test/mock_app/app/models/file_model.rb +19 -0
- data/test/mock_app/app/models/floor.rb +8 -0
- data/test/mock_app/app/models/person.rb +11 -0
- data/test/mock_app/config/application.rb +2 -0
- data/test/mock_app/config/environments/test.rb +1 -1
- data/test/mock_app/config/initializers/secret_token.rb +5 -1
- data/test/mock_app/config/routes.rb +1 -1
- data/test/mock_app/db/schema.rb +51 -0
- data/test/model_stub.rb +3 -3
- data/test/test_helper.rb +15 -12
- metadata +51 -50
- data/lib/active_scaffold/extensions/array.rb +0 -7
- data/lib/active_scaffold/extensions/cache_association.rb +0 -16
- data/lib/active_scaffold/extensions/usa_state.rb +0 -46
- data/lib/active_scaffold_env.rb +0 -13
- data/test/extensions/array_test.rb +0 -12
- data/test/mock_app/public/blank.html +0 -33
- data/test/mock_app/public/images/active_scaffold/DO_NOT_EDIT +0 -2
- data/test/mock_app/public/images/active_scaffold/default/add.gif +0 -0
- data/test/mock_app/public/images/active_scaffold/default/arrow_down.gif +0 -0
- data/test/mock_app/public/images/active_scaffold/default/arrow_up.gif +0 -0
- data/test/mock_app/public/images/active_scaffold/default/close.gif +0 -0
- data/test/mock_app/public/images/active_scaffold/default/cross.png +0 -0
- data/test/mock_app/public/images/active_scaffold/default/indicator-small.gif +0 -0
- data/test/mock_app/public/images/active_scaffold/default/indicator.gif +0 -0
- data/test/mock_app/public/images/active_scaffold/default/magnifier.png +0 -0
- data/test/mock_app/public/javascripts/active_scaffold/DO_NOT_EDIT +0 -2
- data/test/mock_app/public/javascripts/active_scaffold/default/active_scaffold.js +0 -532
- data/test/mock_app/public/javascripts/active_scaffold/default/dhtml_history.js +0 -867
- data/test/mock_app/public/javascripts/active_scaffold/default/form_enhancements.js +0 -117
- data/test/mock_app/public/javascripts/active_scaffold/default/rico_corner.js +0 -370
- data/test/mock_app/public/stylesheets/active_scaffold/DO_NOT_EDIT +0 -2
- data/test/mock_app/public/stylesheets/active_scaffold/default/stylesheet-ie.css +0 -35
- data/test/mock_app/public/stylesheets/active_scaffold/default/stylesheet.css +0 -848
@@ -29,23 +29,22 @@ module ActiveScaffold
|
|
29
29
|
active_scaffold_search_date_bridge_calendar_control(column, options, current_search, 'from') <<
|
30
30
|
content_tag(:span, (" - " + active_scaffold_search_date_bridge_calendar_control(column, options, current_search, 'to')).html_safe,
|
31
31
|
:id => "#{options[:id]}_between", :class => "as_search_range_between", :style => current_search['opt'] == 'BETWEEN' ? nil : "display: none")
|
32
|
-
content_tag("span", numeric_controls.html_safe, :id => "#{options[:id]}_numeric", :style => ActiveScaffold::Finder::NumericComparators.include?(current_search['opt']) ? nil : "display: none")
|
32
|
+
content_tag("span", numeric_controls.html_safe, :id => "#{options[:id]}_numeric", :class => "search-date-numeric", :style => ActiveScaffold::Finder::NumericComparators.include?(current_search['opt']) ? nil : "display: none")
|
33
33
|
end
|
34
34
|
|
35
35
|
def active_scaffold_search_date_bridge_trend_tag(column, options, current_search)
|
36
36
|
active_scaffold_date_bridge_trend_tag(column, options,
|
37
|
-
{:
|
38
|
-
:number_value => current_search['number'],
|
37
|
+
{:number_value => current_search['number'],
|
39
38
|
:unit_value => current_search["unit"],
|
40
39
|
:show => (current_search['opt'] == 'PAST' || current_search['opt'] == 'FUTURE')})
|
41
40
|
end
|
42
41
|
|
43
42
|
def active_scaffold_date_bridge_trend_tag(column, options, trend_options)
|
44
|
-
trend_controls = text_field_tag("#{
|
45
|
-
select_tag("#{
|
43
|
+
trend_controls = text_field_tag("#{options[:name]}[number]", trend_options[:number_value], :class => 'text-input', :size => 10, :autocomplete => 'off') << " " <<
|
44
|
+
select_tag("#{options[:name]}[unit]",
|
46
45
|
options_for_select(active_scaffold_search_date_bridge_trend_units(column), trend_options[:unit_value]),
|
47
46
|
:class => 'text-input')
|
48
|
-
content_tag("span", trend_controls.html_safe, :id => "#{options[:id]}_trend", :style => trend_options[:show] ? nil : "display: none")
|
47
|
+
content_tag("span", trend_controls.html_safe, :id => "#{options[:id]}_trend", :class => "search-date-trend", :style => trend_options[:show] ? nil : "display: none")
|
49
48
|
end
|
50
49
|
|
51
50
|
def active_scaffold_search_date_bridge_trend_units(column)
|
@@ -55,10 +54,10 @@ module ActiveScaffold
|
|
55
54
|
end
|
56
55
|
|
57
56
|
def active_scaffold_search_date_bridge_range_tag(column, options, current_search)
|
58
|
-
range_controls = select_tag("
|
57
|
+
range_controls = select_tag("#{options[:name]}[range]",
|
59
58
|
options_for_select( ActiveScaffold::Finder::DateRanges.collect{|range| [as_(range.downcase.to_sym), range]}, current_search["range"]),
|
60
59
|
:class => 'text-input', :id => nil)
|
61
|
-
content_tag("span", range_controls.html_safe, :id => "#{options[:id]}_range", :style => (current_search['opt'] == 'RANGE') ? nil : "display: none")
|
60
|
+
content_tag("span", range_controls.html_safe, :id => "#{options[:id]}_range", :class => "search-date-range", :style => (current_search['opt'] == 'RANGE') ? nil : "display: none")
|
62
61
|
end
|
63
62
|
|
64
63
|
def column_datetime?(column)
|
@@ -1,6 +1,7 @@
|
|
1
1
|
class ActiveScaffold::Bridges::TinyMce < ActiveScaffold::DataStructures::Bridge
|
2
|
+
autoload :Helpers, 'active_scaffold/bridges/tiny_mce/helpers.rb'
|
2
3
|
def self.install
|
3
|
-
|
4
|
+
ActionView::Base.class_eval { include ActiveScaffold::Bridges::TinyMce::Helpers }
|
4
5
|
end
|
5
6
|
|
6
7
|
def self.install?
|
@@ -8,9 +9,10 @@ class ActiveScaffold::Bridges::TinyMce < ActiveScaffold::DataStructures::Bridge
|
|
8
9
|
end
|
9
10
|
|
10
11
|
def self.javascripts
|
11
|
-
|
12
|
+
case ActiveScaffold.js_framework
|
13
|
+
when :jquery
|
12
14
|
['tinymce-jquery', 'jquery/tiny_mce_bridge']
|
13
|
-
|
15
|
+
when :prototype
|
14
16
|
['tinymce', 'prototype/tiny_mce_bridge']
|
15
17
|
end
|
16
18
|
end
|
@@ -26,9 +26,10 @@ class ActiveScaffold::Bridges::TinyMce
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def onsubmit_with_tiny_mce
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
case ActiveScaffold.js_framework
|
30
|
+
when :jquery
|
31
|
+
submit_js = 'tinyMCE.triggerSave();jQuery(\'textarea.mceEditor\').each(function(index, elem) { tinyMCE.execCommand(\'mceRemoveControl\', false, jQuery(elem).attr(\'id\')); });'
|
32
|
+
when :prototype
|
32
33
|
submit_js = 'tinyMCE.triggerSave();this.select(\'textarea.mceEditor\').each(function(elem) { tinyMCE.execCommand(\'mceRemoveControl\', false, elem.id); });'
|
33
34
|
end
|
34
35
|
[onsubmit_without_tiny_mce, submit_js].compact.join ';'
|
@@ -42,5 +43,3 @@ class ActiveScaffold::Bridges::TinyMce
|
|
42
43
|
end
|
43
44
|
end
|
44
45
|
end
|
45
|
-
|
46
|
-
ActionView::Base.class_eval { include ActiveScaffold::Bridges::TinyMce::Helpers }
|
@@ -6,7 +6,11 @@ module ActiveScaffold::Config
|
|
6
6
|
def initialize(core_config)
|
7
7
|
@core = core_config
|
8
8
|
@action_group = self.class.action_group.clone if self.class.action_group
|
9
|
+
|
10
|
+
# start with the ActionLink defined globally
|
11
|
+
@link = self.class.link.clone if self.class.respond_to?(:link) && self.class.link
|
9
12
|
end
|
13
|
+
attr_reader :core
|
10
14
|
|
11
15
|
def self.inherited(subclass)
|
12
16
|
class << subclass
|
@@ -1,8 +1,6 @@
|
|
1
1
|
module ActiveScaffold::Config
|
2
|
-
# to fix the ckeditor bridge problem
|
2
|
+
# to fix the ckeditor bridge problem inherit from full class name
|
3
3
|
class Core < ActiveScaffold::Config::Base
|
4
|
-
# code commented out (see above)
|
5
|
-
#class Core < Base
|
6
4
|
# global level configuration
|
7
5
|
# --------------------------
|
8
6
|
|
@@ -33,6 +31,10 @@ module ActiveScaffold::Config
|
|
33
31
|
cattr_accessor :cache_association_options
|
34
32
|
@@cache_association_options = true
|
35
33
|
|
34
|
+
# enable setting ETag and LastModified on responses and using fresh_when/stale? to respond with 304 and avoid rendering views
|
35
|
+
cattr_accessor :conditional_get_support
|
36
|
+
@@conditional_get_support = false
|
37
|
+
|
36
38
|
# enable saving user settings in session (per_page, limit, page, sort, search params)
|
37
39
|
cattr_accessor :store_user_settings
|
38
40
|
@@store_user_settings = true
|
@@ -55,7 +57,7 @@ module ActiveScaffold::Config
|
|
55
57
|
# * current_user_method - what method on the controller returns the current user. default: :current_user
|
56
58
|
# * default_permission - what the default permission is. default: true
|
57
59
|
def self.security
|
58
|
-
ActiveRecordPermissions
|
60
|
+
ActiveScaffold::ActiveRecordPermissions
|
59
61
|
end
|
60
62
|
|
61
63
|
# columns that should be ignored for every model. these should be metadata columns like change dates, versions, etc.
|
@@ -109,6 +111,9 @@ module ActiveScaffold::Config
|
|
109
111
|
# enable caching of association options
|
110
112
|
attr_accessor :cache_association_options
|
111
113
|
|
114
|
+
# enable setting ETag and LastModified on responses and using fresh_when/stale? to respond with 304 and avoid rendering views
|
115
|
+
attr_accessor :conditional_get_support
|
116
|
+
|
112
117
|
# enable saving user settings in session (per_page, limit, page, sort, search params)
|
113
118
|
attr_accessor :store_user_settings
|
114
119
|
|
@@ -153,8 +158,9 @@ module ActiveScaffold::Config
|
|
153
158
|
@columns = ActiveScaffold::DataStructures::Columns.new(self.model, attribute_names + association_column_names)
|
154
159
|
|
155
160
|
# and then, let's remove some columns from the inheritable set.
|
161
|
+
content_columns = Set.new(self.model.content_columns.map(&:name))
|
156
162
|
@columns.exclude(*self.class.ignore_columns)
|
157
|
-
@columns.exclude(*@columns.find_all { |c| c.column and (c.column.
|
163
|
+
@columns.exclude(*@columns.find_all { |c| c.column and content_columns.exclude?(c.column.name) }.collect {|c| c.name})
|
158
164
|
@columns.exclude(*self.model.reflect_on_all_associations.collect{|a| :"#{a.name}_type" if a.options[:polymorphic]}.compact)
|
159
165
|
|
160
166
|
# inherit the global frontend
|
@@ -162,6 +168,7 @@ module ActiveScaffold::Config
|
|
162
168
|
@theme = self.class.theme
|
163
169
|
@cache_action_link_urls = self.class.cache_action_link_urls
|
164
170
|
@cache_association_options = self.class.cache_association_options
|
171
|
+
@conditional_get_support = self.class.conditional_get_support
|
165
172
|
@store_user_settings = self.class.store_user_settings
|
166
173
|
@sti_create_links = self.class.sti_create_links
|
167
174
|
|
@@ -6,9 +6,6 @@ module ActiveScaffold::Config
|
|
6
6
|
super
|
7
7
|
@text_search = self.class.text_search
|
8
8
|
@human_conditions = self.class.human_conditions
|
9
|
-
|
10
|
-
# start with the ActionLink defined globally
|
11
|
-
@link = self.class.link.clone
|
12
9
|
end
|
13
10
|
|
14
11
|
|
@@ -16,7 +13,7 @@ module ActiveScaffold::Config
|
|
16
13
|
# --------------------------
|
17
14
|
# the ActionLink for this action
|
18
15
|
cattr_reader :link
|
19
|
-
@@link = ActiveScaffold::DataStructures::ActionLink.new('show_search', :label => :search, :type => :collection, :security_method => :search_authorized?, :ignore_method => :
|
16
|
+
@@link = ActiveScaffold::DataStructures::ActionLink.new('show_search', :label => :search, :type => :collection, :security_method => :search_authorized?, :ignore_method => :field_search_ignore?)
|
20
17
|
|
21
18
|
# A flag for how the search should do full-text searching in the database:
|
22
19
|
# * :full: LIKE %?%
|
@@ -2,8 +2,6 @@ module ActiveScaffold::Config
|
|
2
2
|
class Form < Base
|
3
3
|
def initialize(core_config)
|
4
4
|
super
|
5
|
-
# start with the ActionLink defined globally
|
6
|
-
@link = self.class.link.clone unless self.class.link.nil?
|
7
5
|
@show_unauthorized_columns = self.class.show_unauthorized_columns
|
8
6
|
@refresh_list = self.class.refresh_list
|
9
7
|
@persistent = self.class.persistent
|
@@ -18,6 +18,7 @@ module ActiveScaffold::Config
|
|
18
18
|
@empty_field_text = self.class.empty_field_text
|
19
19
|
@association_join_text = self.class.association_join_text
|
20
20
|
@pagination = self.class.pagination
|
21
|
+
@auto_pagination = self.class.auto_pagination
|
21
22
|
@show_search_reset = self.class.show_search_reset
|
22
23
|
@reset_link = self.class.reset_link.clone
|
23
24
|
@wrap_tag = self.class.wrap_tag
|
@@ -26,6 +27,7 @@ module ActiveScaffold::Config
|
|
26
27
|
@messages_above_header = self.class.messages_above_header
|
27
28
|
@auto_select_columns = self.class.auto_select_columns
|
28
29
|
@refresh_with_header = self.class.refresh_with_header
|
30
|
+
@calculate_etag = self.class.calculate_etag
|
29
31
|
end
|
30
32
|
|
31
33
|
# global level configuration
|
@@ -65,6 +67,12 @@ module ActiveScaffold::Config
|
|
65
67
|
cattr_accessor :pagination
|
66
68
|
@@pagination = true
|
67
69
|
|
70
|
+
# Auto paginate, only can be used with pagination enabled
|
71
|
+
# * true: First page will be loaded on first request, next pages will be requested by AJAX until all items are loaded
|
72
|
+
# * false: Disable auto pagination
|
73
|
+
cattr_accessor :auto_pagination
|
74
|
+
@@auto_pagination = false
|
75
|
+
|
68
76
|
# show a link to reset the search next to filtered message
|
69
77
|
cattr_accessor :show_search_reset
|
70
78
|
@@show_search_reset = true
|
@@ -90,6 +98,11 @@ module ActiveScaffold::Config
|
|
90
98
|
cattr_accessor :auto_select_columns
|
91
99
|
@@auto_select_columns = false
|
92
100
|
|
101
|
+
# Enable ETag calculation (when conditional_get_support is enabled), it requires to load records for page, when is disabled query can be avoided when page is cached in browser
|
102
|
+
# order clause will be used for ETag when calculate_etag is disabled, so query for records can be avoided
|
103
|
+
cattr_accessor :calculate_etag
|
104
|
+
@@calculate_etag = false
|
105
|
+
|
93
106
|
# instance-level configuration
|
94
107
|
# ----------------------------
|
95
108
|
|
@@ -119,6 +132,11 @@ module ActiveScaffold::Config
|
|
119
132
|
# * false: Disable pagination
|
120
133
|
attr_accessor :pagination
|
121
134
|
|
135
|
+
# Auto paginate, only can be used with pagination enabled
|
136
|
+
# * true: First page will be loaded on first request, next pages will be requested by AJAX until all items are loaded
|
137
|
+
# * false: Disable auto pagination
|
138
|
+
attr_accessor :auto_pagination
|
139
|
+
|
122
140
|
# what string to use when a field is empty
|
123
141
|
attr_accessor :empty_field_text
|
124
142
|
|
@@ -169,6 +187,14 @@ module ActiveScaffold::Config
|
|
169
187
|
end
|
170
188
|
|
171
189
|
def search_partial
|
190
|
+
if @always_show_search == true
|
191
|
+
auto_search_partial
|
192
|
+
else
|
193
|
+
@always_show_search.to_s if @core.actions.include? @always_show_search
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def auto_search_partial
|
172
198
|
return "search" if @core.actions.include?(:search)
|
173
199
|
return "field_search" if @core.actions.include?(:field_search)
|
174
200
|
end
|
@@ -198,6 +224,10 @@ module ActiveScaffold::Config
|
|
198
224
|
# Enable auto select columns on list, so only columns needed for list columns are selected
|
199
225
|
attr_accessor :auto_select_columns
|
200
226
|
|
227
|
+
# Enable ETag calculation (when conditional_get_support is enabled), it requires to load records for page, when is disabled query can be avoided when page is cached in browser
|
228
|
+
# order clause will be used for ETag when calculate_etag is disabled, so query for records can be avoided
|
229
|
+
attr_accessor :calculate_etag
|
230
|
+
|
201
231
|
class UserSettings < UserSettings
|
202
232
|
def initialize(conf, storage, params)
|
203
233
|
super(conf, storage, params, :list)
|
@@ -216,7 +246,7 @@ module ActiveScaffold::Config
|
|
216
246
|
end
|
217
247
|
|
218
248
|
def page
|
219
|
-
self['page'] = @params['page'] if @params.has_key?
|
249
|
+
self['page'] = @params['page'] || 1 if @params.has_key?('page') || @conf.auto_pagination
|
220
250
|
self['page'] || 1
|
221
251
|
end
|
222
252
|
|
@@ -2,12 +2,6 @@ module ActiveScaffold::Config
|
|
2
2
|
class Show < Base
|
3
3
|
self.crud_type = :read
|
4
4
|
|
5
|
-
def initialize(core_config)
|
6
|
-
super
|
7
|
-
# start with the ActionLink defined globally
|
8
|
-
@link = self.class.link.clone
|
9
|
-
end
|
10
|
-
|
11
5
|
# global level configuration
|
12
6
|
# --------------------------
|
13
7
|
cattr_accessor :link
|
@@ -7,7 +7,7 @@ module ActiveScaffold
|
|
7
7
|
module Configurable
|
8
8
|
def configure(&configuration_block)
|
9
9
|
return unless configuration_block
|
10
|
-
@configuration_binding = configuration_block.binding
|
10
|
+
@configuration_binding = eval("self", configuration_block.binding)
|
11
11
|
ret = instance_exec self, &configuration_block
|
12
12
|
@configuration_binding = nil
|
13
13
|
return ret
|
@@ -21,7 +21,7 @@ module ActiveScaffold
|
|
21
21
|
if @configuration_binding.nil?
|
22
22
|
raise $!
|
23
23
|
else
|
24
|
-
|
24
|
+
@configuration_binding.send(name, *args)
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
@@ -55,7 +55,7 @@ module ActiveScaffold
|
|
55
55
|
field = far_association.klass.primary_key
|
56
56
|
table = far_association.table_name
|
57
57
|
|
58
|
-
|
58
|
+
active_scaffold_references.concat([{k => far_association.name}]) # e.g. {:den => :park}
|
59
59
|
hash_conditions.merge!("#{table}.#{field}" => v.values.first)
|
60
60
|
|
61
61
|
# association column constraint
|
@@ -63,13 +63,17 @@ module ActiveScaffold
|
|
63
63
|
if column.association.macro == :has_and_belongs_to_many
|
64
64
|
active_scaffold_habtm_joins.concat column.includes
|
65
65
|
elsif !column.association.options[:polymorphic]
|
66
|
-
|
66
|
+
if column.association.macro == :belongs_to
|
67
|
+
active_scaffold_preload.concat column.includes
|
68
|
+
else
|
69
|
+
active_scaffold_references.concat column.includes
|
70
|
+
end
|
67
71
|
end
|
68
72
|
hash_conditions.merge!(condition_from_association_constraint(column.association, v))
|
69
73
|
|
70
74
|
# regular column constraints
|
71
75
|
elsif column.searchable? && params[column.name] != v
|
72
|
-
|
76
|
+
active_scaffold_references.concat column.references if column.includes.present?
|
73
77
|
conditions << [column.search_sql.collect { |search_sql| "#{search_sql} = ?" }.join(' OR '), *([v] * column.search_sql.size)]
|
74
78
|
end
|
75
79
|
# unknown-to-activescaffold-but-real-database-column constraint
|
@@ -90,23 +94,16 @@ module ActiveScaffold
|
|
90
94
|
# we have to use the other model's primary_key.
|
91
95
|
#
|
92
96
|
# please see the relevant tests for concrete examples.
|
93
|
-
|
97
|
+
|
98
|
+
field = if [:has_one, :has_many, :has_and_belongs_to_many].include?(association.macro)
|
94
99
|
association.klass.primary_key
|
95
|
-
elsif [:has_and_belongs_to_many].include?(association.macro)
|
96
|
-
association.association_foreign_key
|
97
100
|
else
|
98
101
|
association.options[:foreign_key] || association.name.to_s.foreign_key
|
99
102
|
end
|
100
103
|
|
101
104
|
table = case association.macro
|
102
|
-
when :
|
103
|
-
association.
|
104
|
-
|
105
|
-
when :belongs_to
|
106
|
-
active_scaffold_config.model.table_name
|
107
|
-
|
108
|
-
else
|
109
|
-
association.table_name
|
105
|
+
when :belongs_to then active_scaffold_config.model.table_name
|
106
|
+
else association.table_name
|
110
107
|
end
|
111
108
|
|
112
109
|
if association.options[:primary_key]
|
@@ -0,0 +1,277 @@
|
|
1
|
+
module ActiveScaffold
|
2
|
+
module Core
|
3
|
+
def self.included(base)
|
4
|
+
base.extend(ClassMethods)
|
5
|
+
base.module_eval do
|
6
|
+
# TODO: these should be in actions/core
|
7
|
+
before_filter :handle_user_settings
|
8
|
+
before_filter :check_input_device
|
9
|
+
end
|
10
|
+
|
11
|
+
base.helper_method :touch_device?
|
12
|
+
base.helper_method :hover_via_click?
|
13
|
+
base.helper_method :active_scaffold_constraints
|
14
|
+
end
|
15
|
+
|
16
|
+
def active_scaffold_config
|
17
|
+
self.class.active_scaffold_config
|
18
|
+
end
|
19
|
+
|
20
|
+
def active_scaffold_config_for(klass)
|
21
|
+
self.class.active_scaffold_config_for(klass)
|
22
|
+
end
|
23
|
+
|
24
|
+
def active_scaffold_session_storage_key(id = nil)
|
25
|
+
id ||= params[:eid] || "#{params[:controller]}#{"_#{nested_parent_id}" if nested?}"
|
26
|
+
"as:#{id}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def active_scaffold_session_storage(id = nil)
|
30
|
+
session_index = active_scaffold_session_storage_key(id)
|
31
|
+
session[session_index] ||= {}
|
32
|
+
session[session_index]
|
33
|
+
end
|
34
|
+
|
35
|
+
def clear_storage
|
36
|
+
session_index = active_scaffold_session_storage_key
|
37
|
+
session.delete(session_index) unless session[session_index].present?
|
38
|
+
end
|
39
|
+
|
40
|
+
# at some point we need to pass the session and params into config. we'll just take care of that before any particular action occurs by passing those hashes off to the UserSettings class of each action.
|
41
|
+
def handle_user_settings
|
42
|
+
if self.class.uses_active_scaffold?
|
43
|
+
active_scaffold_config.actions.each do |action_name|
|
44
|
+
conf_instance = active_scaffold_config.send(action_name) rescue next
|
45
|
+
next if conf_instance.class::UserSettings == ActiveScaffold::Config::Base::UserSettings # if it hasn't been extended, skip it
|
46
|
+
storage = active_scaffold_config.store_user_settings ? active_scaffold_session_storage : {}
|
47
|
+
conf_instance.user = conf_instance.class::UserSettings.new(conf_instance, storage, params)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def check_input_device
|
53
|
+
if request.env["HTTP_USER_AGENT"] && request.env["HTTP_USER_AGENT"][/(iPhone|iPod|iPad)/i]
|
54
|
+
session[:input_device_type] = 'TOUCH'
|
55
|
+
session[:hover_supported] = false
|
56
|
+
else
|
57
|
+
session[:input_device_type] = 'MOUSE'
|
58
|
+
session[:hover_supported] = true
|
59
|
+
end if session[:input_device_type].nil?
|
60
|
+
end
|
61
|
+
|
62
|
+
def touch_device?
|
63
|
+
session[:input_device_type] == 'TOUCH'
|
64
|
+
end
|
65
|
+
|
66
|
+
def hover_via_click?
|
67
|
+
session[:hover_supported] == false
|
68
|
+
end
|
69
|
+
|
70
|
+
module ClassMethods
|
71
|
+
def active_scaffold(model_id = nil, &block)
|
72
|
+
extend Prefixes
|
73
|
+
# initialize bridges here
|
74
|
+
ActiveScaffold::Bridges.run_all
|
75
|
+
|
76
|
+
# converts Foo::BarController to 'bar' and FooBarsController to 'foo_bar' and AddressController to 'address'
|
77
|
+
model_id = self.to_s.split('::').last.sub(/Controller$/, '').pluralize.singularize.underscore unless model_id
|
78
|
+
|
79
|
+
# run the configuration
|
80
|
+
@active_scaffold_config = ActiveScaffold::Config::Core.new(model_id)
|
81
|
+
@active_scaffold_config_block = block
|
82
|
+
self.links_for_associations
|
83
|
+
|
84
|
+
self.active_scaffold_superclasses_blocks.each {|superblock| self.active_scaffold_config.configure &superblock}
|
85
|
+
self.active_scaffold_config.sti_children = nil # reset sti_children if set in parent block
|
86
|
+
self.active_scaffold_config.configure &block if block_given?
|
87
|
+
self.active_scaffold_config._configure_sti unless self.active_scaffold_config.sti_children.nil?
|
88
|
+
self.active_scaffold_config._load_action_columns
|
89
|
+
|
90
|
+
# defines the attribute read methods on the model, so record.send() doesn't find protected/private methods instead
|
91
|
+
klass = self.active_scaffold_config.model
|
92
|
+
# Rails 4.0.4 has removed attribute_methods_generated,
|
93
|
+
# and made define_attribute_methods threadsave to call multiple times.
|
94
|
+
# Check for that here.
|
95
|
+
if ((Rails::VERSION::MAJOR == 4) && !klass.respond_to?(:attribute_methods_generated)) ||
|
96
|
+
!klass.attribute_methods_generated?
|
97
|
+
klass.define_attribute_methods
|
98
|
+
end
|
99
|
+
# include the rest of the code into the controller: the action core and the included actions
|
100
|
+
module_eval do
|
101
|
+
include ActiveScaffold::Finder
|
102
|
+
include ActiveScaffold::Constraints
|
103
|
+
include ActiveScaffold::AttributeParams
|
104
|
+
include ActiveScaffold::Actions::Core
|
105
|
+
active_scaffold_config.actions.each do |mod|
|
106
|
+
name = mod.to_s.camelize
|
107
|
+
include "ActiveScaffold::Actions::#{name}".constantize
|
108
|
+
|
109
|
+
# sneak the action links from the actions into the main set
|
110
|
+
mod_conf = active_scaffold_config.send(mod)
|
111
|
+
if mod_conf.respond_to?(:link) && (link = mod_conf.link)
|
112
|
+
if link.is_a? Array
|
113
|
+
link.each {|current| active_scaffold_config.action_links.add_to_group(current, active_scaffold_config.send(mod).action_group)}
|
114
|
+
elsif link.is_a? ActiveScaffold::DataStructures::ActionLink
|
115
|
+
active_scaffold_config.action_links.add_to_group(link, active_scaffold_config.send(mod).action_group)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
self._add_sti_create_links if self.active_scaffold_config.add_sti_create_links?
|
121
|
+
end
|
122
|
+
|
123
|
+
module Prefixes
|
124
|
+
def parent_prefixes
|
125
|
+
@parent_prefixes ||= super << 'active_scaffold_overrides'
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# To be called after include action modules
|
130
|
+
def _add_sti_create_links
|
131
|
+
new_action_link = active_scaffold_config.action_links.collection['new']
|
132
|
+
unless new_action_link.nil? || active_scaffold_config.sti_children.empty?
|
133
|
+
active_scaffold_config.action_links.collection.delete('new')
|
134
|
+
active_scaffold_config.sti_children.each do |child|
|
135
|
+
new_sti_link = Marshal.load(Marshal.dump(new_action_link)) # deep clone
|
136
|
+
new_sti_link.label = as_(:create_model, :model => child.to_s.camelize.constantize.model_name.human)
|
137
|
+
new_sti_link.parameters = {:parent_sti => controller_path}
|
138
|
+
new_sti_link.controller = Proc.new { active_scaffold_controller_for(child.to_s.camelize.constantize).controller_path }
|
139
|
+
active_scaffold_config.action_links.collection.create.add(new_sti_link)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# Create the automatic column links. Note that this has to happen when configuration is *done*, because otherwise the Nested module could be disabled. Actually, it could still be disabled later, couldn't it?
|
145
|
+
def links_for_associations
|
146
|
+
return unless active_scaffold_config.actions.include? :list and active_scaffold_config.actions.include? :nested
|
147
|
+
active_scaffold_config.columns.each do |column|
|
148
|
+
next unless column.link.nil? and column.autolink?
|
149
|
+
#lazy load of action_link, cause it was really slowing down app in dev mode
|
150
|
+
#and might lead to trouble cause of cyclic constantization of controllers
|
151
|
+
#and might be unnecessary cause it is done before columns are configured
|
152
|
+
column.set_link(Proc.new {|col| link_for_association(col)})
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def active_scaffold_controller_for_column(column, options = {})
|
157
|
+
begin
|
158
|
+
if column.polymorphic_association?
|
159
|
+
:polymorph
|
160
|
+
elsif options.include?(:controller)
|
161
|
+
"#{options[:controller].to_s.camelize}Controller".constantize
|
162
|
+
else
|
163
|
+
active_scaffold_controller_for(column.association.klass)
|
164
|
+
end
|
165
|
+
rescue ActiveScaffold::ControllerNotFound
|
166
|
+
nil
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def link_for_association(column, options = {})
|
171
|
+
controller = active_scaffold_controller_for_column(column, options)
|
172
|
+
|
173
|
+
unless controller.nil?
|
174
|
+
options.reverse_merge! :position => :after, :type => :member, :controller => (controller == :polymorph ? controller : controller.controller_path), :column => column
|
175
|
+
options[:parameters] ||= {}
|
176
|
+
options[:parameters].reverse_merge! :association => column.association.name
|
177
|
+
if column.plural_association?
|
178
|
+
ActiveScaffold::DataStructures::ActionLink.new('index', options.merge(:refresh_on_close => true))
|
179
|
+
else
|
180
|
+
actions = controller.active_scaffold_config.actions unless controller == :polymorph
|
181
|
+
actions ||= [:create, :update, :show]
|
182
|
+
column.actions_for_association_links.delete :new unless actions.include? :create
|
183
|
+
column.actions_for_association_links.delete :edit unless actions.include? :update
|
184
|
+
column.actions_for_association_links.delete :show unless actions.include? :show
|
185
|
+
ActiveScaffold::DataStructures::ActionLink.new(nil, options.merge(:html_options => {:class => column.name}))
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def link_for_association_as_scope(scope, options = {})
|
191
|
+
options.reverse_merge! :label => scope, :position => :after, :type => :member, :controller => controller_path
|
192
|
+
options[:parameters] ||= {}
|
193
|
+
options[:parameters].reverse_merge! :named_scope => scope
|
194
|
+
ActiveScaffold::DataStructures::ActionLink.new('index', options)
|
195
|
+
end
|
196
|
+
|
197
|
+
def add_active_scaffold_path(path)
|
198
|
+
as_path = File.join(ActiveScaffold::Config::Core.plugin_directory, 'app', 'views')
|
199
|
+
index = view_paths.find_index { |p| p.to_s == as_path }
|
200
|
+
if index
|
201
|
+
self.view_paths = view_paths[0..index-1] + Array(path) + view_paths[index..-1]
|
202
|
+
else
|
203
|
+
append_view_path path
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def active_scaffold_config
|
208
|
+
if @active_scaffold_config.nil?
|
209
|
+
self.superclass.active_scaffold_config if self.superclass.respond_to? :active_scaffold_config
|
210
|
+
else
|
211
|
+
@active_scaffold_config
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def active_scaffold_config_block
|
216
|
+
@active_scaffold_config_block
|
217
|
+
end
|
218
|
+
|
219
|
+
def active_scaffold_superclasses_blocks
|
220
|
+
blocks = []
|
221
|
+
klass = self.superclass
|
222
|
+
while klass.respond_to? :active_scaffold_superclasses_blocks
|
223
|
+
blocks << klass.active_scaffold_config_block
|
224
|
+
klass = klass.superclass
|
225
|
+
end
|
226
|
+
blocks.compact.reverse
|
227
|
+
end
|
228
|
+
|
229
|
+
def active_scaffold_config_for(klass)
|
230
|
+
begin
|
231
|
+
controller = active_scaffold_controller_for(klass)
|
232
|
+
rescue ActiveScaffold::ControllerNotFound
|
233
|
+
config = ActiveScaffold::Config::Core.new(klass)
|
234
|
+
config._load_action_columns
|
235
|
+
config
|
236
|
+
else
|
237
|
+
controller.active_scaffold_config
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
def active_scaffold_controller_for(klass)
|
242
|
+
ActiveScaffold::Core.active_scaffold_controller_for(klass, self.to_s.split('::')[0...-1].join('::') + '::')
|
243
|
+
end
|
244
|
+
|
245
|
+
|
246
|
+
def uses_active_scaffold?
|
247
|
+
!active_scaffold_config.nil?
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
# Tries to find a controller for the given ActiveRecord model.
|
252
|
+
# Searches in the namespace of the current controller for singular and plural versions of the conventional "#{model}Controller" syntax.
|
253
|
+
# You may override this method to customize the search routine.
|
254
|
+
def self.active_scaffold_controller_for(klass, controller_namespace = '::')
|
255
|
+
error_message = []
|
256
|
+
[controller_namespace, ''].each do |namespace|
|
257
|
+
["#{klass.to_s.underscore.pluralize}", "#{klass.to_s.underscore.pluralize.singularize}"].each do |controller_name|
|
258
|
+
begin
|
259
|
+
controller = "#{namespace}#{controller_name.camelize}Controller".constantize
|
260
|
+
rescue NameError => error
|
261
|
+
# Only rescue NameError associated with the controller constant not existing - not other compile errors
|
262
|
+
if error.message["uninitialized constant #{controller}"]
|
263
|
+
error_message << "#{namespace}#{controller_name.camelize}Controller"
|
264
|
+
next
|
265
|
+
else
|
266
|
+
raise
|
267
|
+
end
|
268
|
+
end
|
269
|
+
raise ActiveScaffold::ControllerNotFound, "#{controller} missing ActiveScaffold", caller unless controller.uses_active_scaffold?
|
270
|
+
raise ActiveScaffold::ControllerNotFound, "ActiveScaffold on #{controller} is not for #{klass} model.", caller unless controller.active_scaffold_config.model.to_s == klass.to_s
|
271
|
+
return controller
|
272
|
+
end
|
273
|
+
end
|
274
|
+
raise ActiveScaffold::ControllerNotFound, "Could not find " + error_message.join(" or "), caller
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|