radiant 0.6.3 → 0.6.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of radiant might be problematic. Click here for more details.

Files changed (197) hide show
  1. data/CHANGELOG +61 -7
  2. data/CONTRIBUTORS +15 -0
  3. data/app/controllers/admin/export_controller.rb +1 -1
  4. data/app/controllers/admin/page_controller.rb +1 -0
  5. data/app/controllers/admin/user_controller.rb +2 -1
  6. data/app/controllers/application.rb +7 -8
  7. data/app/helpers/admin/node_helper.rb +84 -0
  8. data/app/helpers/admin/page_helper.rb +1 -19
  9. data/app/helpers/application_helper.rb +15 -9
  10. data/app/models/file_not_found_page.rb +2 -2
  11. data/app/models/page.rb +22 -18
  12. data/app/models/page_context.rb +9 -0
  13. data/app/models/radiant/config.rb +4 -2
  14. data/app/models/response_cache.rb +18 -12
  15. data/app/models/standard_tags.rb +111 -50
  16. data/app/views/admin/extension/index.rhtml +2 -2
  17. data/app/views/admin/layout/edit.rhtml +2 -2
  18. data/app/views/admin/layout/remove.rhtml +2 -2
  19. data/app/views/admin/page/_node.rhtml +4 -26
  20. data/app/views/admin/page/_part.rhtml +9 -14
  21. data/app/views/admin/page/edit.rhtml +38 -121
  22. data/app/views/admin/page/index.rhtml +2 -6
  23. data/app/views/admin/page/remove.rhtml +2 -2
  24. data/app/views/admin/snippet/edit.rhtml +3 -3
  25. data/app/views/admin/snippet/index.rhtml +2 -2
  26. data/app/views/admin/snippet/remove.rhtml +2 -2
  27. data/app/views/admin/user/edit.rhtml +4 -4
  28. data/app/views/admin/user/preferences.rhtml +2 -2
  29. data/app/views/admin/welcome/login.rhtml +1 -1
  30. data/config/environment.rb +79 -78
  31. data/db/schema.rb +2 -0
  32. data/lib/local_time.rb +12 -0
  33. data/lib/plugins/extension_patches/lib/fixture_loading_extension.rb +1 -1
  34. data/lib/plugins/extension_patches/lib/mailer_view_paths_extension.rb +3 -3
  35. data/lib/radiant.rb +1 -1
  36. data/lib/radiant/extension.rb +9 -3
  37. data/lib/radiant/extension_loader.rb +2 -2
  38. data/lib/tasks/extensions.rake +23 -8
  39. data/public/javascripts/admin.js +89 -0
  40. data/public/javascripts/controls.js +486 -354
  41. data/public/javascripts/dragdrop.js +90 -58
  42. data/public/javascripts/effects.js +398 -364
  43. data/public/javascripts/pngfix.js +37 -37
  44. data/public/javascripts/prototype.js +2764 -1095
  45. data/public/javascripts/ruledtable.js +10 -25
  46. data/public/javascripts/sitemap.js +74 -112
  47. data/public/javascripts/string.js +1 -7
  48. data/public/javascripts/tabcontrol.js +71 -86
  49. data/public/javascripts/tag_reference_search.js +19 -26
  50. data/public/stylesheets/admin/main.css +11 -5
  51. data/test/fixtures/extensions/01_basic/lib/new_module.rb +2 -0
  52. data/test/fixtures/page_parts.yml +16 -1
  53. data/test/fixtures/pages.yml +47 -84
  54. data/test/functional/extension_initialization_test.rb +11 -0
  55. data/test/helpers/login_test_helper.rb +12 -1
  56. data/test/helpers/page_test_helper.rb +6 -0
  57. data/test/helpers/render_test_helper.rb +11 -8
  58. data/test/test_helper.rb +1 -12
  59. data/test/unit/file_not_found_page_test.rb +5 -1
  60. data/test/unit/local_time_test.rb +45 -0
  61. data/test/unit/page_context_test.rb +32 -1
  62. data/test/unit/page_test.rb +45 -11
  63. data/test/unit/radiant/config_test.rb +1 -1
  64. data/test/unit/response_cache_test.rb +27 -2
  65. data/test/unit/standard_tags_test.rb +60 -15
  66. data/vendor/extensions/archive/README +29 -0
  67. data/vendor/extensions/archive/Rakefile +25 -0
  68. data/{app → vendor/extensions/archive/app}/models/archive_day_index_page.rb +0 -0
  69. data/{app → vendor/extensions/archive/app}/models/archive_finder.rb +8 -6
  70. data/{app → vendor/extensions/archive/app}/models/archive_month_index_page.rb +0 -0
  71. data/{app → vendor/extensions/archive/app}/models/archive_page.rb +0 -0
  72. data/{app → vendor/extensions/archive/app}/models/archive_year_index_page.rb +0 -0
  73. data/vendor/extensions/archive/archive_extension.rb +19 -0
  74. data/{lib → vendor/extensions/archive/lib}/archive_index_tags_and_methods.rb +0 -0
  75. data/vendor/extensions/archive/lib/tasks/archive_extension_tasks.rake +28 -0
  76. data/vendor/extensions/archive/test/fixtures/pages.yml +397 -0
  77. data/vendor/extensions/archive/test/functional/archive_extension_test.rb +16 -0
  78. data/{test → vendor/extensions/archive/test}/helpers/archive_index_test_helper.rb +0 -0
  79. data/vendor/extensions/archive/test/test_helper.rb +19 -0
  80. data/{test → vendor/extensions/archive/test}/unit/archive_day_index_page_test.rb +0 -0
  81. data/{test → vendor/extensions/archive/test}/unit/archive_month_index_page_test.rb +0 -0
  82. data/{test → vendor/extensions/archive/test}/unit/archive_page_test.rb +7 -1
  83. data/{test → vendor/extensions/archive/test}/unit/archive_year_index_page_test.rb +0 -0
  84. data/vendor/rails/actionmailer/CHANGELOG +10 -0
  85. data/vendor/rails/actionmailer/Rakefile +1 -1
  86. data/vendor/rails/actionmailer/lib/action_mailer/version.rb +1 -1
  87. data/vendor/rails/actionpack/CHANGELOG +51 -2
  88. data/vendor/rails/actionpack/Rakefile +1 -1
  89. data/vendor/rails/actionpack/lib/action_controller/assertions/dom_assertions.rb +2 -2
  90. data/vendor/rails/actionpack/lib/action_controller/assertions/model_assertions.rb +1 -1
  91. data/vendor/rails/actionpack/lib/action_controller/assertions/response_assertions.rb +3 -0
  92. data/vendor/rails/actionpack/lib/action_controller/assertions/routing_assertions.rb +1 -0
  93. data/vendor/rails/actionpack/lib/action_controller/assertions/selector_assertions.rb +2 -0
  94. data/vendor/rails/actionpack/lib/action_controller/base.rb +7 -1
  95. data/vendor/rails/actionpack/lib/action_controller/caching.rb +39 -38
  96. data/vendor/rails/actionpack/lib/action_controller/cgi_ext/pstore_performance_fix.rb +30 -0
  97. data/vendor/rails/actionpack/lib/action_controller/cgi_ext/raw_post_data_fix.rb +1 -1
  98. data/vendor/rails/actionpack/lib/action_controller/cgi_process.rb +13 -4
  99. data/vendor/rails/actionpack/lib/action_controller/cookies.rb +5 -3
  100. data/vendor/rails/actionpack/lib/action_controller/filters.rb +176 -77
  101. data/vendor/rails/actionpack/lib/action_controller/integration.rb +31 -21
  102. data/vendor/rails/actionpack/lib/action_controller/macros/in_place_editing.rb +1 -1
  103. data/vendor/rails/actionpack/lib/action_controller/pagination.rb +7 -1
  104. data/vendor/rails/actionpack/lib/action_controller/resources.rb +117 -32
  105. data/vendor/rails/actionpack/lib/action_controller/routing.rb +56 -23
  106. data/vendor/rails/actionpack/lib/action_controller/test_process.rb +5 -2
  107. data/vendor/rails/actionpack/lib/action_controller/url_rewriter.rb +4 -1
  108. data/vendor/rails/actionpack/lib/action_controller/verification.rb +1 -0
  109. data/vendor/rails/actionpack/lib/action_pack/version.rb +1 -1
  110. data/vendor/rails/actionpack/lib/action_view/base.rb +25 -19
  111. data/vendor/rails/actionpack/lib/action_view/compiled_templates.rb +2 -2
  112. data/vendor/rails/actionpack/lib/action_view/helpers/active_record_helper.rb +18 -18
  113. data/vendor/rails/actionpack/lib/action_view/helpers/debug_helper.rb +10 -0
  114. data/vendor/rails/actionpack/lib/action_view/helpers/deprecated_helper.rb +3 -0
  115. data/vendor/rails/actionpack/lib/action_view/helpers/prototype_helper.rb +33 -17
  116. data/vendor/rails/actionpack/test/activerecord/pagination_test.rb +9 -0
  117. data/vendor/rails/actionpack/test/controller/action_pack_assertions_test.rb +13 -0
  118. data/vendor/rails/actionpack/test/controller/addresses_render_test.rb +4 -1
  119. data/vendor/rails/actionpack/test/controller/base_test.rb +1 -1
  120. data/vendor/rails/actionpack/test/controller/caching_test.rb +3 -2
  121. data/vendor/rails/actionpack/test/controller/cookie_test.rb +11 -0
  122. data/vendor/rails/actionpack/test/controller/deprecation/deprecated_base_methods_test.rb +18 -0
  123. data/vendor/rails/actionpack/test/controller/filter_params_test.rb +1 -0
  124. data/vendor/rails/actionpack/test/controller/filters_test.rb +149 -26
  125. data/vendor/rails/actionpack/test/controller/integration_test.rb +93 -8
  126. data/vendor/rails/actionpack/test/controller/resources_test.rb +215 -36
  127. data/vendor/rails/actionpack/test/controller/routing_test.rb +2 -2
  128. data/vendor/rails/actionpack/test/controller/test_test.rb +16 -0
  129. data/vendor/rails/actionpack/test/controller/url_rewriter_test.rb +66 -10
  130. data/vendor/rails/actionpack/test/controller/verification_test.rb +15 -0
  131. data/vendor/rails/actionpack/test/fixtures/test/hello_world.rxml +2 -1
  132. data/vendor/rails/actionpack/test/template/asset_tag_helper_test.rb +5 -0
  133. data/vendor/rails/actionpack/test/template/compiled_templates_test.rb +29 -17
  134. data/vendor/rails/actionpack/test/template/javascript_helper_test.rb +4 -4
  135. data/vendor/rails/actionpack/test/template/number_helper_test.rb +1 -1
  136. data/vendor/rails/actionpack/test/template/prototype_helper_test.rb +13 -13
  137. data/vendor/rails/actionwebservice/CHANGELOG +14 -0
  138. data/vendor/rails/actionwebservice/Rakefile +2 -2
  139. data/vendor/rails/actionwebservice/lib/action_web_service/version.rb +1 -1
  140. data/vendor/rails/activerecord/CHANGELOG +34 -0
  141. data/vendor/rails/activerecord/Rakefile +1 -1
  142. data/vendor/rails/activerecord/lib/active_record/acts/list.rb +14 -2
  143. data/vendor/rails/activerecord/lib/active_record/acts/tree.rb +7 -0
  144. data/vendor/rails/activerecord/lib/active_record/associations.rb +29 -14
  145. data/vendor/rails/activerecord/lib/active_record/associations/association_collection.rb +5 -1
  146. data/vendor/rails/activerecord/lib/active_record/associations/has_many_association.rb +2 -2
  147. data/vendor/rails/activerecord/lib/active_record/associations/has_many_through_association.rb +10 -0
  148. data/vendor/rails/activerecord/lib/active_record/base.rb +12 -3
  149. data/vendor/rails/activerecord/lib/active_record/calculations.rb +2 -2
  150. data/vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
  151. data/vendor/rails/activerecord/lib/active_record/connection_adapters/oracle_adapter.rb +1 -0
  152. data/vendor/rails/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb +2 -2
  153. data/vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb +54 -38
  154. data/vendor/rails/activerecord/lib/active_record/deprecated_finders.rb +3 -3
  155. data/vendor/rails/activerecord/lib/active_record/fixtures.rb +1 -1
  156. data/vendor/rails/activerecord/lib/active_record/timestamp.rb +0 -9
  157. data/vendor/rails/activerecord/lib/active_record/version.rb +1 -1
  158. data/vendor/rails/activerecord/test/associations/eager_test.rb +13 -0
  159. data/vendor/rails/activerecord/test/associations/join_model_test.rb +10 -1
  160. data/vendor/rails/activerecord/test/associations_test.rb +36 -3
  161. data/vendor/rails/activerecord/test/base_test.rb +17 -4
  162. data/vendor/rails/activerecord/test/defaults_test.rb +15 -0
  163. data/vendor/rails/activerecord/test/fixtures/author.rb +1 -0
  164. data/vendor/rails/activerecord/test/fixtures/binaries.yml +437 -0
  165. data/vendor/rails/activerecord/test/fixtures/db_definitions/schema.rb +13 -0
  166. data/vendor/rails/activerecord/test/fixtures/developer.rb +10 -0
  167. data/vendor/rails/activerecord/test/fixtures_test.rb +9 -5
  168. data/vendor/rails/activerecord/test/migration_test.rb +9 -10
  169. data/vendor/rails/activerecord/test/mixin_test.rb +47 -0
  170. data/vendor/rails/activerecord/test/validations_test.rb +2 -2
  171. data/vendor/rails/activesupport/CHANGELOG +16 -0
  172. data/vendor/rails/activesupport/lib/active_support/core_ext/blank.rb +9 -3
  173. data/vendor/rails/activesupport/lib/active_support/core_ext/hash/conversions.rb +48 -3
  174. data/vendor/rails/activesupport/lib/active_support/core_ext/module/introspection.rb +14 -0
  175. data/vendor/rails/activesupport/lib/active_support/dependencies.rb +3 -3
  176. data/vendor/rails/activesupport/lib/active_support/json/encoders/core.rb +5 -3
  177. data/vendor/rails/activesupport/lib/active_support/multibyte/chars.rb +6 -6
  178. data/vendor/rails/activesupport/lib/active_support/version.rb +1 -1
  179. data/vendor/rails/activesupport/test/core_ext/hash_ext_test.rb +37 -0
  180. data/vendor/rails/activesupport/test/core_ext/module_test.rb +8 -0
  181. data/vendor/rails/activesupport/test/dependencies_test.rb +11 -0
  182. data/vendor/rails/activesupport/test/{json.rb → json_test.rb} +15 -5
  183. data/vendor/rails/railties/CHANGELOG +25 -1
  184. data/vendor/rails/railties/README +32 -3
  185. data/vendor/rails/railties/Rakefile +5 -5
  186. data/vendor/rails/railties/environments/boot.rb +12 -18
  187. data/vendor/rails/railties/environments/environment.rb +15 -15
  188. data/vendor/rails/railties/lib/dispatcher.rb +1 -2
  189. data/vendor/rails/railties/lib/initializer.rb +33 -9
  190. data/vendor/rails/railties/lib/rails/version.rb +1 -1
  191. data/vendor/rails/railties/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb +1 -1
  192. data/vendor/rails/railties/lib/rails_generator/generators/components/scaffold_resource/scaffold_resource_generator.rb +1 -0
  193. data/vendor/rails/railties/lib/railties_path.rb +1 -1
  194. data/vendor/rails/railties/lib/tasks/framework.rake +4 -4
  195. data/vendor/rails/railties/lib/tasks/routes.rake +17 -0
  196. data/vendor/rails/release.rb +2 -2
  197. metadata +1877 -1848
