active_scaffold 3.0.4 → 3.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. data/CHANGELOG +5 -0
  2. data/active_scaffold.gemspec +1 -1
  3. data/frontends/default/stylesheets/stylesheet.css +40 -2
  4. data/lib/active_scaffold.rb +111 -21
  5. data/lib/active_scaffold/actions/nested.rb +5 -1
  6. data/lib/active_scaffold/actions/subform.rb +4 -1
  7. data/lib/active_scaffold/attribute_params.rb +4 -4
  8. data/lib/active_scaffold/bridges/bridge.rb +2 -5
  9. data/lib/active_scaffold/config/list.rb +9 -9
  10. data/lib/active_scaffold/config/update.rb +1 -1
  11. data/lib/active_scaffold/data_structures/action_links.rb +4 -3
  12. data/lib/active_scaffold/finder.rb +13 -13
  13. data/lib/active_scaffold/helpers/controller_helpers.rb +5 -3
  14. data/lib/active_scaffold/helpers/country_helpers.rb +263 -257
  15. data/lib/active_scaffold/helpers/form_column_helpers.rb +5 -5
  16. data/lib/active_scaffold/helpers/id_helpers.rb +2 -2
  17. data/lib/active_scaffold/helpers/search_column_helpers.rb +11 -11
  18. data/lib/active_scaffold/helpers/view_helpers.rb +15 -15
  19. data/lib/active_scaffold/marked_model.rb +6 -6
  20. data/lib/extensions/action_view_rendering.rb +5 -5
  21. data/lib/extensions/active_record_offset.rb +7 -7
  22. data/lib/extensions/localize.rb +1 -1
  23. data/lib/extensions/name_option_for_datetime.rb +1 -1
  24. data/lib/extensions/paginator_extensions.rb +2 -2
  25. data/lib/extensions/reverse_associations.rb +1 -1
  26. data/lib/extensions/routing_mapper.rb +2 -2
  27. data/lib/extensions/usa_state.rb +15 -11
  28. data/lib/generators/active_scaffold/active_scaffold_generator.rb +5 -5
  29. data/lib/generators/active_scaffold_controller/active_scaffold_controller_generator.rb +2 -2
  30. data/lib/generators/active_scaffold_setup/active_scaffold_setup_generator.rb +10 -10
  31. metadata +4 -6
  32. data/environment.rb +0 -24
  33. data/install_assets.rb +0 -44
data/CHANGELOG CHANGED
@@ -1,3 +1,8 @@
1
+ = 3.0.5
2
+
3
+ - switch from explicit requires to autoloading
4
+ - get nested action links up and running
5
+
1
6
  = 3.0.4
2
7
 
3
8
  - Fix a typo that made 3.0.3 unusable.
@@ -2,7 +2,7 @@ $:.push File.expand_path("../lib", __FILE__)
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "active_scaffold"
5
- s.version = "3.0.4"
5
+ s.version = "3.0.5"
6
6
  s.platform = Gem::Platform::RUBY
7
7
  s.authors = ["Many, see README"]
8
8
  s.email = ["activescaffold@googlegroups.com"]
@@ -264,7 +264,8 @@ text-align: right;
264
264
  padding: 0 2px;
265
265
  }
266
266
 