@@ -1,78 +1,79 @@
1
- # Uncomment below to force Rails into production mode when
2
- # you don't control web/app server and can't set it the proper way
3
- # ENV['RAILS_ENV'] ||= 'production'
4
-
5
- # Bootstrap the Rails environment, frameworks, and default configuration
6
- require File.join(File.dirname(__FILE__), 'boot')
7
-
8
- require 'radius'
9
-
10
- Radiant::Initializer.run do |config|
11
- # Settings in config/environments/* take precedence those specified here
12
-
13
- # Skip frameworks you're not going to use
14
- config.frameworks -= [ :action_web_service, :action_mailer ]
15
-
16
- # Add additional load paths for when Radiant is running in instance mode
17
- config.load_paths += %w(
18
- app/controllers
19
- app/models
20
- app/helpers
21
- lib
22
- ).map { |path| File.join(RADIANT_ROOT, path) }
23
- config.controller_paths << File.join(RADIANT_ROOT, 'app', 'controllers')
24
- config.view_path = File.join(RADIANT_ROOT, 'app', 'views')
25
-
26
- # Only load the extensions named here, in the order given. By default all plugins in vendor/extensions are
27
- # loaded, in alphabetical order. :all can be used as a placeholder for all extensions not explicitly named.
28
- # config.extensions = [ :textile_filter, :markdown_filter, :all ]
29
-
30
- # Force all environments to use the same logger level
31
- # (by default production uses :info, the others :debug)
32
- # config.log_level = :debug
33
-
34
- # Use the database for sessions instead of the file system
35
- # (create the session table with 'rake create_sessions_table')
36
- # config.action_controller.session_store = :active_record_store
37
-
38
- # Enable page/fragment caching by setting a file-based store
39
- # (remember to create the caching directory and make it readable to the application)
40
- # config.action_controller.fragment_cache_store = :file_store, "#{RAILS_ROOT}/fragment_cache"
41
- config.action_controller.page_cache_directory = "#{RAILS_ROOT}/cache"
42
-
43
- # Make Active Record use UTC-base instead of local time
44
- config.active_record.default_timezone = :utc
45
-
46
- # Activate observers that should always be running
47
- config.active_record.observers = :user_action_observer
48
-
49
- # Make sure plugins are loaded from lib and vendor
50
- config.plugin_paths = [
51
- "#{RAILS_ROOT}/vendor/plugins",
52
- "#{RADIANT_ROOT}/lib/plugins",
53
- "#{RADIANT_ROOT}/vendor/plugins"
54
- ]
55
-
56
- # Use ActiveRecord sessions
57
- config.action_controller.session_store = :active_record_store
58
-
59
- # See Rails::Configuration for more options
60
- end
61
-
62
- # Add new inflection rules using the following format:
63
- Inflector.inflections do |inflect|
64
- inflect.uncountable 'config'
65
- inflect.uncountable 'meta'
66
- end
67
-
68
- # Auto-require text filters
69
- Dir["#{RADIANT_ROOT}/app/models/*_filter.rb"].each do |filter|
70
- filter = $1 if filter =~ %r{/([^/]+)\.rb}
71
- require_dependency filter
72
- end
73
-
74
- # Response Caching Defaults
75
- ResponseCache.defaults[:directory] = ActionController::Base.page_cache_directory
76
- ResponseCache.defaults[:logger] = ActionController::Base.logger
77
-
78
- require "status"
1
+ # Uncomment below to force Rails into production mode when
2
+ # you don't control web/app server and can't set it the proper way
3
+ # ENV['RAILS_ENV'] ||= 'production'
4
+
5
+ # Bootstrap the Rails environment, frameworks, and default configuration
6
+ require File.join(File.dirname(__FILE__), 'boot')
7
+
8
+ require 'radius'
9
+
10
+ Radiant::Initializer.run do |config|
11
+ # Settings in config/environments/* take precedence those specified here
12
+
13
+ # Skip frameworks you're not going to use
14
+ config.frameworks -= [ :action_web_service, :action_mailer ]
15
+
16
+ # Add additional load paths for when Radiant is running in instance mode
17
+ config.load_paths += %w(
18
+ app/controllers
19
+ app/models
20
+ app/helpers
21
+ lib
22
+ ).map { |path| File.join(RADIANT_ROOT, path) }
23
+ config.controller_paths << File.join(RADIANT_ROOT, 'app', 'controllers')
24
+ config.view_path = File.join(RADIANT_ROOT, 'app', 'views')
25
+
26
+ # Only load the extensions named here, in the order given. By default all plugins in vendor/extensions are
27
+ # loaded, in alphabetical order. :all can be used as a placeholder for all extensions not explicitly named.
28
+ # config.extensions = [ :textile_filter, :markdown_filter, :all ]
29
+
30
+ # Force all environments to use the same logger level
31
+ # (by default production uses :info, the others :debug)
32
+ # config.log_level = :debug
33
+
34
+ # Use the database for sessions instead of the file system
35
+ # (create the session table with 'rake create_sessions_table')
36
+ # config.action_controller.session_store = :active_record_store
37
+
38
+ # Enable page/fragment caching by setting a file-based store
39
+ # (remember to create the caching directory and make it readable to the application)
40
+ # config.action_controller.fragment_cache_store = :file_store, "#{RAILS_ROOT}/fragment_cache"
41
+ config.action_controller.page_cache_directory = "#{RAILS_ROOT}/cache"
42
+
43
+ # Make Active Record use UTC-base instead of local time
44
+ config.active_record.default_timezone = :utc
45
+
46
+ # Activate observers that should always be running
47
+ config.active_record.observers = :user_action_observer
48
+
49
+ # Make sure plugins are loaded from lib and vendor
50
+ config.plugin_paths = [
51
+ "#{RAILS_ROOT}/vendor/plugins",
52
+ "#{RADIANT_ROOT}/lib/plugins",
53
+ "#{RADIANT_ROOT}/vendor/plugins"
54
+ ]
55
+
56
+ # Use ActiveRecord sessions
57
+ config.action_controller.session_store = :active_record_store
58
+
59
+ # See Rails::Configuration for more options
60
+ end
61
+
62
+ # Add new inflection rules using the following format:
63
+ Inflector.inflections do |inflect|
64
+ inflect.uncountable 'config'
65
+ inflect.uncountable 'meta'
66
+ end
67
+
68
+ # Auto-require text filters
69
+ Dir["#{RADIANT_ROOT}/app/models/*_filter.rb"].each do |filter|
70
+ require_dependency File.basename(filter).sub(/\.rb$/, '')
71
+ end
72
+
73
+ # Response Caching Defaults
74
+ ResponseCache.defaults[:directory] = ActionController::Base.page_cache_directory
75
+ ResponseCache.defaults[:logger] = ActionController::Base.logger
76
+
77
+ ActionView::Base.field_error_proc = Proc.new do |html, instance|
78
+ %{<div class="error-with-field">#{html} <small class="error">&bull; #{[instance.error_message].flatten.first}</small></div>}
79
+ end
data/db/schema.rb CHANGED
@@ -50,6 +50,8 @@ ActiveRecord::Schema.define(:version => 16) do
50
50
  t.column "updated_by", :integer
51
51
  t.column "virtual", :boolean, :default => false, :null => false
52
52
  t.column "lock_version", :integer, :default => 0
53
+ t.column "appears_on", :date
54
+ t.column "expires_on", :date
53
55
  end
54
56
 
55
57
  create_table "sessions", :force => true do |t|
data/lib/local_time.rb ADDED
@@ -0,0 +1,12 @@
1
+ require 'radiant/config'
2
+ module LocalTime
3
+ def adjust_time(time)
4
+ if (tz_string = Radiant::Config["local.timezone"]) and
5
+ timezone = (TimeZone[tz_string] || TimeZone[tz_string.to_i])
6
+ # adjust time
7
+ timezone.adjust(time)
8
+ else
9
+ time
10
+ end
11
+ end
12
+ end
@@ -17,7 +17,7 @@ module Radiant
17
17
  begin
18
18
  directory = paths.pop
19
19
  fixtures_map[table_name] = Fixtures.new(connection, File.split(table_name.to_s).last, class_names[table_name.to_sym], File.join(directory, table_name))
20
- rescue Exception => e
20
+ rescue SystemCallError => e
21
21
  retry unless paths.empty?
22
22
  raise e
23
23
  end
@@ -43,7 +43,7 @@ module Radiant
43
43
  next unless md = /^([^\.]+)\.([^\.]+\.[^\+]+)\.(rhtml|rxml)$/.match(basename)
44
44
  template_name = basename
45
45
  content_type = md.captures[1].gsub('.', '/')
46
- @parts << Part.new(:content_type => content_type,
46
+ @parts << ActionMailer::Part.new(:content_type => content_type,
47
47
  :disposition => "inline", :charset => charset,
48
48
  :body => render_message(template_name, @body))
49
49
  end
@@ -65,7 +65,7 @@ module Radiant
65
65
  # we shift it onto the front of the parts and set the body to nil (so
66
66
  # that create_mail doesn't try to render it in addition to the parts).
67
67
  if !@parts.empty? && String === @body
68
- @parts.unshift Part.new(:charset => charset, :body => @body)
68
+ @parts.unshift ActionMailer::Part.new(:charset => charset, :body => @body)
69
69
  @body = nil
70
70
  end
71
71
  end
@@ -85,4 +85,4 @@ module Radiant
85
85
  end
86
86
  end
87
87
 
88
- ActionMailer::Base.send(:include, Radiant::MailerViewPathsExtension)
88
+ ActionMailer::Base.send(:include, Radiant::MailerViewPathsExtension)
data/lib/radiant.rb CHANGED
@@ -5,7 +5,7 @@ unless defined? Radiant::Version
5
5
  module Version
6
6
  Major = '0'
7
7
  Minor = '6'
8
- Tiny = '3'
8
+ Tiny = '4'
9
9
 
10
10
  class << self
11
11
  def to_s
@@ -80,12 +80,18 @@ module Radiant
80
80
  begin
81
81
  Radiant::Extension.const_get(const_name)
82
82
  rescue
83
- $LOAD_PATH << "#{plugin}/lib"
84
- require "#{plugin}/init.rb"
83
+ lib = "#{plugin}/lib"
84
+ init ="#{plugin}/init.rb"
85
+ if File.directory?(lib)
86
+ $LOAD_PATH << lib
87
+ Dependencies.load_paths << lib
88
+ Dependencies.load_once_paths << lib
89
+ end
90
+ require init if File.exists?(init)
85
91
  Radiant::Extension.const_set const_name, plugin
86
92
  end
87
93
  end
88
94
  end
89
95
  end
90
96
  end
91
- end
97
+ end
@@ -78,7 +78,7 @@ module Radiant
78
78
  extension_roots.each do |ext_path|
79
79
  load_paths = %w(lib app/models app/controllers app/helpers test/helpers).collect { |p| "#{ext_path}/#{p}" }
80
80
  load_paths << ext_path
81
- load_paths.each { |p| configuration.load_paths << p }
81
+ load_paths.each { |p| configuration.load_paths << p; $LOAD_PATH << p; }
82
82
  configuration.controller_paths << "#{ext_path}/app/controllers"
83
83
  configuration.view_paths << "#{ext_path}/app/views"
84
84
  @extension_roots << ext_path
@@ -133,4 +133,4 @@ module Radiant
133
133
  end
134
134
 
135
135
  end
136
- end
136
+ end
@@ -22,14 +22,29 @@ namespace :db do
22
22
  end
23
23
 
24
24
  namespace :test do
25
- desc "Runs tests on all available Radiant extensions"
25
+ desc "Runs tests on all available Radiant extensions, pass EXT=extension_name to test a single extension"
26
26
  task :extensions => "db:test:prepare" do
27
- Dir["#{RAILS_ROOT}/vendor/extensions/*"].sort.select { |f| File.directory?(f) }.each do |directory|
28
- chdir directory do
29
- if RUBY_PLATFORM =~ /win32/
30
- system "rake.cmd test"
31
- else
32
- system "rake test"
27
+ if ENV["EXT"]
28
+ extension = RAILS_ROOT + "/vendor/extensions/" + ENV["EXT"]
29
+ if File.directory?(extension)
30
+ chdir extension do
31
+ if RUBY_PLATFORM =~ /win32/
32
+ system "rake.cmd test"
33
+ else
34
+ system "rake test"
35
+ end
36
+ end
37
+ else
38
+ puts "Sorry, that extension is not installed."
39
+ end
40
+ else
41
+ Dir["#{RAILS_ROOT}/vendor/extensions/*"].sort.select { |f| File.directory?(f) }.each do |directory|
42
+ chdir directory do
43
+ if RUBY_PLATFORM =~ /win32/
44
+ system "rake.cmd test"
45
+ else
46
+ system "rake test"
47
+ end
33
48
  end
34
49
  end
35
50
  end
@@ -39,4 +54,4 @@ end
39
54
  # Load any custom rakefiles from extensions
40
55
  [RAILS_ROOT, RADIANT_ROOT].uniq.each do |root|
41
56
  Dir[root + '/vendor/extensions/**/tasks/**/*.rake'].sort.each { |ext| load ext }
42
- end
57
+ end
@@ -0,0 +1,89 @@
1
+ document.observe('dom:loaded', function() {
2
+ when('site-map', function(table) { new SiteMap(table) });
3
+
4
+ when('page_title', function(title) {
5
+ var slug = $('page_slug'),
6
+ breadcrumb = $('page_breadcrumb'),
7
+ oldTitle = title.value;
8
+
9
+ if (!slug || !breadcrumb) return;
10
+
11
+ new Form.Element.Observer(title, 0.15, function() {
12
+ if (oldTitle.toSlug() == slug.value) slug.value = title.value.toSlug();
13
+ if (oldTitle == breadcrumb.value) breadcrumb.value = title.value;
14
+ oldTitle = title.value;
15
+ });
16
+ });
17
+
18
+ when($$('#pages div.part > input[type=hidden]:first-child'), function(parts) {
19
+ tabControl = new TabControl('tab-control');
20
+
21
+ parts.each(function(part, index) {
22
+ var page = part.up('.page');
23
+ tabControl.addTab('tab-' + (index + 1), part.value, page.id);
24
+ });
25
+
26
+ tabControl.autoSelect();
27
+ });
28
+ });
29
+
30
+ // When object is available, do function fn.
31
+ function when(obj, fn) {
32
+ if (Object.isString(obj)) obj = /^[\w-]+$/.test(obj) ? $(obj) : $(document.body).down(obj);
33
+ if (Object.isArray(obj) && !obj.length) return;
34
+ if (obj) fn(obj);
35
+ }
36
+
37
+ function part_added() {
38
+ var partNameField = $('part-name-field');
39
+ var partIndexField = $('part-index-field');
40
+ var index = parseInt(partIndexField.value) + 1;
41
+ var tab = 'tab-' + index;
42
+ var caption = partNameField.value;
43
+ var page = 'page-' + index;
44
+ tabControl.addTab(tab, caption, page);
45
+ Element.hide('add-part-popup');
46
+ Element.hide('busy');
47
+ partNameField.value = '';
48
+ partIndexField.value = (index + 1).toString();
49
+ $('add-part-button').disabled = false;
50
+ Field.focus(partNameField);
51
+ tabControl.select(tab);
52
+ }
53
+ function part_loading() {
54
+ $('add-part-button').disabled = true;
55
+ $('busy').appear();
56
+ }
57
+ function valid_part_name() {
58
+ var partNameField = $('part-name-field');
59
+ var name = partNameField.value.downcase().strip();
60
+ var result = true;
61
+ if (name == '') {
62
+ alert('Part name cannot be empty.');
63
+ return false;
64
+ }
65
+ tabControl.tabs.each(function(pair){
66
+ if (tabControl.tabs.get(pair.key).caption == name) {
67
+ result = false;
68
+ alert('Part name must be unique.');
69
+ throw $break;
70
+ }
71
+ })
72
+ return result;
73
+ }
74
+ function center(element) {
75
+ var header = $('header')
76
+ element = $(element);
77
+ element.style.position = 'absolute';
78
+ var dim = Element.getDimensions(element);
79
+ var top = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop;
80
+ element.style.top = (top + 200) + 'px';
81
+ element.style.left = ((header.offsetWidth - dim.width) / 2) + 'px';
82
+ }
83
+ function toggle_add_part_popup() {
84
+ var popup = $('add-part-popup');
85
+ var partNameField = $('part-name-field');
86
+ center(popup);
87
+ Element.toggle(popup);
88
+ Field.focus(partNameField);
89
+ }
@@ -1,6 +1,8 @@
1
- // Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
2
- // (c) 2005, 2006 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
3
- // (c) 2005, 2006 Jon Tirsen (http://www.tirsen.com)
1
+ // script.aculo.us controls.js v1.8.0, Tue Nov 06 15:01:40 +0300 2007
2
+
3
+ // Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
4
+ // (c) 2005-2007 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
5
+ // (c) 2005-2007 Jon Tirsen (http://www.tirsen.com)
4
6
  // Contributors:
5
7
  // Richard Livsey
6
8
  // Rahul Bhargava
@@ -37,22 +39,23 @@
37
39
  if(typeof Effect == 'undefined')
38
40
  throw("controls.js requires including script.aculo.us' effects.js library");
39
41
 
40
- var Autocompleter = {}
41
- Autocompleter.Base = function() {};
42
- Autocompleter.Base.prototype = {
42
+ var Autocompleter = { }
43
+ Autocompleter.Base = Class.create({
43
44
  baseInitialize: function(element, update, options) {
44
- this.element = $(element);
45
+ element = $(element)
46
+ this.element = element;
45
47
  this.update = $(update);
46
48
  this.hasFocus = false;
47
49
  this.changed = false;
48
50
  this.active = false;
49
51
  this.index = 0;
50
52
  this.entryCount = 0;
53
+ this.oldElementValue = this.element.value;
51
54
 
52
55
  if(this.setOptions)
53
56
  this.setOptions(options);
54
57
  else
55
- this.options = options || {};
58
+ this.options = options || { };
56
59
 
57
60
  this.options.paramName = this.options.paramName || this.element.name;
58
61
  this.options.tokens = this.options.tokens || [];
@@ -74,6 +77,9 @@ Autocompleter.Base.prototype = {
74
77
 
75
78
  if(typeof(this.options.tokens) == 'string')
76
79
  this.options.tokens = new Array(this.options.tokens);
80
+ // Force carriage returns as token delimiters anyway
81
+ if (!this.options.tokens.include('\n'))
82
+ this.options.tokens.push('\n');
77
83
 
78
84
  this.observer = null;
79
85
 
@@ -81,15 +87,14 @@ Autocompleter.Base.prototype = {
81
87
 
82
88
  Element.hide(this.update);
83
89
 
84
- Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this));
85
- Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this));
90
+ Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this));
91
+ Event.observe(this.element, 'keypress', this.onKeyPress.bindAsEventListener(this));
86
92
  },
87
93
 
88
94
  show: function() {
89
95
  if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
90
96
  if(!this.iefix &&
91
- (navigator.appVersion.indexOf('MSIE')>0) &&
92
- (navigator.userAgent.indexOf('Opera')<0) &&
97
+ (Prototype.Browser.IE) &&
93
98
  (Element.getStyle(this.update, 'position')=='absolute')) {
94
99
  new Insertion.After(this.update,
95
100
  '<iframe id="' + this.update.id + '_iefix" '+
@@ -139,17 +144,17 @@ Autocompleter.Base.prototype = {
139
144
  case Event.KEY_UP:
140
145
  this.markPrevious();
141
146
  this.render();
142
- if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
147
+ if(Prototype.Browser.WebKit) Event.stop(event);
143
148
  return;
144
149
  case Event.KEY_DOWN:
145
150
  this.markNext();
146
151
  this.render();
147
- if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
152
+ if(Prototype.Browser.WebKit) Event.stop(event);
148
153
  return;
149
154
  }
150
155
  else
151
156
  if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||
152
- (navigator.appVersion.indexOf('AppleWebKit') > 0 && event.keyCode == 0)) return;
157
+ (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return;
153
158
 
154
159
  this.changed = true;
155
160
  this.hasFocus = true;
@@ -195,7 +200,6 @@ Autocompleter.Base.prototype = {
195
200
  this.index==i ?
196
201
  Element.addClassName(this.getEntry(i),"selected") :
197
202
  Element.removeClassName(this.getEntry(i),"selected");
198
-
199
203
  if(this.hasFocus) {
200
204
  this.show();
201
205
  this.active = true;
@@ -238,21 +242,22 @@ Autocompleter.Base.prototype = {
238
242
  }
239
243
  var value = '';
240
244
  if (this.options.select) {
241
- var nodes = document.getElementsByClassName(this.options.select, selectedElement) || [];
245
+ var nodes = $(selectedElement).select('.' + this.options.select) || [];
242
246
  if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
243
247
  } else
244
248
  value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
245
249
 
246
- var lastTokenPos = this.findLastToken();
247
- if (lastTokenPos != -1) {
248
- var newValue = this.element.value.substr(0, lastTokenPos + 1);
249
- var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/);
250
+ var bounds = this.getTokenBounds();
251
+ if (bounds[0] != -1) {
252
+ var newValue = this.element.value.substr(0, bounds[0]);
253
+ var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/);
250
254
  if (whitespace)
251
255
  newValue += whitespace[0];
252
- this.element.value = newValue + value;
256
+ this.element.value = newValue + value + this.element.value.substr(bounds[1]);
253
257
  } else {
254
258
  this.element.value = value;
255
259
  }
260
+ this.oldElementValue = this.element.value;
256
261
  this.element.focus();
257
262
 
258
263
  if (this.options.afterUpdateElement)
@@ -296,39 +301,48 @@ Autocompleter.Base.prototype = {
296
301
 
297
302
  onObserverEvent: function() {
298
303
  this.changed = false;
304
+ this.tokenBounds = null;
299
305
  if(this.getToken().length>=this.options.minChars) {
300
- this.startIndicator();
301
306
  this.getUpdatedChoices();
302
307
  } else {
303
308
  this.active = false;
304
309
  this.hide();
305
310
  }
311
+ this.oldElementValue = this.element.value;
306
312
  },
307
313
 
308
314
  getToken: function() {
309
- var tokenPos = this.findLastToken();
310
- if (tokenPos != -1)
311
- var ret = this.element.value.substr(tokenPos + 1).replace(/^\s+/,'').replace(/\s+$/,'');
312
- else
313
- var ret = this.element.value;
314
-
315
- return /\n/.test(ret) ? '' : ret;
316
- },
317
-
318
- findLastToken: function() {
319
- var lastTokenPos = -1;
320
-
321
- for (var i=0; i<this.options.tokens.length; i++) {
322
- var thisTokenPos = this.element.value.lastIndexOf(this.options.tokens[i]);
323
- if (thisTokenPos > lastTokenPos)
324
- lastTokenPos = thisTokenPos;
315
+ var bounds = this.getTokenBounds();
316
+ return this.element.value.substring(bounds[0], bounds[1]).strip();
317
+ },
318
+
319
+ getTokenBounds: function() {
320
+ if (null != this.tokenBounds) return this.tokenBounds;
321
+ var value = this.element.value;
322
+ if (value.strip().empty()) return [-1, 0];
323
+ var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue);
324
+ var offset = (diff == this.oldElementValue.length ? 1 : 0);
325
+ var prevTokenPos = -1, nextTokenPos = value.length;
326
+ var tp;
327
+ for (var index = 0, l = this.options.tokens.length; index < l; ++index) {
328
+ tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1);
329
+ if (tp > prevTokenPos) prevTokenPos = tp;
330
+ tp = value.indexOf(this.options.tokens[index], diff + offset);
331
+ if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp;
325
332
  }
326
- return lastTokenPos;
333
+ return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]);
327
334
  }
328
- }
335
+ });
336
+
337
+ Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) {
338
+ var boundary = Math.min(newS.length, oldS.length);
339
+ for (var index = 0; index < boundary; ++index)
340
+ if (newS[index] != oldS[index])
341
+ return index;
342
+ return boundary;
343
+ };
329
344
 
330
- Ajax.Autocompleter = Class.create();
331
- Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), {
345
+ Ajax.Autocompleter = Class.create(Autocompleter.Base, {
332
346
  initialize: function(element, update, url, options) {
333
347
  this.baseInitialize(element, update, options);
334
348
  this.options.asynchronous = true;
@@ -338,7 +352,9 @@ Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.pro
338
352
  },
339
353
 
340
354
  getUpdatedChoices: function() {
341
- entry = encodeURIComponent(this.options.paramName) + '=' +
355
+ this.startIndicator();
356
+
357
+ var entry = encodeURIComponent(this.options.paramName) + '=' +
342
358
  encodeURIComponent(this.getToken());
343
359
 
344
360
  this.options.parameters = this.options.callback ?
@@ -346,14 +362,13 @@ Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.pro
346
362
 
347
363
  if(this.options.defaultParams)
348
364
  this.options.parameters += '&' + this.options.defaultParams;
349
-
365
+
350
366
  new Ajax.Request(this.url, this.options);
351
367
  },
352
368
 
353
369
  onComplete: function(request) {
354
370
  this.updateChoices(request.responseText);
355
371
  }
356
-
357
372
  });
358
373
 
359
374
  // The local array autocompleter. Used when you'd prefer to
@@ -391,8 +406,7 @@ Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.pro
391
406
  // In that case, the other options above will not apply unless
392
407
  // you support them.
393
408
 
394
- Autocompleter.Local = Class.create();
395
- Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), {
409
+ Autocompleter.Local = Class.create(Autocompleter.Base, {
396
410
  initialize: function(element, update, array, options) {
397
411
  this.baseInitialize(element, update, options);
398
412
  this.options.array = array;
@@ -448,13 +462,12 @@ Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), {
448
462
  ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
449
463
  return "<ul>" + ret.join('') + "</ul>";
450
464
  }
451
- }, options || {});
465
+ }, options || { });
452
466
  }