267
- .active-scaffold tr.record td.actions a {
267
+ .active-scaffold tr.record td.actions a,
268
+ .active-scaffold tr.record td.actions span {
268
269
  font: bold 11px verdana, sans-serif;
269
270
  letter-spacing: -1px;
270
271
  padding: 2px;
@@ -273,6 +274,43 @@ line-height: 16px;
273
274
  white-space: nowrap;
274
275
  }
275
276
 
277
+ .active-scaffold tr.record td.actions td.action_list {
278
+ position:relative;
279
+ text-align: left;
280
+ color: #0066CC;
281
+ }
282
+
283
+ .active-scaffold tr.record td.actions .action_list ul {
284
+ border:medium none;
285
+ list-style-type:none;
286
+ margin:0;
287
+ padding:0;
288
+ position:absolute;
289
+ line-height:200%;
290
+ display: none;
291
+ width:100%;
292
+ }
293
+
294
+ .active-scaffold tr.record td.actions .action_list ul li {
295
+ background:none repeat scroll 0 0 #FFF;
296
+ border-bottom:1px solid #AFD0F5;
297
+ border-left:1px solid #AFD0F5;
298
+ border-right:1px solid #AFD0F5;
299
+ color:#000000;
300
+ display:block;
301
+ padding-bottom:5px;
302
+ position:relative;
303
+ width:160px;
304
+ z-index: 2;
305
+ }
306
+
307
+ .active-scaffold tr.record td.actions td.action_list:hover ul {
308
+ display:block;
309
+ }
310
+
311
+
312
+
313
+
276
314
  /* Table :: Inline Adapter
277
315
  ============================= */
278
316
 
@@ -625,7 +663,6 @@ letter-spacing: 0;
625
663
 
626
664
  .active-scaffold li.form-element {
627
665
  clear: both;
628
- padding-top: 2px;
629
666
  }
630
667
 
631
668
  .active-scaffold label {
@@ -653,6 +690,7 @@ margin: 0;
653
690
 
654
691
 
655
692
  .active-scaffold .description {
693
+ display: inline-block;
656
694
  color: #999;
657
695
  font-size: 10px;
658
696
  margin-left: 5px;
@@ -1,3 +1,7 @@
1
+ unless Rails::VERSION::MAJOR == 3 && Rails::VERSION::MINOR >= 0
2
+ raise "This version of ActiveScaffold requires Rails 3.0 or higher. Please use an earlier version."
3
+ end
4
+
1
5
  require 'render_component' rescue nil
2
6
  require 'verification'
3
7
 
@@ -5,18 +9,43 @@ require 'active_record_permissions'
5
9
  require 'dhtml_confirm'
6
10
  require 'paginator'
7
11
  require 'responds_to_parent'
8
- require 'active_scaffold/attribute_params'
9
- require 'active_scaffold/configurable'
10
- require 'active_scaffold/constraints'
11
- require 'active_scaffold/finder'
12
- require 'active_scaffold/marked_model'
13
- require 'active_scaffold/config/base'
14
- require 'active_scaffold/data_structures/column'
15
- require 'active_scaffold/data_structures/actions'
16
- require 'active_scaffold/data_structures/action_links'
17
- require 'active_scaffold/config/form'
18
12
 
19
13
  module ActiveScaffold
14
+ autoload :AttributeParams, 'active_scaffold/attribute_params'
15
+ autoload :Configurable, 'active_scaffold/configurable'
16
+ autoload :Constraints, 'active_scaffold/constraints'
17
+ autoload :Finder, 'active_scaffold/finder'
18
+ autoload :MarkedModel, 'active_scaffold/marked_model'
19
+
20
+ def self.active_scaffold_autoload_subdir(dir, mod=self)
21
+ Dir["#{File.dirname(__FILE__)}/active_scaffold/#{dir}/*.rb"].each { |file|
22
+ basename = File.basename(file, ".rb")
23
+ mod.module_eval {
24
+ autoload basename.camelcase.to_sym, "active_scaffold/#{dir}/#{basename}"
25
+ }
26
+ }
27
+ end
28
+
29
+ module Actions
30
+ ActiveScaffold.active_scaffold_autoload_subdir('actions', self)
31
+ end
32
+
33
+ module Bridges
34
+ autoload :Bridge, 'active_scaffold/bridges/bridge'
35
+ end
36
+
37
+ module Config
38
+ ActiveScaffold.active_scaffold_autoload_subdir('config', self)
39
+ end
40
+
41
+ module DataStructures
42
+ ActiveScaffold.active_scaffold_autoload_subdir('data_structures', self)
43
+ end
44
+
45
+ module Helpers
46
+ ActiveScaffold.active_scaffold_autoload_subdir('helpers', self)
47
+ end
48
+
20
49
  class ControllerNotFound < RuntimeError; end
21
50
  class DependencyFailure < RuntimeError; end
22
51
  class MalformedConstraint < RuntimeError; end
@@ -71,6 +100,58 @@ module ActiveScaffold
71
100
  @@js_framework ||= :prototype
72
101
  end
73
102
 
103
+ ##
104
+ ## Copy over asset files (javascript/css/images) from directory to public/
105
+ ##
106
+ def self.install_assets_from(directory)
107
+ copy_files("/public", "/public", directory)
108
+
109
+ available_frontends = Dir[File.join(directory, 'frontends', '*')].map { |d| File.basename d }
110
+ [:stylesheets, :javascripts, :images].each do |asset_type|
111
+ path = "/public/#{asset_type}/active_scaffold"
112
+ copy_files(path, path, directory)
113
+
114
+ File.open(File.join(Rails.root, path, 'DO_NOT_EDIT'), 'w') do |f|
115
+ f.puts "Any changes made to files in sub-folders will be lost."
116
+ f.puts "See http://activescaffold.com/tutorials/faq#custom-css."
117
+ end
118
+
119
+ available_frontends.each do |frontend|
120
+ if asset_type == :javascripts
121
+ file_mask = '*.js'
122
+ source = "/frontends/#{frontend}/#{asset_type}/#{ActiveScaffold.js_framework}"
123
+ else
124
+ file_mask = '*.*'
125
+ source = "/frontends/#{frontend}/#{asset_type}"
126
+ end
127
+ destination = "/public/#{asset_type}/active_scaffold/#{frontend}"
128
+ copy_files(source, destination, directory, file_mask)
129
+ end
130
+ end
131
+ end
132
+
133
+ def self.root
134
+ File.dirname(__FILE__) + "/.."
135
+ end
136
+
137
+ def self.delete_stale_assets
138
+ available_frontends = Dir[File.join(root, 'frontends', '*')].map { |d| File.basename d }
139
+ [:stylesheets, :javascripts, :images].each do |asset_type|
140
+ available_frontends.each do |frontend|
141
+ destination = File.join(Rails.root, "/public/#{asset_type}/active_scaffold/#{frontend}")
142
+ FileUtils.rm Dir.glob("#{destination}/*")
143
+ end
144
+ end
145
+ end
146
+
147
+ private
148
+ def self.copy_files(source_path, destination_path, directory, file_mask = '*.*')
149
+ source, destination = File.join(directory, source_path), File.join(Rails.root, destination_path)
150
+ FileUtils.mkdir_p(destination) unless File.exist?(destination)
151
+
152
+ FileUtils.cp_r(Dir.glob("#{source}/#{file_mask}"), destination)
153
+ end
154
+
74
155
  module ClassMethods
75
156
  def active_scaffold(model_id = nil, &block)
76
157
  # initialize bridges here
@@ -228,8 +309,10 @@ module ActiveScaffold
228
309
  end
229
310
 
230
311
  # Tries to find a controller for the given ActiveRecord model.
231
- # Searches in the namespace of the current controller for singular and plural versions of the conventional "#{model}Controller" syntax.
232
- # You may override this method to customize the search routine.
312
+ # Searches in the namespace of the current controller for singular
313
+ # and plural versions of the conventional "#{model}Controller"
314
+ # syntax. You may override this method to customize the search
315
+ # routine.
233
316
  def active_scaffold_controller_for(klass)
234
317
  controller_namespace = self.to_s.split('::')[0...-1].join('::') + '::'
235
318
  error_message = []
@@ -260,22 +343,29 @@ module ActiveScaffold
260
343
  end
261
344
  end
262
345
 
263
- ##
264
- ## Initialize the environment
265
- ##
266
- unless Rails::VERSION::MAJOR == 3 && Rails::VERSION::MINOR >= 0
267
- raise "This version of ActiveScaffold requires Rails 3.0 or higher. Please use an earlier version."
268
- end
346
+ # TODO: clean up extensions. some could be organized for autoloading, and others could be removed entirely.
347
+ Dir["#{File.dirname __FILE__}/extensions/*.rb"].each { |file| require file }
348
+
349
+ ActionController::Base.send(:include, ActiveScaffold)
350
+ ActionController::Base.send(:include, RespondsToParent)
351
+ ActionController::Base.send(:include, ActiveScaffold::Helpers::ControllerHelpers)
352
+ ActionView::Base.send(:include, ActiveScaffold::Helpers::ViewHelpers)
353
+
354
+ ActionController::Base.class_eval {include ActiveRecordPermissions::ModelUserAccess::Controller}
355
+ ActiveRecord::Base.class_eval {include ActiveRecordPermissions::ModelUserAccess::Model}
356
+ ActiveRecord::Base.class_eval {include ActiveRecordPermissions::Permissions}
269
357
 
270
- require File.dirname(__FILE__) + '/../environment'
358
+ I18n.load_path += Dir[File.join(File.dirname(__FILE__), 'active_scaffold', 'locale', '*.{rb,yml}')]
359
+ #ActiveScaffold.js_framework = :jquery
271
360
 
272
361
  ##
273
362
  ## Run the install assets script, too, just to make sure
274
363
  ## But at least rescue the action in production
275
364
  ##
276
- Rails::Application.initializer("active_scaffold_install_assets") do
365
+ Rails::Application.initializer("active_scaffold.install_assets") do
277
366
  begin
278
- require File.dirname(__FILE__) + '/../install_assets'
367
+ ActiveScaffold.delete_stale_assets
368
+ ActiveScaffold.install_assets_from(ActiveScaffold.root)
279
369
  rescue
280
370
  raise $! unless Rails.env == 'production'
281
371
  end
@@ -1,5 +1,9 @@
1
1
  module ActiveScaffold::Actions
2
- # The Nested module basically handles automatically linking controllers together. It does this by creating column links with the right parameters, and by providing any supporting systems (like a /:controller/nested action for returning associated scaffolds).
2
+ # The Nested module basically handles automatically linking
3
+ # controllers together. It does this by creating column links with
4
+ # the right parameters, and by providing any supporting systems
5
+ # (like a /:controller/nested action for returning associated
6
+ # scaffolds).
3
7
  module Nested
4
8
 
5
9
  def self.included(base)
@@ -4,7 +4,10 @@ module ActiveScaffold::Actions
4
4
  @parent_record = params[:id].nil? ? active_scaffold_config.model.new : find_if_allowed(params[:id], :update)
5
5
  @column = active_scaffold_config.columns[params[:association]]
6
6
 
7
- # NOTE: we don't check whether the user is allowed to update this record, because if not, we'll still let them associate the record. we'll just refuse to do more than associate, is all.
7
+ # NOTE: we don't check whether the user is allowed to update
8
+ # this record, because if not, we'll still let them associate
9
+ # the record. we'll just refuse to do more than associate, is
10
+ # all.
8
11
  @record = @column.association.klass.find(params[:associated_id]) if params[:associated_id]
9
12
  @record ||= @column.association.klass.new
10
13
 
@@ -56,11 +56,11 @@ module ActiveScaffold
56
56
  if multi_parameter_attributes.has_key? column.name
57
57
  parent_record.send(:assign_multiparameter_attributes, multi_parameter_attributes[column.name])
58
58
  elsif attributes.has_key? column.name
59
- value = column_value_from_param_value(parent_record, column, attributes[column.name])
59
+ value = column_value_from_param_value(parent_record, column, attributes[column.name])
60
60
 
61
61
  # we avoid assigning a value that already exists because otherwise has_one associations will break (AR bug in has_one_association.rb#replace)
62
62
  parent_record.send("#{column.name}=", value) unless parent_record.send(column.name) == value
63
-
63
+
64
64
  # plural associations may not actually appear in the params if all of the options have been unselected or cleared away.
65
65
  # the "form_ui" check is necessary, becuase without it we have problems
66
66
  # with subforms. the UI cuts out deep associations, which means they're not present in the
@@ -85,7 +85,7 @@ module ActiveScaffold
85
85
 
86
86
  parent_record
87
87
  end
88
-
88
+
89
89
  def manage_nested_record_from_params(parent_record, column, attributes)
90
90
  record = find_or_create_for_params(attributes, column, parent_record)
91
91
  if record
@@ -95,7 +95,7 @@ module ActiveScaffold
95
95
  end
96
96
  record
97
97
  end
98
-
98
+
99
99
  def column_value_from_param_value(parent_record, column, value)
100
100
  # convert the value, possibly by instantiating associated objects
101
101
  if value.is_a?(Hash)
@@ -37,11 +37,8 @@ module ActiveScaffold
37
37
  end
38
38
 
39
39
  def self.run_all
40
- return false if self.bridges_run
41
- ActiveScaffold::Bridges::Bridge.bridges.each{|bridge|
42
- bridge.run
43
- }
44
- self.bridges_run=true
40
+ self.bridges.each(&:run) unless self.bridges_run
41
+ self.bridges_run = true
45
42
  end
46
43
  end
47
44
  end
@@ -9,7 +9,7 @@ module ActiveScaffold::Config
9
9
  # full configuration path is: defaults => global table => local table
10
10
  @per_page = self.class.per_page
11
11
  @page_links_window = self.class.page_links_window
12
-
12
+
13
13
  # originates here
14
14
  @sorting = ActiveScaffold::DataStructures::Sorting.new(@core.columns)
15
15
  @sorting.set_default_sorting(@core.model)
@@ -49,7 +49,7 @@ module ActiveScaffold::Config
49
49
  self.columns = @core.columns._inheritable unless @columns # lazy evaluation
50
50
  @columns
51
51
  end
52
-
52
+
53
53
  public :columns=
54
54
 
55
55
  # how many rows to show at once
@@ -79,7 +79,7 @@ module ActiveScaffold::Config
79
79
  def sorting
80
80
  @sorting ||= ActiveScaffold::DataStructures::Sorting.new(@core.columns)
81
81
  end
82
-
82
+
83
83
  # overwrite the includes used for the count sql query
84
84
  attr_accessor :count_includes
85
85
 
@@ -98,29 +98,29 @@ module ActiveScaffold::Config
98
98
  def filtered_message
99
99
  @filtered_message ? @filtered_message : :filtered
100
100
  end
101
-
101
+
102
102
  attr_writer :always_show_search
103
103
  def always_show_search
104
104
  @always_show_search && !search_partial.blank?
105
105
  end
106
-
106
+
107
107
  def search_partial
108
108
  return "search" if @core.actions.include?(:search)
109
109
  return "field_search" if @core.actions.include?(:field_search)
110
110
  end
111
-
111
+
112
112
  # always show create
113
113
  attr_writer :always_show_create
114
114
  def always_show_create
115
115
  @always_show_create && @core.actions.include?(:create)
116
116
  end
117
-
117
+
118
118
  # might be set to open nested_link automatically in view
119
119
  # conf.nested.add_link(:players)
120
120
  # conf.list.nested_auto_open = {:players => 2}
121
121
  # will open nested players view if there are 2 or less records in parent
122
122
  attr_accessor :nested_auto_open
123
-
123
+
124
124
  class UserSettings < UserSettings
125
125
  # This label has alread been localized.
126
126
  def label
@@ -165,7 +165,7 @@ module ActiveScaffold::Config
165
165
  return default_sorting
166
166
  end
167
167
  end
168
-
168
+
169
169
  def count_includes
170
170
  @conf.count_includes
171
171
  end
@@ -33,6 +33,6 @@ module ActiveScaffold::Config
33
33
  def hide_nested_column
34
34
  @hide_nested_column.nil? ? true : @hide_nested_column
35
35
  end
36
-
36
+
37
37
  end
38
38
  end
@@ -73,12 +73,13 @@ module ActiveScaffold::DataStructures
73
73
  end
74
74
 
75
75
  def traverse(controller, options = {}, &block)
76
- @set.each do |link|
76
+ traverse_method = options.delete(:reverse).nil? ? :each : :reverse_each
77
+ @set.send(traverse_method) do |link|
77
78
  if link.is_a?(ActiveScaffold::DataStructures::ActionLinks)
78
79
  # add top node only if there is anything in the list
79
80
  #yield({:kind => :node, :level => 1, :last => false, :link => link})
80
81
  yield(link, nil, {:node => :start_traversing})
81
- link.traverse(options, &block)
82
+ link.traverse(controller,options, &block)
82
83
  yield(link, nil, {:node => :finished_traversing})
83
84
  #yield({:kind => :completed_group, :level => 1, :last => false, :link => link})
84
85
  elsif controller.nil? || !skip_action_link(controller, link, options[:record])
@@ -89,7 +90,7 @@ module ActiveScaffold::DataStructures
89
90
  end
90
91
 
91
92
  def collect
92
- @set.collect
93
+ @set
93
94
  end
94
95
 
95
96
  def empty?
@@ -98,7 +98,7 @@ module ActiveScaffold
98
98
  nil
99
99
  end
100
100
  end
101
-
101
+
102
102
  def condition_value_for_datetime(value, conversion = :to_time)
103
103
  if value.is_a? Hash
104
104
  Time.zone.local(*[:year, :month, :day, :hour, :minute, :second].collect {|part| value[field][part].to_i}) rescue nil
@@ -132,7 +132,7 @@ module ActiveScaffold
132
132
  value
133
133
  end
134
134
  end
135
-
135
+
136
136
  def condition_for_datetime(column, value, like_pattern = nil)
137
137
  conversion = column.column.type == :date ? :to_date : :to_time
138
138
  from_value = condition_value_for_datetime(value[:from], conversion)
@@ -156,7 +156,7 @@ module ActiveScaffold
156
156
  ["#{column.search_sql} = ?", value]
157
157
  end
158
158
  end
159
-
159
+
160
160
  def condition_for_null_type(column, value, like_pattern = nil)
161
161
  case value.to_sym
162
162
  when :null
@@ -196,8 +196,8 @@ module ActiveScaffold
196
196
  :null,
197
197
  :not_null
198
198
  ]
199
-
200
-
199
+
200
+
201
201
 
202
202
  def self.included(klass)
203
203
  klass.extend ClassMethods
@@ -219,7 +219,7 @@ module ActiveScaffold
219
219
  def active_scaffold_habtm_joins
220
220
  @active_scaffold_habtm_joins ||= []
221
221
  end
222
-
222
+
223
223
  def all_conditions
224
224
  merge_conditions(
225
225
  active_scaffold_conditions, # from the search modules
@@ -229,7 +229,7 @@ module ActiveScaffold
229
229
  active_scaffold_session_storage[:conditions] # embedding conditions (weaker constraints)
230
230
  )
231
231
  end
232
-
232
+
233
233
  # returns a single record (the given id) but only if it's allowed for the specified action.
234
234
  # accomplishes this by checking model.#{action}_authorized?
235
235
  # TODO: this should reside on the model, not the controller
@@ -255,19 +255,19 @@ module ActiveScaffold
255
255
  options[:count_includes] ||= full_includes unless search_conditions.nil?
256
256
 
257
257
  klass = beginning_of_chain
258
-
258
+
259
259
  # create a general-use options array that's compatible with Rails finders
260
260
  finder_options = { :order => options[:sorting].try(:clause),
261
261
  :where => search_conditions,
262
262
  :joins => joins_for_finder,
263
263
  :includes => options[:count_includes]}
264
-
264
+
265
265
  finder_options.merge! custom_finder_options
266
266
 
267
267
  # NOTE: we must use :include in the count query, because some conditions may reference other tables
268
268
  count_query = append_to_query(klass, finder_options.reject{|k, v| [:select, :order].include?(k)})
269
269
  count = count_query.count unless options[:pagination] == :infinite
270
-
270
+
271
271
  # Converts count to an integer if ActiveRecord returned an OrderedHash
272
272
  # that happens when finder_options contains a :group key
273
273
  count = count.length if count.is_a? ActiveSupport::OrderedHash
@@ -288,11 +288,11 @@ module ActiveScaffold
288
288
  end
289
289
  pager.page(options[:page])
290
290
  end
291
-
291
+
292
292
  def append_to_query(query, options)
293
293
  options.assert_valid_keys :where, :select, :group, :order, :limit, :offset, :joins, :includes, :lock, :readonly, :from
294
294
  options.reject{|k, v| v.blank?}.inject(query) do |query, (k, v)|
295
- query.send((k.to_sym), v)
295
+ query.send((k.to_sym), v)
296
296
  end
297
297
  end
298
298
 
@@ -306,7 +306,7 @@ module ActiveScaffold
306
306
  []
307
307
  end + active_scaffold_habtm_joins
308
308
  end
309
-
309
+
310
310
  def merge_conditions(*conditions)
311
311
  segments = []
312
312
  conditions.each do |condition|