453
467
  });
454
468
 
455
- // AJAX in-place editor
456
- //
457
- // see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor
469
+ // AJAX in-place editor and collection editor
470
+ // Full rewrite by Christophe Porteneuve <tdd@tddsworld.com> (April 2007).
458
471
 
459
472
  // Use this if you notice weird scrolling problems on some browsers,
460
473
  // the DOM might be a bit confused when this gets called so do this
@@ -465,353 +478,472 @@ Field.scrollFreeActivate = function(field) {
465
478
  }, 1);
466
479
  }
467
480
 
468
- Ajax.InPlaceEditor = Class.create();
469
- Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99";
470
- Ajax.InPlaceEditor.prototype = {
481
+ Ajax.InPlaceEditor = Class.create({
471
482
  initialize: function(element, url, options) {
472
483
  this.url = url;
473
- this.element = $(element);
474
-
475
- this.options = Object.extend({
476
- paramName: "value",
477
- okButton: true,
478
- okText: "ok",
479
- cancelLink: true,
480
- cancelText: "cancel",
481
- savingText: "Saving...",
482
- clickToEditText: "Click to edit",
483
- okText: "ok",
484
- rows: 1,
485
- onComplete: function(transport, element) {
486
- new Effect.Highlight(element, {startcolor: this.options.highlightcolor});
487
- },
488
- onFailure: function(transport) {
489
- alert("Error communicating with the server: " + transport.responseText.stripTags());
490
- },
491
- callback: function(form) {
492
- return Form.serialize(form);
493
- },
494
- handleLineBreaks: true,
495
- loadingText: 'Loading...',
496
- savingClassName: 'inplaceeditor-saving',
497
- loadingClassName: 'inplaceeditor-loading',
498
- formClassName: 'inplaceeditor-form',
499
- highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor,
500
- highlightendcolor: "#FFFFFF",
501
- externalControl: null,
502
- submitOnBlur: false,
503
- ajaxOptions: {},
504
- evalScripts: false
505
- }, options || {});
506
-
507
- if(!this.options.formId && this.element.id) {
508
- this.options.formId = this.element.id + "-inplaceeditor";
509
- if ($(this.options.formId)) {
510
- // there's already a form with that name, don't specify an id
511
- this.options.formId = null;
512
- }
484
+ this.element = element = $(element);
485
+ this.prepareOptions();
486
+ this._controls = { };
487
+ arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!!
488
+ Object.extend(this.options, options || { });
489
+ if (!this.options.formId && this.element.id) {
490
+ this.options.formId = this.element.id + '-inplaceeditor';
491
+ if ($(this.options.formId))
492
+ this.options.formId = '';
513
493
  }
514
-
515
- if (this.options.externalControl) {
494
+ if (this.options.externalControl)
516
495
  this.options.externalControl = $(this.options.externalControl);
517
- }
518
-
519
- this.originalBackground = Element.getStyle(this.element, 'background-color');
520
- if (!this.originalBackground) {
521
- this.originalBackground = "transparent";
522
- }
523
-
496
+ if (!this.options.externalControl)
497
+ this.options.externalControlOnly = false;
498
+ this._originalBackground = this.element.getStyle('background-color') || 'transparent';
524
499
  this.element.title = this.options.clickToEditText;
525
-
526
- this.onclickListener = this.enterEditMode.bindAsEventListener(this);
527
- this.mouseoverListener = this.enterHover.bindAsEventListener(this);
528
- this.mouseoutListener = this.leaveHover.bindAsEventListener(this);
529
- Event.observe(this.element, 'click', this.onclickListener);
530
- Event.observe(this.element, 'mouseover', this.mouseoverListener);
531
- Event.observe(this.element, 'mouseout', this.mouseoutListener);
532
- if (this.options.externalControl) {
533
- Event.observe(this.options.externalControl, 'click', this.onclickListener);
534
- Event.observe(this.options.externalControl, 'mouseover', this.mouseoverListener);
535
- Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener);
536
- }
537
- },
538
- enterEditMode: function(evt) {
539
- if (this.saving) return;
540
- if (this.editing) return;
541
- this.editing = true;
542
- this.onEnterEditMode();
543
- if (this.options.externalControl) {
544
- Element.hide(this.options.externalControl);
545
- }
546
- Element.hide(this.element);
547
- this.createForm();
548
- this.element.parentNode.insertBefore(this.form, this.element);
549
- if (!this.options.loadTextURL) Field.scrollFreeActivate(this.editField);
550
- // stop the event to avoid a page refresh in Safari
551
- if (evt) {
552
- Event.stop(evt);
553
- }
554
- return false;
555
- },
556
- createForm: function() {
557
- this.form = document.createElement("form");
558
- this.form.id = this.options.formId;
559
- Element.addClassName(this.form, this.options.formClassName)
560
- this.form.onsubmit = this.onSubmit.bind(this);
561
-
562
- this.createEditField();
563
-
564
- if (this.options.textarea) {
565
- var br = document.createElement("br");
566
- this.form.appendChild(br);
567
- }
568
-
569
- if (this.options.okButton) {
570
- okButton = document.createElement("input");
571
- okButton.type = "submit";
572
- okButton.value = this.options.okText;
573
- okButton.className = 'editor_ok_button';
574
- this.form.appendChild(okButton);
575
- }
576
-
577
- if (this.options.cancelLink) {
578
- cancelLink = document.createElement("a");
579
- cancelLink.href = "#";
580
- cancelLink.appendChild(document.createTextNode(this.options.cancelText));
581
- cancelLink.onclick = this.onclickCancel.bind(this);
582
- cancelLink.className = 'editor_cancel';
583
- this.form.appendChild(cancelLink);
500
+ this._boundCancelHandler = this.handleFormCancellation.bind(this);
501
+ this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this);
502
+ this._boundFailureHandler = this.handleAJAXFailure.bind(this);
503
+ this._boundSubmitHandler = this.handleFormSubmission.bind(this);
504
+ this._boundWrapperHandler = this.wrapUp.bind(this);
505
+ this.registerListeners();
506
+ },
507
+ checkForEscapeOrReturn: function(e) {
508
+ if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return;
509
+ if (Event.KEY_ESC == e.keyCode)
510
+ this.handleFormCancellation(e);
511
+ else if (Event.KEY_RETURN == e.keyCode)
512
+ this.handleFormSubmission(e);
513
+ },
514
+ createControl: function(mode, handler, extraClasses) {
515
+ var control = this.options[mode + 'Control'];
516
+ var text = this.options[mode + 'Text'];
517
+ if ('button' == control) {
518
+ var btn = document.createElement('input');
519
+ btn.type = 'submit';
520
+ btn.value = text;
521
+ btn.className = 'editor_' + mode + '_button';
522
+ if ('cancel' == mode)
523
+ btn.onclick = this._boundCancelHandler;
524
+ this._form.appendChild(btn);
525
+ this._controls[mode] = btn;
526
+ } else if ('link' == control) {
527
+ var link = document.createElement('a');
528
+ link.href = '#';
529
+ link.appendChild(document.createTextNode(text));
530
+ link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler;
531
+ link.className = 'editor_' + mode + '_link';
532
+ if (extraClasses)
533
+ link.className += ' ' + extraClasses;
534
+ this._form.appendChild(link);
535
+ this._controls[mode] = link;
584
536
  }
585
537
  },
586
- hasHTMLLineBreaks: function(string) {
587
- if (!this.options.handleLineBreaks) return false;
588
- return string.match(/<br/i) || string.match(/<p>/i);
589
- },
590
- convertHTMLLineBreaks: function(string) {
591
- return string.replace(/<br>/gi, "\n").replace(/<br\/>/gi, "\n").replace(/<\/p>/gi, "\n").replace(/<p>/gi, "");
592
- },
593
538
  createEditField: function() {
594
- var text;
595
- if(this.options.loadTextURL) {
596
- text = this.options.loadingText;
597
- } else {
598
- text = this.getText();
599
- }
600
-
601
- var obj = this;
602
-
603
- if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) {
604
- this.options.textarea = false;
605
- var textField = document.createElement("input");
606
- textField.obj = this;
607
- textField.type = "text";
608
- textField.name = this.options.paramName;
609
- textField.value = text;
610
- textField.style.backgroundColor = this.options.highlightcolor;
611
- textField.className = 'editor_field';
539
+ var text = (this.options.loadTextURL ? this.options.loadingText : this.getText());
540
+ var fld;
541
+ if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) {
542
+ fld = document.createElement('input');
543
+ fld.type = 'text';
612
544
  var size = this.options.size || this.options.cols || 0;
613
- if (size != 0) textField.size = size;
614
- if (this.options.submitOnBlur)
615
- textField.onblur = this.onSubmit.bind(this);
616
- this.editField = textField;
545
+ if (0 < size) fld.size = size;
617
546
  } else {
618
- this.options.textarea = true;
619
- var textArea = document.createElement("textarea");
620
- textArea.obj = this;
621
- textArea.name = this.options.paramName;
622
- textArea.value = this.convertHTMLLineBreaks(text);
623
- textArea.rows = this.options.rows;
624
- textArea.cols = this.options.cols || 40;
625
- textArea.className = 'editor_field';
626
- if (this.options.submitOnBlur)
627
- textArea.onblur = this.onSubmit.bind(this);
628
- this.editField = textArea;
547
+ fld = document.createElement('textarea');
548
+ fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows);
549
+ fld.cols = this.options.cols || 40;
629
550
  }
630
-
631
- if(this.options.loadTextURL) {
551
+ fld.name = this.options.paramName;
552
+ fld.value = text; // No HTML breaks conversion anymore
553
+ fld.className = 'editor_field';
554
+ if (this.options.submitOnBlur)
555
+ fld.onblur = this._boundSubmitHandler;
556
+ this._controls.editor = fld;
557
+ if (this.options.loadTextURL)
632
558
  this.loadExternalText();
633
- }
634
- this.form.appendChild(this.editField);
559
+ this._form.appendChild(this._controls.editor);
560
+ },
561
+ createForm: function() {
562
+ var ipe = this;
563
+ function addText(mode, condition) {
564
+ var text = ipe.options['text' + mode + 'Controls'];
565
+ if (!text || condition === false) return;
566
+ ipe._form.appendChild(document.createTextNode(text));
567
+ };
568
+ this._form = $(document.createElement('form'));
569
+ this._form.id = this.options.formId;
570
+ this._form.addClassName(this.options.formClassName);
571
+ this._form.onsubmit = this._boundSubmitHandler;
572
+ this.createEditField();
573
+ if ('textarea' == this._controls.editor.tagName.toLowerCase())
574
+ this._form.appendChild(document.createElement('br'));
575
+ if (this.options.onFormCustomization)
576
+ this.options.onFormCustomization(this, this._form);
577
+ addText('Before', this.options.okControl || this.options.cancelControl);
578
+ this.createControl('ok', this._boundSubmitHandler);
579
+ addText('Between', this.options.okControl && this.options.cancelControl);
580
+ this.createControl('cancel', this._boundCancelHandler, 'editor_cancel');
581
+ addText('After', this.options.okControl || this.options.cancelControl);
582
+ },
583
+ destroy: function() {
584
+ if (this._oldInnerHTML)
585
+ this.element.innerHTML = this._oldInnerHTML;
586
+ this.leaveEditMode();
587
+ this.unregisterListeners();
588
+ },
589
+ enterEditMode: function(e) {
590
+ if (this._saving || this._editing) return;
591
+ this._editing = true;
592
+ this.triggerCallback('onEnterEditMode');
593
+ if (this.options.externalControl)
594
+ this.options.externalControl.hide();
595
+ this.element.hide();
596
+ this.createForm();
597
+ this.element.parentNode.insertBefore(this._form, this.element);
598
+ if (!this.options.loadTextURL)
599
+ this.postProcessEditField();
600
+ if (e) Event.stop(e);
601
+ },
602
+ enterHover: function(e) {
603
+ if (this.options.hoverClassName)
604
+ this.element.addClassName(this.options.hoverClassName);
605
+ if (this._saving) return;
606
+ this.triggerCallback('onEnterHover');
635
607
  },
636
608
  getText: function() {
637
609
  return this.element.innerHTML;
638
610
  },
639
- loadExternalText: function() {
640
- Element.addClassName(this.form, this.options.loadingClassName);
641
- this.editField.disabled = true;
642
- new Ajax.Request(
643
- this.options.loadTextURL,
644
- Object.extend({
645
- asynchronous: true,
646
- onComplete: this.onLoadedExternalText.bind(this)
647
- }, this.options.ajaxOptions)
648
- );
649
- },
650
- onLoadedExternalText: function(transport) {
651
- Element.removeClassName(this.form, this.options.loadingClassName);
652
- this.editField.disabled = false;
653
- this.editField.value = transport.responseText.stripTags();
654
- Field.scrollFreeActivate(this.editField);
655
- },
656
- onclickCancel: function() {
657
- this.onComplete();
658
- this.leaveEditMode();
659
- return false;
660
- },
661
- onFailure: function(transport) {
662
- this.options.onFailure(transport);
663
- if (this.oldInnerHTML) {
664
- this.element.innerHTML = this.oldInnerHTML;
665
- this.oldInnerHTML = null;
611
+ handleAJAXFailure: function(transport) {
612
+ this.triggerCallback('onFailure', transport);
613
+ if (this._oldInnerHTML) {
614
+ this.element.innerHTML = this._oldInnerHTML;
615
+ this._oldInnerHTML = null;
666
616
  }
667
- return false;
668
617
  },
669
- onSubmit: function() {
670
- // onLoading resets these so we need to save them away for the Ajax call
671
- var form = this.form;
672
- var value = this.editField.value;
673
-
674
- // do this first, sometimes the ajax call returns before we get a chance to switch on Saving...
675
- // which means this will actually switch on Saving... *after* we've left edit mode causing Saving...
676
- // to be displayed indefinitely
677
- this.onLoading();
678
-
679
- if (this.options.evalScripts) {
680
- new Ajax.Request(
681
- this.url, Object.extend({
682
- parameters: this.options.callback(form, value),
683
- onComplete: this.onComplete.bind(this),
684
- onFailure: this.onFailure.bind(this),
685
- asynchronous:true,
686
- evalScripts:true
687
- }, this.options.ajaxOptions));
688
- } else {
689
- new Ajax.Updater(
690
- { success: this.element,
691
- // don't update on failure (this could be an option)
692
- failure: null },
693
- this.url, Object.extend({
694
- parameters: this.options.callback(form, value),
695
- onComplete: this.onComplete.bind(this),
696
- onFailure: this.onFailure.bind(this)
697
- }, this.options.ajaxOptions));
698
- }
699
- // stop the event to avoid a page refresh in Safari
700
- if (arguments.length > 1) {
701
- Event.stop(arguments[0]);
618
+ handleFormCancellation: function(e) {
619
+ this.wrapUp();
620
+ if (e) Event.stop(e);
621
+ },
622
+ handleFormSubmission: function(e) {
623
+ var form = this._form;
624
+ var value = $F(this._controls.editor);
625
+ this.prepareSubmission();
626
+ var params = this.options.callback(form, value) || '';
627
+ if (Object.isString(params))
628
+ params = params.toQueryParams();
629
+ params.editorId = this.element.id;
630
+ if (this.options.htmlResponse) {
631
+ var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions);
632
+ Object.extend(options, {
633
+ parameters: params,
634
+ onComplete: this._boundWrapperHandler,
635
+ onFailure: this._boundFailureHandler
636
+ });
637
+ new Ajax.Updater({ success: this.element }, this.url, options);
638
+ } else {
639
+ var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
640
+ Object.extend(options, {
641
+ parameters: params,
642
+ onComplete: this._boundWrapperHandler,
643
+ onFailure: this._boundFailureHandler
644
+ });
645
+ new Ajax.Request(this.url, options);
702
646
  }
703
- return false;
647
+ if (e) Event.stop(e);
648
+ },
649
+ leaveEditMode: function() {
650
+ this.element.removeClassName(this.options.savingClassName);
651
+ this.removeForm();
652
+ this.leaveHover();
653
+ this.element.style.backgroundColor = this._originalBackground;
654
+ this.element.show();
655
+ if (this.options.externalControl)
656
+ this.options.externalControl.show();
657
+ this._saving = false;
658
+ this._editing = false;
659
+ this._oldInnerHTML = null;
660
+ this.triggerCallback('onLeaveEditMode');
661
+ },
662
+ leaveHover: function(e) {
663
+ if (this.options.hoverClassName)
664
+ this.element.removeClassName(this.options.hoverClassName);
665
+ if (this._saving) return;
666
+ this.triggerCallback('onLeaveHover');
704
667
  },
705
- onLoading: function() {
706
- this.saving = true;
668
+ loadExternalText: function() {
669
+ this._form.addClassName(this.options.loadingClassName);
670
+ this._controls.editor.disabled = true;
671
+ var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
672
+ Object.extend(options, {
673
+ parameters: 'editorId=' + encodeURIComponent(this.element.id),
674
+ onComplete: Prototype.emptyFunction,
675
+ onSuccess: function(transport) {
676
+ this._form.removeClassName(this.options.loadingClassName);
677
+ var text = transport.responseText;
678
+ if (this.options.stripLoadedTextTags)
679
+ text = text.stripTags();
680
+ this._controls.editor.value = text;
681
+ this._controls.editor.disabled = false;
682
+ this.postProcessEditField();
683
+ }.bind(this),
684
+ onFailure: this._boundFailureHandler
685
+ });
686
+ new Ajax.Request(this.options.loadTextURL, options);
687
+ },
688
+ postProcessEditField: function() {
689
+ var fpc = this.options.fieldPostCreation;
690
+ if (fpc)
691
+ $(this._controls.editor)['focus' == fpc ? 'focus' : 'activate']();
692
+ },
693
+ prepareOptions: function() {
694
+ this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions);
695
+ Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks);
696
+ [this._extraDefaultOptions].flatten().compact().each(function(defs) {
697
+ Object.extend(this.options, defs);
698
+ }.bind(this));
699
+ },
700
+ prepareSubmission: function() {
701
+ this._saving = true;
707
702
  this.removeForm();
708
703
  this.leaveHover();
709
704
  this.showSaving();
710
705
  },
706
+ registerListeners: function() {
707
+ this._listeners = { };
708
+ var listener;
709
+ $H(Ajax.InPlaceEditor.Listeners).each(function(pair) {
710
+ listener = this[pair.value].bind(this);
711
+ this._listeners[pair.key] = listener;
712
+ if (!this.options.externalControlOnly)
713
+ this.element.observe(pair.key, listener);
714
+ if (this.options.externalControl)
715
+ this.options.externalControl.observe(pair.key, listener);
716
+ }.bind(this));
717
+ },
718
+ removeForm: function() {
719
+ if (!this._form) return;
720
+ this._form.remove();
721
+ this._form = null;
722
+ this._controls = { };
723
+ },
711
724
  showSaving: function() {
712
- this.oldInnerHTML = this.element.innerHTML;
725
+ this._oldInnerHTML = this.element.innerHTML;
713
726
  this.element.innerHTML = this.options.savingText;
714
- Element.addClassName(this.element, this.options.savingClassName);
715
- this.element.style.backgroundColor = this.originalBackground;
716
- Element.show(this.element);
727
+ this.element.addClassName(this.options.savingClassName);
728
+ this.element.style.backgroundColor = this._originalBackground;
729
+ this.element.show();
717
730
  },
718
- removeForm: function() {
719
- if(this.form) {
720
- if (this.form.parentNode) Element.remove(this.form);
721
- this.form = null;
731
+ triggerCallback: function(cbName, arg) {
732
+ if ('function' == typeof this.options[cbName]) {
733
+ this.options[cbName](this, arg);
722
734
  }
723
735
  },
724
- enterHover: function() {
725
- if (this.saving) return;
726
- this.element.style.backgroundColor = this.options.highlightcolor;
727
- if (this.effect) {
728
- this.effect.cancel();
729
- }
730
- Element.addClassName(this.element, this.options.hoverClassName)
736
+ unregisterListeners: function() {
737
+ $H(this._listeners).each(function(pair) {
738
+ if (!this.options.externalControlOnly)
739
+ this.element.stopObserving(pair.key, pair.value);
740
+ if (this.options.externalControl)
741
+ this.options.externalControl.stopObserving(pair.key, pair.value);
742
+ }.bind(this));
731
743
  },
732
- leaveHover: function() {
733
- if (this.options.backgroundColor) {
734
- this.element.style.backgroundColor = this.oldBackground;
735
- }
736
- Element.removeClassName(this.element, this.options.hoverClassName)
737
- if (this.saving) return;
738
- this.effect = new Effect.Highlight(this.element, {
739
- startcolor: this.options.highlightcolor,
740
- endcolor: this.options.highlightendcolor,
741
- restorecolor: this.originalBackground
744
+ wrapUp: function(transport) {
745
+ this.leaveEditMode();
746
+ // Can't use triggerCallback due to backward compatibility: requires
747
+ // binding + direct element
748
+ this._boundComplete(transport, this.element);
749
+ }
750
+ });
751
+
752
+ Object.extend(Ajax.InPlaceEditor.prototype, {
753
+ dispose: Ajax.InPlaceEditor.prototype.destroy
754
+ });
755
+
756
+ Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, {
757
+ initialize: function($super, element, url, options) {
758
+ this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions;
759
+ $super(element, url, options);
760
+ },
761
+
762
+ createEditField: function() {
763
+ var list = document.createElement('select');
764
+ list.name = this.options.paramName;
765
+ list.size = 1;
766
+ this._controls.editor = list;
767
+ this._collection = this.options.collection || [];
768
+ if (this.options.loadCollectionURL)
769
+ this.loadCollection();
770
+ else
771
+ this.checkForExternalText();
772
+ this._form.appendChild(this._controls.editor);
773
+ },
774
+
775
+ loadCollection: function() {
776
+ this._form.addClassName(this.options.loadingClassName);
777
+ this.showLoadingText(this.options.loadingCollectionText);
778
+ var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
779
+ Object.extend(options, {
780
+ parameters: 'editorId=' + encodeURIComponent(this.element.id),
781
+ onComplete: Prototype.emptyFunction,
782
+ onSuccess: function(transport) {
783
+ var js = transport.responseText.strip();
784
+ if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check
785
+ throw 'Server returned an invalid collection representation.';
786
+ this._collection = eval(js);
787
+ this.checkForExternalText();
788
+ }.bind(this),
789
+ onFailure: this.onFailure
742
790
  });
791
+ new Ajax.Request(this.options.loadCollectionURL, options);
743
792
  },
744
- leaveEditMode: function() {
745
- Element.removeClassName(this.element, this.options.savingClassName);
746
- this.removeForm();
747
- this.leaveHover();
748
- this.element.style.backgroundColor = this.originalBackground;
749
- Element.show(this.element);
750
- if (this.options.externalControl) {
751
- Element.show(this.options.externalControl);
793
+
794
+ showLoadingText: function(text) {
795
+ this._controls.editor.disabled = true;
796
+ var tempOption = this._controls.editor.firstChild;
797
+ if (!tempOption) {
798
+ tempOption = document.createElement('option');
799
+ tempOption.value = '';
800
+ this._controls.editor.appendChild(tempOption);
801
+ tempOption.selected = true;
752
802
  }
753
- this.editing = false;
754
- this.saving = false;
755
- this.oldInnerHTML = null;
756
- this.onLeaveEditMode();
803
+ tempOption.update((text || '').stripScripts().stripTags());
757
804
  },
758
- onComplete: function(transport) {
759
- this.leaveEditMode();
760
- this.options.onComplete.bind(this)(transport, this.element);
805
+
806
+ checkForExternalText: function() {
807
+ this._text = this.getText();
808
+ if (this.options.loadTextURL)
809
+ this.loadExternalText();
810
+ else
811
+ this.buildOptionList();
761
812
  },
762
- onEnterEditMode: function() {},
763
- onLeaveEditMode: function() {},
764
- dispose: function() {
765
- if (this.oldInnerHTML) {
766
- this.element.innerHTML = this.oldInnerHTML;
767
- }
768
- this.leaveEditMode();
769
- Event.stopObserving(this.element, 'click', this.onclickListener);
770
- Event.stopObserving(this.element, 'mouseover', this.mouseoverListener);
771
- Event.stopObserving(this.element, 'mouseout', this.mouseoutListener);
772
- if (this.options.externalControl) {
773
- Event.stopObserving(this.options.externalControl, 'click', this.onclickListener);
774
- Event.stopObserving(this.options.externalControl, 'mouseover', this.mouseoverListener);
775
- Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener);
776
- }
813
+
814
+ loadExternalText: function() {
815
+ this.showLoadingText(this.options.loadingText);
816
+ var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
817
+ Object.extend(options, {
818
+ parameters: 'editorId=' + encodeURIComponent(this.element.id),
819
+ onComplete: Prototype.emptyFunction,
820
+ onSuccess: function(transport) {
821
+ this._text = transport.responseText.strip();
822
+ this.buildOptionList();
823
+ }.bind(this),
824
+ onFailure: this.onFailure
825
+ });
826
+ new Ajax.Request(this.options.loadTextURL, options);
827
+ },
828
+
829
+ buildOptionList: function() {
830
+ this._form.removeClassName(this.options.loadingClassName);
831
+ this._collection = this._collection.map(function(entry) {
832
+ return 2 === entry.length ? entry : [entry, entry].flatten();
833
+ });
834
+ var marker = ('value' in this.options) ? this.options.value : this._text;
835
+ var textFound = this._collection.any(function(entry) {
836
+ return entry[0] == marker;
837
+ }.bind(this));
838
+ this._controls.editor.update('');
839
+ var option;
840
+ this._collection.each(function(entry, index) {
841
+ option = document.createElement('option');
842
+ option.value = entry[0];
843
+ option.selected = textFound ? entry[0] == marker : 0 == index;
844
+ option.appendChild(document.createTextNode(entry[1]));
845
+ this._controls.editor.appendChild(option);
846
+ }.bind(this));
847
+ this._controls.editor.disabled = false;
848
+ Field.scrollFreeActivate(this._controls.editor);
777
849
  }
778
- };
850
+ });
779
851
 
780
- Ajax.InPlaceCollectionEditor = Class.create();
781
- Object.extend(Ajax.InPlaceCollectionEditor.prototype, Ajax.InPlaceEditor.prototype);
782
- Object.extend(Ajax.InPlaceCollectionEditor.prototype, {
783
- createEditField: function() {
784
- if (!this.cached_selectTag) {
785
- var selectTag = document.createElement("select");
786
- var collection = this.options.collection || [];
787
- var optionTag;
788
- collection.each(function(e,i) {
789
- optionTag = document.createElement("option");
790
- optionTag.value = (e instanceof Array) ? e[0] : e;
791
- if((typeof this.options.value == 'undefined') &&
792
- ((e instanceof Array) ? this.element.innerHTML == e[1] : e == optionTag.value)) optionTag.selected = true;
793
- if(this.options.value==optionTag.value) optionTag.selected = true;
794
- optionTag.appendChild(document.createTextNode((e instanceof Array) ? e[1] : e));
795
- selectTag.appendChild(optionTag);
796
- }.bind(this));
797
- this.cached_selectTag = selectTag;
798
- }
852
+ //**** DEPRECATION LAYER FOR InPlace[Collection]Editor! ****
853
+ //**** This only exists for a while, in order to let ****
854
+ //**** users adapt to the new API. Read up on the new ****
855
+ //**** API and convert your code to it ASAP! ****
856
+
857
+ Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options) {
858
+ if (!options) return;
859
+ function fallback(name, expr) {
860
+ if (name in options || expr === undefined) return;
861
+ options[name] = expr;
862
+ };
863
+ fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' :
864
+ options.cancelLink == options.cancelButton == false ? false : undefined)));
865
+ fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' :
866
+ options.okLink == options.okButton == false ? false : undefined)));
867
+ fallback('highlightColor', options.highlightcolor);
868
+ fallback('highlightEndColor', options.highlightendcolor);
869
+ };
799
870
 
800
- this.editField = this.cached_selectTag;
801
- if(this.options.loadTextURL) this.loadExternalText();
802
- this.form.appendChild(this.editField);
803
- this.options.callback = function(form, value) {
804
- return "value=" + encodeURIComponent(value);
871
+ Object.extend(Ajax.InPlaceEditor, {
872
+ DefaultOptions: {
873
+ ajaxOptions: { },
874
+ autoRows: 3, // Use when multi-line w/ rows == 1
875
+ cancelControl: 'link', // 'link'|'button'|false
876
+ cancelText: 'cancel',
877
+ clickToEditText: 'Click to edit',
878
+ externalControl: null, // id|elt
879
+ externalControlOnly: false,
880
+ fieldPostCreation: 'activate', // 'activate'|'focus'|false
881
+ formClassName: 'inplaceeditor-form',
882
+ formId: null, // id|elt
883
+ highlightColor: '#ffff99',
884
+ highlightEndColor: '#ffffff',
885
+ hoverClassName: '',
886
+ htmlResponse: true,
887
+ loadingClassName: 'inplaceeditor-loading',
888
+ loadingText: 'Loading...',
889
+ okControl: 'button', // 'link'|'button'|false
890
+ okText: 'ok',
891
+ paramName: 'value',
892
+ rows: 1, // If 1 and multi-line, uses autoRows
893
+ savingClassName: 'inplaceeditor-saving',
894
+ savingText: 'Saving...',
895
+ size: 0,
896
+ stripLoadedTextTags: false,
897
+ submitOnBlur: false,
898
+ textAfterControls: '',
899
+ textBeforeControls: '',
900
+ textBetweenControls: ''
901
+ },
902
+ DefaultCallbacks: {
903
+ callback: function(form) {
904
+ return Form.serialize(form);
905
+ },
906
+ onComplete: function(transport, element) {
907
+ // For backward compatibility, this one is bound to the IPE, and passes
908
+ // the element directly. It was too often customized, so we don't break it.
909
+ new Effect.Highlight(element, {
910
+ startcolor: this.options.highlightColor, keepBackgroundImage: true });
911
+ },
912
+ onEnterEditMode: null,
913
+ onEnterHover: function(ipe) {
914
+ ipe.element.style.backgroundColor = ipe.options.highlightColor;
915
+ if (ipe._effect)
916
+ ipe._effect.cancel();
917
+ },
918
+ onFailure: function(transport, ipe) {
919
+ alert('Error communication with the server: ' + transport.responseText.stripTags());
920
+ },
921
+ onFormCustomization: null, // Takes the IPE and its generated form, after editor, before controls.
922
+ onLeaveEditMode: null,
923
+ onLeaveHover: function(ipe) {
924
+ ipe._effect = new Effect.Highlight(ipe.element, {
925
+ startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor,
926
+ restorecolor: ipe._originalBackground, keepBackgroundImage: true
927
+ });
805
928
  }
929
+ },
930
+ Listeners: {
931
+ click: 'enterEditMode',
932
+ keydown: 'checkForEscapeOrReturn',
933
+ mouseover: 'enterHover',
934
+ mouseout: 'leaveHover'
806
935
  }
807
936
  });
808
937
 
938
+ Ajax.InPlaceCollectionEditor.DefaultOptions = {
939
+ loadingCollectionText: 'Loading options...'
940
+ };
941
+
809
942
  // Delayed observer, like Form.Element.Observer,
810
943
  // but waits for delay after last key input
811
944
  // Ideal for live-search fields
812
945
 
813
- Form.Element.DelayedObserver = Class.create();
814
- Form.Element.DelayedObserver.prototype = {
946
+ Form.Element.DelayedObserver = Class.create({
815
947
  initialize: function(element, delay, callback) {
816
948
  this.delay = delay || 0.5;
817
949
  this.element = $(element);
@@ -830,4 +962,4 @@ Form.Element.DelayedObserver.prototype = {
830
962
  this.timer = null;
831
963
  this.callback(this.element, $F(this.element));
832
964
  }
833
- };
965
+ });