Skip to content
This repository
Browse code

Now where did that stable go

git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/stable@4195 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information...
commit e1deb6accad581f1f56e8b3e490ed61676f58b0a 2 parents 2f40936 + 34a7f66
David Heinemeier Hansson authored

Showing 95 changed files with 1,601 additions and 528 deletions. Show diff stats Hide diff stats

  1. 5  actionmailer/CHANGELOG
  2. 4  actionmailer/Rakefile
  3. 2  actionmailer/lib/action_mailer/version.rb
  4. 32  actionpack/CHANGELOG
  5. 4  actionpack/Rakefile
  6. 16  actionpack/lib/action_controller/base.rb
  7. 2  actionpack/lib/action_controller/caching.rb
  8. 13  actionpack/lib/action_controller/filters.rb
  9. 2  actionpack/lib/action_controller/integration.rb
  10. 6  actionpack/lib/action_controller/templates/rescues/diagnostics.rhtml
  11. 2  actionpack/lib/action_pack/version.rb
  12. 36  actionpack/lib/action_view/base.rb
  13. 21  actionpack/lib/action_view/helpers/asset_tag_helper.rb
  14. 11  actionpack/lib/action_view/helpers/java_script_macros_helper.rb
  15. 315  actionpack/lib/action_view/helpers/javascripts/dragdrop.js
  16. 25  actionpack/lib/action_view/helpers/javascripts/effects.js
  17. 97  actionpack/lib/action_view/helpers/javascripts/prototype.js
  18. 2  actionpack/lib/action_view/helpers/prototype_helper.rb
  19. 33  actionpack/test/controller/filters_test.rb
  20. BIN  actionpack/test/fixtures/public/images/rails.png
  21. 21  actionpack/test/template/asset_tag_helper_test.rb
  22. 9  actionpack/test/template/java_script_macros_helper_test.rb
  23. 5  actionwebservice/CHANGELOG
  24. 4  actionwebservice/Rakefile
  25. 2  actionwebservice/lib/action_web_service/client/soap_client.rb
  26. 34  actionwebservice/lib/action_web_service/templates/scaffolds/layout.rhtml
  27. 1  actionwebservice/lib/action_web_service/test_invoke.rb
  28. 2  actionwebservice/lib/action_web_service/version.rb
  29. 21  actionwebservice/test/test_invoke_test.rb
  30. 57  activerecord/CHANGELOG
  31. 6  activerecord/Rakefile
  32. 107  activerecord/lib/active_record/associations.rb
  33. 1  activerecord/lib/active_record/associations/association_collection.rb
  34. 12  activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb
  35. 2  activerecord/lib/active_record/associations/has_many_association.rb
  36. 23  activerecord/lib/active_record/associations/has_many_through_association.rb
  37. 38  activerecord/lib/active_record/base.rb
  38. 7  activerecord/lib/active_record/calculations.rb
  39. 84  activerecord/lib/active_record/connection_adapters/oracle_adapter.rb
  40. 32  activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
  41. 1  activerecord/lib/active_record/migration.rb
  42. 8  activerecord/lib/active_record/reflection.rb
  43. 4  activerecord/lib/active_record/validations.rb
  44. 2  activerecord/lib/active_record/version.rb
  45. 2  activerecord/test/adapter_test.rb
  46. 10  activerecord/test/associations_go_eager_test.rb
  47. 32  activerecord/test/associations_join_model_test.rb
  48. 41  activerecord/test/associations_test.rb
  49. 14  activerecord/test/base_test.rb
  50. 12  activerecord/test/calculations_test.rb
  51. 2  activerecord/test/connections/native_oracle/connection.rb
  52. 5  activerecord/test/fixtures/author.rb
  53. 4  activerecord/test/fixtures/customer.rb
  54. 4  activerecord/test/fixtures/tag.rb
  55. 14  activerecord/test/migration_test.rb
  56. 18  activerecord/test/readonly_test.rb
  57. 2  activerecord/test/reflection_test.rb
  58. 9  activesupport/CHANGELOG
  59. 19  activesupport/lib/active_support/core_ext/exception.rb
  60. 2  activesupport/lib/active_support/core_ext/hash/indifferent_access.rb
  61. 7  activesupport/lib/active_support/core_ext/pathname.rb
  62. 14  activesupport/lib/active_support/core_ext/pathname/clean_within.rb
  63. 9  activesupport/lib/active_support/core_ext/symbol.rb
  64. 11  activesupport/lib/active_support/dependencies.rb
  65. 2  activesupport/lib/active_support/version.rb
  66. 23  activesupport/test/core_ext/exception_test.rb
  67. 12  activesupport/test/core_ext/pathname_test.rb
  68. 4  activesupport/test/core_ext/{symbol.rb → symbol_test.rb}
  69. 39  railties/CHANGELOG
  70. 6  railties/README
  71. 14  railties/Rakefile
  72. 12  railties/bin/rails
  73. 12  railties/builtin/rails_info/rails/info.rb
  74. 16  railties/builtin/rails_info/rails/info_controller.rb
  75. 2  railties/builtin/rails_info/rails/info_helper.rb
  76. 2  railties/builtin/rails_info/rails_info_controller.rb
  77. 31  railties/configs/lighttpd.conf
  78. 23  railties/environments/boot.rb
  79. 1  railties/environments/development.rb
  80. 3  railties/environments/environment.rb
  81. 2  railties/html/index.html
  82. 315  railties/html/javascripts/dragdrop.js
  83. 25  railties/html/javascripts/effects.js
  84. 97  railties/html/javascripts/prototype.js
  85. 2  railties/lib/commands/console.rb
  86. 17  railties/lib/commands/plugin.rb
  87. 29  railties/lib/commands/process/spawner.rb
  88. 22  railties/lib/dispatcher.rb
  89. 2  railties/lib/{rails_version.rb → rails/version.rb}
  90. 17  railties/lib/rails_generator/generators/applications/app/app_generator.rb
  91. 1  railties/lib/tasks/databases.rake
  92. 31  railties/lib/tasks/framework.rake
  93. 2  railties/lib/tasks/tmp.rake
  94. 22  railties/test/rails_info_controller_test.rb
  95. 1  release.rb
5  actionmailer/CHANGELOG
... ...
@@ -1,3 +1,8 @@
  1
+*1.2.1* (April 6th, 2005)
  2
+
  3
+* Be part of Rails 1.1.1
  4
+
  5
+
1 6
 *1.2.0* (March 27th, 2005)
2 7
 
3 8
 * Nil charset caused subject line to be improperly quoted in implicitly multipart messages #2662 [ehalvorsen+rails@runbox.com]
4  actionmailer/Rakefile
@@ -54,14 +54,14 @@ spec = Gem::Specification.new do |s|
54 54
   s.rubyforge_project = "actionmailer"
55 55
   s.homepage = "http://www.rubyonrails.org"
56 56
 
57  
-  s.add_dependency('actionpack', '= 1.12.0' + PKG_BUILD)
  57
+  s.add_dependency('actionpack', '= 1.12.1' + PKG_BUILD)
58 58
 
59 59
   s.has_rdoc = true
60 60
   s.requirements << 'none'
61 61
   s.require_path = 'lib'
62 62
   s.autorequire = 'action_mailer'
63 63
 
64  
-  s.files = [ "rakefile", "install.rb", "README", "CHANGELOG", "MIT-LICENSE" ]
  64
+  s.files = [ "Rakefile", "install.rb", "README", "CHANGELOG", "MIT-LICENSE" ]
65 65
   s.files = s.files + Dir.glob( "lib/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
66 66
   s.files = s.files + Dir.glob( "test/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
67 67
 end
2  actionmailer/lib/action_mailer/version.rb
@@ -2,7 +2,7 @@ module ActionMailer
2 2
   module VERSION #:nodoc:
3 3
     MAJOR = 1
4 4
     MINOR = 2
5  
-    TINY  = 0
  5
+    TINY  = 1
6 6
 
7 7
     STRING = [MAJOR, MINOR, TINY].join('.')
8 8
   end
32  actionpack/CHANGELOG
... ...
@@ -1,3 +1,35 @@
  1
+*1.12.1* (April 6th, 2005)
  2
+
  3
+* Fixed that template extensions would be cached development mode #4624 [Stefan Kaes]
  4
+
  5
+* Update to Prototype 1.5.0_rc0 [Sam Stephenson]
  6
+
  7
+* Honor skipping filters conditionally for only certain actions even when the parent class sets that filter to conditionally be executed only for the same actions. #4522 [Marcel Molina Jr.]
  8
+
  9
+* Delegate xml_http_request in integration tests to the session instance. [Jamis Buck]
  10
+
  11
+* Update the diagnostics template skip the useless '<controller not set>' text. [Nicholas Seckar]
  12
+
  13
+* CHANGED DEFAULT: Don't parse YAML input by default, but keep it available as an easy option [DHH]
  14
+
  15
+* Add additional autocompleter options [aballai, Thomas Fuchs]
  16
+
  17
+* Fixed fragment caching of binary data on Windows #4493 [bellis@deepthought.org]
  18
+
  19
+* Applied Prototype $() performance patches (#4465, #4477) and updated script.aculo.us [Sam Stephenson, Thomas Fuchs]
  20
+
  21
+* Added automated timestamping to AssetTagHelper methods for stylesheets, javascripts, and images when Action Controller is run under Rails [DHH]. Example:
  22
+
  23
+    image_tag("rails.png") # => '<img alt="Rails" src="/images/rails.png?1143664135" />'
  24
+  
  25
+  ...to avoid frequent stats (not a problem for most people), you can set RAILS_ASSET_ID in the ENV to avoid stats:
  26
+
  27
+    ENV["RAILS_ASSET_ID"] = "2345"
  28
+    image_tag("rails.png") # => '<img alt="Rails" src="/images/rails.png?2345" />'
  29
+
  30
+  This can be used by deployment managers to set the asset id by application revision
  31
+
  32
+
1 33
 *1.12.0* (March 27th, 2005)
2 34
 
3 35
 * Add documentation for respond_to. [Jamis Buck]
4  actionpack/Rakefile
@@ -68,12 +68,12 @@ spec = Gem::Specification.new do |s|
68 68
   s.has_rdoc = true
69 69
   s.requirements << 'none'
70 70
 
71  
-  s.add_dependency('activesupport', '= 1.3.0' + PKG_BUILD)
  71
+  s.add_dependency('activesupport', '= 1.3.1' + PKG_BUILD)
72 72
 
73 73
   s.require_path = 'lib'
74 74
   s.autorequire = 'action_controller'
75 75
 
76  
-  s.files = [ "rakefile", "install.rb", "README", "RUNNING_UNIT_TESTS", "CHANGELOG", "MIT-LICENSE", "examples/.htaccess" ]
  76
+  s.files = [ "Rakefile", "install.rb", "README", "RUNNING_UNIT_TESTS", "CHANGELOG", "MIT-LICENSE", "examples/.htaccess" ]
77 77
   dist_dirs.each do |dir|
78 78
     s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
79 79
   end
16  actionpack/lib/action_controller/base.rb
@@ -265,11 +265,9 @@ class Base
265 265
     # The param_parsers hash lets you register handlers wich will process the http body and add parameters to the 
266 266
     # @params hash. These handlers are invoked for post and put requests.
267 267
     #
268  
-    # By default application/xml and application/x-yaml are enabled. For application/xml, a XmlSimple class with
269  
-    # the same param name as the root will be instanciated in the @params. This allows XML requests to mask themselves
270  
-    # as regular form submissions, so you can have one action serve both regular forms and web service requests. For
271  
-    # application/x-yaml, the YAML document is merged into the parameters and appears to the application as if the
272  
-    # YAML elements were simply form submissions.
  268
+    # By default application/xml is enabled. A XmlSimple class with the same param name as the root will be instanciated 
  269
+    # in the @params. This allows XML requests to mask themselves as regular form submissions, so you can have one
  270
+    # action serve both regular forms and web service requests.
273 271
     # 
274 272
     # Example of doing your own parser for a custom content type:
275 273
     #
@@ -283,9 +281,13 @@ class Base
283 281
     # in params[:r][:name] for "David" instead of params[:name]. To get the old behavior, you can 
284 282
     # re-register XmlSimple as application/xml handler ike this:
285 283
     #
286  
-    #   ActionController::Base.param_parsers[Mime::XML]  = 
  284
+    #   ActionController::Base.param_parsers[Mime::XML] = 
287 285
     #     Proc.new { |data| XmlSimple.xml_in(data, 'ForceArray' => false) }
288  
-    @@param_parsers = { Mime::XML => :xml_simple, Mime::YAML => :yaml }
  286
+    #
  287
+    # A YAML parser is also available and can be turned on with:
  288
+    #
  289
+    #   ActionController::Base.param_parsers[Mime::YAML] = :yaml
  290
+    @@param_parsers = { Mime::XML => :xml_simple }
289 291
     cattr_accessor :param_parsers 
290 292
 
291 293
     # Template root determines the base from which template references will be made. So a call to render("test/template")
2  actionpack/lib/action_controller/caching.rb
@@ -416,7 +416,7 @@ def write(name, value, options = nil) #:nodoc:
416 416
         end
417 417
 
418 418
         def read(name, options = nil) #:nodoc:
419  
-          IO.read(real_file_path(name)) rescue nil
  419
+          File.open(real_file_path(name), 'rb') { |f| f.read } rescue nil
420 420
         end
421 421
 
422 422
         def delete(name, options) #:nodoc:
13  actionpack/lib/action_controller/filters.rb
@@ -255,6 +255,7 @@ def prepend_around_filter(*filters)
255 255
       # just like when you apply the filters.
256 256
       def skip_before_filter(*filters)
257 257
         if conditions = extract_conditions!(filters)
  258
+          remove_contradicting_conditions!(filters, conditions)
258 259
           conditions[:only], conditions[:except] = conditions[:except], conditions[:only]
259 260
           add_action_conditions(filters, conditions)
260 261
         else
@@ -272,6 +273,7 @@ def skip_before_filter(*filters)
272 273
       # just like when you apply the filters.
273 274
       def skip_after_filter(*filters)
274 275
         if conditions = extract_conditions!(filters)
  276
+          remove_contradicting_conditions!(filters, conditions)
275 277
           conditions[:only], conditions[:except] = conditions[:except], conditions[:only]
276 278
           add_action_conditions(filters, conditions)
277 279
         else
@@ -332,6 +334,17 @@ def add_action_conditions(filters, conditions)
332 334
         def condition_hash(filters, *actions)
333 335
           filters.inject({}) {|hash, filter| hash.merge(filter => actions.flatten.map {|action| action.to_s})}
334 336
         end
  337
+        
  338
+        def remove_contradicting_conditions!(filters, conditions)
  339
+          return unless conditions[:only]
  340
+          filters.each do |filter|
  341
+            next unless included_actions_for_filter = (read_inheritable_attribute('included_actions') || {})[filter]
  342
+            [*conditions[:only]].each do |conditional_action|
  343
+              conditional_action = conditional_action.to_s
  344
+              included_actions_for_filter.delete(conditional_action) if included_actions_for_filter.include?(conditional_action)
  345
+            end
  346
+          end
  347
+        end
335 348
     end
336 349
 
337 350
     module InstanceMethods # :nodoc:
2  actionpack/lib/action_controller/integration.rb
@@ -464,7 +464,7 @@ def reset!
464 464
       @integration_session = open_session
465 465
     end
466 466
 
467  
-    %w(get post cookies assigns).each do |method|
  467
+    %w(get post cookies assigns xml_http_request).each do |method|
468 468
       define_method(method) do |*args|
469 469
         reset! unless @integration_session
470 470
         returning @integration_session.send(method, *args) do
6  actionpack/lib/action_controller/templates/rescues/diagnostics.rhtml
... ...
@@ -1,6 +1,8 @@
1 1
 <h1>
2  
-  <%=h @exception.class.to_s %> in
3  
-  <%=h (@request.parameters["controller"] || "<controller not set>").capitalize %>#<%=h @request.parameters["action"] || "<action not set>" %>
  2
+  <%=h @exception.class.to_s %>
  3
+  <% if @request.parameters['controller'] %>
  4
+    in <%=h @request.parameters['controller'].humanize %>Controller<% if @request.parameters['action'] %>#<%=h @request.parameters['action'] %><% end %>
  5
+  <% end %>
4 6
 </h1>
5 7
 <pre><%=h @exception.clean_message %></pre>
6 8
 
2  actionpack/lib/action_pack/version.rb
@@ -2,7 +2,7 @@ module ActionPack #:nodoc:
2 2
   module VERSION #:nodoc:
3 3
     MAJOR = 1
4 4
     MINOR = 12
5  
-    TINY  = 0
  5
+    TINY  = 1
6 6
     
7 7
     STRING = [MAJOR, MINOR, TINY].join('.')
8 8
   end
36  actionpack/lib/action_view/base.rb
@@ -157,6 +157,11 @@ class Base
157 157
     @@cache_template_loading = false
158 158
     cattr_accessor :cache_template_loading
159 159
 
  160
+    # Specify whether file extension lookup should be cached.
  161
+    # Should be +false+ for development environments. Defaults to +true+.
  162
+    @@cache_template_extensions = true
  163
+    cattr_accessor :cache_template_extensions
  164
+
160 165
     # Specify whether local_assigns should be able to use string keys.
161 166
     # Defaults to +true+. String keys are deprecated and will be removed
162 167
     # shortly.
@@ -312,15 +317,11 @@ def compile_and_render_template(extension, template = nil, file_path = nil, loca
312 317
     end
313 318
 
314 319
     def pick_template_extension(template_path)#:nodoc:
315  
-      @@cached_template_extension[template_path] ||=
316  
-        if match = delegate_template_exists?(template_path)
317  
-          match.first.to_sym
318  
-        elsif erb_template_exists?(template_path):        :rhtml
319  
-        elsif builder_template_exists?(template_path):    :rxml
320  
-        elsif javascript_template_exists?(template_path): :rjs
321  
-        else
322  
-          raise ActionViewError, "No rhtml, rxml, rjs or delegate template found for #{template_path}"
323  
-        end
  320
+      if @@cache_template_extensions
  321
+        @@cached_template_extension[template_path] ||= find_template_extension_for(template_path)
  322
+      else
  323
+        find_template_extension_for(template_path)
  324
+      end
324 325
     end
325 326
 
326 327
     def delegate_template_exists?(template_path)#:nodoc:
@@ -345,7 +346,7 @@ def file_exists?(template_path)#:nodoc:
345 346
       if template_file_extension
346 347
         template_exists?(template_file_name, template_file_extension)
347 348
       else
348  
-        @@cached_template_extension[template_path] ||
  349
+        cached_template_extension(template_path) ||
349 350
            %w(erb builder javascript delegate).any? do |template_type| 
350 351
              send("#{template_type}_template_exists?", template_path)
351 352
            end
@@ -371,6 +372,21 @@ def path_and_extension(template_path)
371 372
         template_path_without_extension = template_path.sub(/\.(\w+)$/, '')
372 373
         [ template_path_without_extension, $1 ]
373 374
       end
  375
+      
  376
+      def cached_template_extension(template_path)
  377
+        @@cache_template_extensions && @@cached_template_extension[template_path]
  378
+      end      
  379
+          
  380
+      def find_template_extension_for(template_path)
  381
+        if match = delegate_template_exists?(template_path)
  382
+          match.first.to_sym
  383
+        elsif erb_template_exists?(template_path):        :rhtml
  384
+        elsif builder_template_exists?(template_path):    :rxml
  385
+        elsif javascript_template_exists?(template_path): :rjs
  386
+        else
  387
+          raise ActionViewError, "No rhtml, rxml, rjs or delegate template found for #{template_path}"
  388
+        end
  389
+      end
374 390
 
375 391
       # This method reads a template file.
376 392
       def read_template_file(template_path, extension)
21  actionpack/lib/action_view/helpers/asset_tag_helper.rb
@@ -59,11 +59,16 @@ def javascript_path(source)
59 59
       # <tt>controllers/application.rb</tt> and <tt>helpers/application_helper.rb</tt>.
60 60
       def javascript_include_tag(*sources)
61 61
         options = sources.last.is_a?(Hash) ? sources.pop.stringify_keys : { }
  62
+
62 63
         if sources.include?(:defaults) 
63  
-          sources = sources[0..(sources.index(:defaults))] + @@javascript_default_sources.dup + sources[(sources.index(:defaults) + 1)..sources.length] 
  64
+          sources = sources[0..(sources.index(:defaults))] + 
  65
+            @@javascript_default_sources.dup + 
  66
+            sources[(sources.index(:defaults) + 1)..sources.length]
  67
+
64 68
           sources.delete(:defaults) 
65  
-          sources << "application" if defined?(RAILS_ROOT) and File.exists?("#{RAILS_ROOT}/public/javascripts/application.js") 
  69
+          sources << "application" if defined?(RAILS_ROOT) && File.exists?("#{RAILS_ROOT}/public/javascripts/application.js") 
66 70
         end
  71
+
67 72
         sources.collect { |source|
68 73
           source = javascript_path(source)        
69 74
           content_tag("script", "", { "type" => "text/javascript", "src" => source }.merge(options))
@@ -145,12 +150,18 @@ def image_tag(source, options = {})
145 150
       
146 151
       private
147 152
         def compute_public_path(source, dir, ext)
148  
-          source = "/#{dir}/#{source}" unless source.first == "/" || source.include?(":")
149  
-          source = "#{source}.#{ext}" unless source.split("/").last.include?(".")
150  
-          source = "#{@controller.request.relative_url_root}#{source}" unless %r{^[-a-z]+://} =~ source
  153
+          source  = "/#{dir}/#{source}" unless source.first == "/" || source.include?(":")
  154
+          source << ".#{ext}" unless source.split("/").last.include?(".")
  155
+          source << '?' + rails_asset_id(source) if defined?(RAILS_ROOT) && %r{^[-a-z]+://} !~ source
  156
+          source  = "#{@controller.request.relative_url_root}#{source}" unless %r{^[-a-z]+://} =~ source
151 157
           source = ActionController::Base.asset_host + source unless source.include?(":")
152 158
           source
153 159
         end
  160
+        
  161
+        def rails_asset_id(source)
  162
+          ENV["RAILS_ASSET_ID"] || 
  163
+            File.mtime("#{RAILS_ROOT}/public/#{source}").to_i.to_s rescue ""
  164
+        end
154 165
     end
155 166
   end
156 167
 end
11  actionpack/lib/action_view/helpers/java_script_macros_helper.rb
@@ -101,6 +101,8 @@ def in_place_editor_field(object, method, tag_options = {}, in_place_editor_opti
101 101
       # <tt>:with</tt>::      A JavaScript expression specifying the
102 102
       #                       parameters for the XMLHttpRequest. This defaults
103 103
       #                       to 'fieldname=value'.
  104
+      # <tt>:frequency</tt>:: Determines the time to wait after the last keystroke
  105
+      #                       for the AJAX request to be initiated.
104 106
       # <tt>:indicator</tt>:: Specifies the DOM ID of an element which will be
105 107
       #                       displayed while autocomplete is running.
106 108
       # <tt>:tokens</tt>::    A string or an array of strings containing
@@ -119,6 +121,11 @@ def in_place_editor_field(object, method, tag_options = {}, in_place_editor_opti
119 121
       #                       innerHTML is replaced.
120 122
       # <tt>:on_show</tt>::   Like on_hide, only now the expression is called
121 123
       #                       then the div is shown.
  124
+      # <tt>:after_update_element</tt>::   A Javascript expression that is called when the
  125
+      #                       user has selected one of the proposed values. 
  126
+      #                       The expression should take two variables: element and value.
  127
+      #                       Element is a DOM element for the field, value
  128
+      #                       is the value selected by the user.
122 129
       # <tt>:select</tt>::    Pick the class of the element from which the value for 
123 130
       #                       insertion should be extracted. If this is not specified,
124 131
       #                       the entire element is used.
@@ -133,8 +140,10 @@ def auto_complete_field(field_id, options = {})
133 140
         js_options[:callback]   = "function(element, value) { return #{options[:with]} }" if options[:with]
134 141
         js_options[:indicator]  = "'#{options[:indicator]}'" if options[:indicator]
135 142
         js_options[:select]     = "'#{options[:select]}'" if options[:select]
  143
+        js_options[:frequency]  = "#{options[:frequency]}" if options[:frequency]
136 144
 
137  
-        { :on_show => :onShow, :on_hide => :onHide, :min_chars => :minChars }.each do |k,v|
  145
+        { :after_update_element => :afterUpdateElement, 
  146
+          :on_show => :onShow, :on_hide => :onHide, :min_chars => :minChars }.each do |k,v|
138 147
           js_options[v] = options[k] if options[k]
139 148
         end
140 149
 
315  actionpack/lib/action_view/helpers/javascripts/dragdrop.js
... ...
@@ -1,4 +1,5 @@
1 1
 // Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
  2
+//           (c) 2005 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
2 3
 // 
3 4
 // See scriptaculous.js for full license.
4 5
 
@@ -15,7 +16,8 @@ var Droppables = {
15 16
     element = $(element);
16 17
     var options = Object.extend({
17 18
       greedy:     true,
18  
-      hoverclass: null  
  19
+      hoverclass: null,
  20
+      tree:       false
19 21
     }, arguments[1] || {});
20 22
 
21 23
     // cache containers
@@ -37,12 +39,27 @@ var Droppables = {
37 39
 
38 40
     this.drops.push(options);
39 41
   },
  42
+  
  43
+  findDeepestChild: function(drops) {
  44
+    deepest = drops[0];
  45
+      
  46
+    for (i = 1; i < drops.length; ++i)
  47
+      if (Element.isParent(drops[i].element, deepest.element))
  48
+        deepest = drops[i];
  49
+    
  50
+    return deepest;
  51
+  },
40 52
 
41 53
   isContained: function(element, drop) {
42  
-    var parentNode = element.parentNode;
43  
-    return drop._containers.detect(function(c) { return parentNode == c });
  54
+    var containmentNode;
  55
+    if(drop.tree) {
  56
+      containmentNode = element.treeNode; 
  57
+    } else {
  58
+      containmentNode = element.parentNode;
  59
+    }
  60
+    return drop._containers.detect(function(c) { return containmentNode == c });
44 61
   },
45  
-
  62
+  
46 63
   isAffected: function(point, element, drop) {
47 64
     return (
48 65
       (drop.element!=element) &&
@@ -68,18 +85,22 @@ var Droppables = {
68 85
 
69 86
   show: function(point, element) {
70 87
     if(!this.drops.length) return;
  88
+    var affected = [];
71 89
     
72 90
     if(this.last_active) this.deactivate(this.last_active);
73 91
     this.drops.each( function(drop) {
74  
-      if(Droppables.isAffected(point, element, drop)) {
75  
-        if(drop.onHover)
76  
-           drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
77  
-        if(drop.greedy) { 
78  
-          Droppables.activate(drop);
79  
-          throw $break;
80  
-        }
81  
-      }
  92
+      if(Droppables.isAffected(point, element, drop))
  93
+        affected.push(drop);
82 94
     });
  95
+        
  96
+    if(affected.length>0) {
  97
+      drop = Droppables.findDeepestChild(affected);
  98
+      Position.within(drop.element, point[0], point[1]);
  99
+      if(drop.onHover)
  100
+        drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
  101
+      
  102
+      Droppables.activate(drop);
  103
+    }
83 104
   },
84 105
 
85 106
   fire: function(event, element) {
@@ -207,8 +228,10 @@ Draggable.prototype = {
207 228
 
208 229
     this.element = $(element);
209 230
     
210  
-    if(options.handle && (typeof options.handle == 'string'))
211  
-      this.handle = Element.childrenWithClassName(this.element, options.handle, true)[0];  
  231
+    if(options.handle && (typeof options.handle == 'string')) {
  232
+      var h = Element.childrenWithClassName(this.element, options.handle, true);
  233
+      if(h.length>0) this.handle = h[0];
  234
+    }
212 235
     if(!this.handle) this.handle = $(options.handle);
213 236
     if(!this.handle) this.handle = this.element;
214 237
     
@@ -412,6 +435,7 @@ Draggable.prototype = {
412 435
     if(this.scrollInterval) {
413 436
       clearInterval(this.scrollInterval);
414 437
       this.scrollInterval = null;
  438
+      Draggables._lastScrollPointer = null;
415 439
     }
416 440
   },
417 441
   
@@ -440,7 +464,14 @@ Draggable.prototype = {
440 464
     Position.prepare();
441 465
     Droppables.show(Draggables._lastPointer, this.element);
442 466
     Draggables.notify('onDrag', this);
443  
-    this.draw(Draggables._lastPointer);    
  467
+    Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
  468
+    Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
  469
+    Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
  470
+    if (Draggables._lastScrollPointer[0] < 0)
  471
+      Draggables._lastScrollPointer[0] = 0;
  472
+    if (Draggables._lastScrollPointer[1] < 0)
  473
+      Draggables._lastScrollPointer[1] = 0;
  474
+    this.draw(Draggables._lastScrollPointer);
444 475
     
445 476
     if(this.options.change) this.options.change(this);
446 477
   },
@@ -492,30 +523,41 @@ SortableObserver.prototype = {
492 523
 }
493 524
 
494 525
 var Sortable = {
495  
-  sortables: new Array(),
  526
+  sortables: {},
496 527
   
497  
-  options: function(element){
498  
-    element = $(element);
499  
-    return this.sortables.detect(function(s) { return s.element == element });
  528
+  _findRootElement: function(element) {
  529
+    while (element.tagName != "BODY") {  
  530
+      if(element.id && Sortable.sortables[element.id]) return element;
  531
+      element = element.parentNode;
  532
+    }
  533
+  },
  534
+
  535
+  options: function(element) {
  536
+    element = Sortable._findRootElement($(element));
  537
+    if(!element) return;
  538
+    return Sortable.sortables[element.id];
500 539
   },
501 540
   
502 541
   destroy: function(element){
503  
-    element = $(element);
504  
-    this.sortables.findAll(function(s) { return s.element == element }).each(function(s){
  542
+    var s = Sortable.options(element);
  543
+    
  544
+    if(s) {
505 545
       Draggables.removeObserver(s.element);
506 546
       s.droppables.each(function(d){ Droppables.remove(d) });
507 547
       s.draggables.invoke('destroy');
508  
-    });
509  
-    this.sortables = this.sortables.reject(function(s) { return s.element == element });
  548
+      
  549
+      delete Sortable.sortables[s.element.id];
  550
+    }
510 551
   },
511  
-  
  552
+
512 553
   create: function(element) {
513 554
     element = $(element);
514 555
     var options = Object.extend({ 
515 556
       element:     element,
516 557
       tag:         'li',       // assumes li children, override with tag: 'tagname'
517 558
       dropOnEmpty: false,
518  
-      tree:        false,      // fixme: unimplemented
  559
+      tree:        false,
  560
+      treeTag:     'ul',
519 561
       overlap:     'vertical', // one of 'vertical', 'horizontal'
520 562
       constraint:  'vertical', // one of 'vertical', 'horizontal', false
521 563
       containment: element,    // also takes array of elements (or id's); or false
@@ -565,9 +607,17 @@ var Sortable = {
565 607
     var options_for_droppable = {
566 608
       overlap:     options.overlap,
567 609
       containment: options.containment,
  610
+      tree:        options.tree,
568 611
       hoverclass:  options.hoverclass,
569  
-      onHover:     Sortable.onHover,
570  
-      greedy:      !options.dropOnEmpty
  612
+      onHover:     Sortable.onHover
  613
+      //greedy:      !options.dropOnEmpty
  614
+    }
  615
+    
  616
+    var options_for_tree = {
  617
+      onHover:      Sortable.onEmptyHover,
  618
+      overlap:      options.overlap,
  619
+      containment:  options.containment,
  620
+      hoverclass:   options.hoverclass
571 621
     }
572 622
 
573 623
     // fix for gecko engine
@@ -576,12 +626,9 @@ var Sortable = {
576 626
     options.draggables = [];
577 627
     options.droppables = [];
578 628
 
579  
-    // make it so
580  
-
581 629
     // drop on empty handling
582  
-    if(options.dropOnEmpty) {
583  
-      Droppables.add(element,
584  
-        {containment: options.containment, onHover: Sortable.onEmptyHover, greedy: false});
  630
+    if(options.dropOnEmpty || options.tree) {
  631
+      Droppables.add(element, options_for_tree);
585 632
       options.droppables.push(element);
586 633
     }
587 634
 
@@ -592,11 +639,20 @@ var Sortable = {
592 639
       options.draggables.push(
593 640
         new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
594 641
       Droppables.add(e, options_for_droppable);
  642
+      if(options.tree) e.treeNode = element;
595 643
       options.droppables.push(e);      
596 644
     });
  645
+    
  646
+    if(options.tree) {
  647
+      (Sortable.findTreeElements(element, options) || []).each( function(e) {
  648
+        Droppables.add(e, options_for_tree);
  649
+        e.treeNode = element;
  650
+        options.droppables.push(e);
  651
+      });
  652
+    }
597 653
 
598 654
     // keep reference
599  
-    this.sortables.push(options);
  655
+    this.sortables[element.id] = options;
600 656
 
601 657
     // for onupdate
602 658
     Draggables.addObserver(new SortableObserver(element, options.onUpdate));
@@ -605,24 +661,21 @@ var Sortable = {
605 661
 
606 662
   // return all suitable-for-sortable elements in a guaranteed order
607 663
   findElements: function(element, options) {
608  
-    if(!element.hasChildNodes()) return null;
609  
-    var elements = [];
610  
-    var only = options.only ? [options.only].flatten() : null;
611  
-    $A(element.childNodes).each( function(e) {
612  
-      if(e.tagName && e.tagName.toUpperCase()==options.tag.toUpperCase() &&
613  
-        (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
614  
-          elements.push(e);
615  
-      if(options.tree) {
616  
-        var grandchildren = this.findElements(e, options);
617  
-        if(grandchildren) elements.push(grandchildren);
618  
-      }
619  
-    });
620  
-
621  
-    return (elements.length>0 ? elements.flatten() : null);
  664
+    return Element.findChildren(
  665
+      element, options.only, options.tree ? true : false, options.tag);
  666
+  },
  667
+  
  668
+  findTreeElements: function(element, options) {
  669
+    return Element.findChildren(
  670
+      element, options.only, options.tree ? true : false, options.treeTag);
622 671
   },
623 672
 
624 673
   onHover: function(element, dropon, overlap) {
625  
-    if(overlap>0.5) {
  674
+    if(Element.isParent(dropon, element)) return;
  675
+
  676
+    if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) {
  677
+      return;
  678
+    } else if(overlap>0.5) {
626 679
       Sortable.mark(dropon, 'before');
627 680
       if(dropon.previousSibling != element) {
628 681
         var oldParentNode = element.parentNode;
@@ -645,13 +698,37 @@ var Sortable = {
645 698
       }
646 699
     }
647 700
   },
648  
-
649  
-  onEmptyHover: function(element, dropon) {
650  
-    if(element.parentNode!=dropon) {
651  
-      var oldParentNode = element.parentNode;
652  
-      dropon.appendChild(element);
  701
+  
  702
+  onEmptyHover: function(element, dropon, overlap) {
  703
+    var oldParentNode = element.parentNode;
  704
+    var droponOptions = Sortable.options(dropon);
  705
+        
  706
+    if(!Element.isParent(dropon, element)) {
  707
+      var index;
  708
+      
  709
+      var children = Sortable.findElements(dropon, {tag: droponOptions.tag});
  710
+      var child = null;
  711
+            
  712
+      if(children) {
  713
+        var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);
  714
+        
  715
+        for (index = 0; index < children.length; index += 1) {
  716
+          if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) {
  717
+            offset -= Element.offsetSize (children[index], droponOptions.overlap);
  718
+          } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {
  719
+            child = index + 1 < children.length ? children[index + 1] : null;
  720
+            break;
  721
+          } else {
  722
+            child = children[index];
  723
+            break;
  724
+          }
  725
+        }
  726
+      }
  727
+      
  728
+      dropon.insertBefore(element, child);
  729
+      
653 730
       Sortable.options(oldParentNode).onChange(element);
654  
-      Sortable.options(dropon).onChange(element);
  731
+      droponOptions.onChange(element);
655 732
     }
656 733
   },
657 734
 
@@ -683,6 +760,75 @@ var Sortable = {
683 760
     
684 761
     Element.show(Sortable._marker);
685 762
   },
  763
+  
  764
+  _tree: function(element, options, parent) {
  765
+    var children = Sortable.findElements(element, options) || [];
  766
+  
  767
+    for (var i = 0; i < children.length; ++i) {
  768
+      var match = children[i].id.match(options.format);
  769
+
  770
+      if (!match) continue;
  771
+      
  772
+      var child = {
  773
+        id: encodeURIComponent(match ? match[1] : null),
  774
+        element: element,
  775
+        parent: parent,
  776
+        children: new Array,
  777
+        position: parent.children.length,
  778
+        container: Sortable._findChildrenElement(children[i], options.treeTag.toUpperCase())
  779
+      }
  780
+      
  781
+      /* Get the element containing the children and recurse over it */
  782
+      if (child.container)
  783
+        this._tree(child.container, options, child)
  784
+      
  785
+      parent.children.push (child);
  786
+    }
  787
+
  788
+    return parent; 
  789
+  },
  790
+
  791
+  /* Finds the first element of the given tag type within a parent element.
  792
+    Used for finding the first LI[ST] within a L[IST]I[TEM].*/
  793
+  _findChildrenElement: function (element, containerTag) {
  794
+    if (element && element.hasChildNodes)
  795
+      for (var i = 0; i < element.childNodes.length; ++i)
  796
+        if (element.childNodes[i].tagName == containerTag)
  797
+          return element.childNodes[i];
  798
+  
  799
+    return null;
  800
+  },
  801
+
  802
+  tree: function(element) {
  803
+    element = $(element);
  804
+    var sortableOptions = this.options(element);
  805
+    var options = Object.extend({
  806
+      tag: sortableOptions.tag,
  807
+      treeTag: sortableOptions.treeTag,
  808
+      only: sortableOptions.only,
  809
+      name: element.id,
  810
+      format: sortableOptions.format
  811
+    }, arguments[1] || {});
  812
+    
  813
+    var root = {
  814
+      id: null,
  815
+      parent: null,
  816
+      children: new Array,
  817
+      container: element,
  818
+      position: 0
  819
+    }
  820
+    
  821
+    return Sortable._tree (element, options, root);
  822
+  },
  823
+
  824
+  /* Construct a [i] index for a particular node */
  825
+  _constructIndex: function(node) {
  826
+    var index = '';
  827
+    do {
  828
+      if (node.id) index = '[' + node.position + ']' + index;
  829
+    } while ((node = node.parent) != null);
  830
+    return index;
  831
+  },
686 832
 
687 833
   sequence: function(element) {
688 834
     element = $(element);
@@ -705,20 +851,63 @@ var Sortable = {
705 851
     });
706 852
    
707 853
     new_sequence.each(function(ident) {
708  
-        var n = nodeMap[ident];
709  
-        if (n) {
710  
-            n[1].appendChild(n[0]);
711  
-            delete nodeMap[ident];
712  
-        }
  854
+      var n = nodeMap[ident];
  855
+      if (n) {
  856
+        n[1].appendChild(n[0]);
  857
+        delete nodeMap[ident];
  858
+      }
713 859
     });
714 860
   },
715  
-
  861
+  
716 862
   serialize: function(element) {
717 863
     element = $(element);
  864
+    var options = Object.extend(Sortable.options(element), arguments[1] || {});
718 865
     var name = encodeURIComponent(
719 866
       (arguments[1] && arguments[1].name) ? arguments[1].name : element.id);
720  
-    return Sortable.sequence(element, arguments[1]).map( function(item) {
721  
-      return name + "[]=" + encodeURIComponent(item);
722  
-    }).join('&');
  867
+    
  868
+    if (options.tree) {
  869
+      return Sortable.tree(element, arguments[1]).children.map( function (item) {
  870
+        return [name + Sortable._constructIndex(item) + "=" + 
  871
+                encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
  872
+      }).flatten().join('&');
  873
+    } else {
  874
+      return Sortable.sequence(element, arguments[1]).map( function(item) {
  875
+        return name + "[]=" + encodeURIComponent(item);
  876
+      }).join('&');
  877
+    }
723 878
   }
724 879
 }
  880
+
  881
+/* Returns true if child is contained within element */
  882
+Element.isParent = function(child, element) {
  883
+  if (!child.parentNode || child == element) return false;
  884
+
  885
+  if (child.parentNode == element) return true;
  886
+
  887
+  return Element.isParent(child.parentNode, element);
  888
+}
  889
+
  890
+Element.findChildren = function(element, only, recursive, tagName) {    
  891
+  if(!element.hasChildNodes()) return null;
  892
+  tagName = tagName.toUpperCase();
  893
+  if(only) only = [only].flatten();
  894
+  var elements = [];
  895
+  $A(element.childNodes).each( function(e) {
  896
+    if(e.tagName && e.tagName.toUpperCase()==tagName &&
  897
+      (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
  898
+        elements.push(e);
  899
+    if(recursive) {
  900
+      var grandchildren = Element.findChildren(e, only, recursive, tagName);
  901
+      if(grandchildren) elements.push(grandchildren);
  902
+    }
  903
+  });
  904
+
  905
+  return (elements.length>0 ? elements.flatten() : []);
  906
+}
  907
+
  908
+Element.offsetSize = function (element, type) {
  909
+  if (type == 'vertical' || type == 'height')
  910
+    return element.offsetHeight;
  911
+  else
  912
+    return element.offsetWidth;
  913
+}
25  actionpack/lib/action_view/helpers/javascripts/effects.js
@@ -77,9 +77,12 @@ Element.getInlineOpacity = function(element){
77 77
 }  
78 78
 
79 79
 Element.childrenWithClassName = function(element, className, findFirst) {
80  
-  return [$A($(element).getElementsByTagName('*'))[findFirst ? 'detect' : 'select']( function(c) { 
81  
-    return c.className ? Element.hasClassName(c, className) : false;
82  
-  })].flatten();
  80
+  var classNameRegExp = new RegExp("(^|\\s)" + className + "(\\s|$)");
  81
+  var results = $A($(element).getElementsByTagName('*'))[findFirst ? 'detect' : 'select']( function(c) { 
  82
+    return (c.className && c.className.match(classNameRegExp));
  83
+  });
  84
+  if(!results) results = [];
  85
+  return results;
83 86
 }
84 87
 
85 88
 Element.forceRerendering = function(element) {
@@ -91,11 +94,6 @@ Element.forceRerendering = function(element) {
91 94
   } catch(e) { }
92 95
 };
93 96
 
94  
-['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom',
95  
- 'collectTextNodes','collectTextNodesIgnoreClass','childrenWithClassName'].each( 
96  
-  function(f) { Element.Methods[f] = Element[f]; } 
97  
-);
98  
-
99 97
 /*--------------------------------------------------------------------------*/
100 98
 
101 99
 Array.prototype.call = function() {
@@ -943,11 +941,18 @@ Effect.Fold = function(element) {
943 941
         effect.element.setStyle(oldStyle);
944 942
       } });
945 943
   }}, arguments[1] || {}));
946  
-}
  944
+};
  945
+
  946
+['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom',
  947
+ 'collectTextNodes','collectTextNodesIgnoreClass','childrenWithClassName'].each( 
  948
+  function(f) { Element.Methods[f] = Element[f]; }
  949
+);
947 950
 
948 951
 Element.Methods.visualEffect = function(element, effect, options) {
949 952
   s = effect.gsub(/_/, '-').camelize();
950 953
   effect_class = s.charAt(0).toUpperCase() + s.substring(1);
951 954
   new Effect[effect_class](element, options);
952 955
   return $(element);
953  
-};
  956
+};
  957
+
  958
+Element.addMethods();
97  actionpack/lib/action_view/helpers/javascripts/prototype.js
... ...
@@ -1,4 +1,4 @@
1  
-/*  Prototype JavaScript framework, version 1.5.0_pre1
  1
+/*  Prototype JavaScript framework, version 1.5.0_rc0
2 2
  *  (c) 2005 Sam Stephenson <sam@conio.net>
3 3
  *
4 4
  *  Prototype is freely distributable under the terms of an MIT-style license.
@@ -7,7 +7,7 @@
7 7
 /*--------------------------------------------------------------------------*/
8 8
 
9 9
 var Prototype = {
10  
-  Version: '1.5.0_pre1',
  10
+  Version: '1.5.0_rc0',
11 11
   ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
12 12
 
13 13
   emptyFunction: function() {},
@@ -25,7 +25,7 @@ var Class = {
25 25
 var Abstract = new Object();
26 26
 
27 27
 Object.extend = function(destination, source) {
28  
-  for (property in source) {
  28
+  for (var property in source) {
29 29
     destination[property] = source[property];
30 30
   }
31 31
   return destination;
@@ -176,7 +176,7 @@ Object.extend(String.prototype, {
176 176
   },
177 177
 
178 178
   evalScripts: function() {
179  
-    return this.extractScripts().map(eval);
  179
+    return this.extractScripts().map(function(script) { return eval(script) });
180 180
   },
181 181
 
182 182
   escapeHTML: function() {
@@ -355,7 +355,7 @@ var Enumerable = {
355 355
     var result;
356 356
     this.each(function(value, index) {
357 357
       value = (iterator || Prototype.K)(value, index);
358  
-      if (value >= (result || value))
  358
+      if (result == undefined || value >= result)
359 359
         result = value;
360 360
     });
361 361
     return result;
@@ -365,7 +365,7 @@ var Enumerable = {
365 365
     var result;
366 366
     this.each(function(value, index) {
367 367
       value = (iterator || Prototype.K)(value, index);
368  
-      if (value <= (result || value))
  368
+      if (result == undefined || value < result)
369 369
         result = value;
370 370
     });
371 371
     return result;
@@ -447,7 +447,8 @@ var $A = Array.from = function(iterable) {
447 447
 
448 448
 Object.extend(Array.prototype, Enumerable);
449 449
 
450  
-Array.prototype._reverse = Array.prototype.reverse;
  450
+if (!Array.prototype._reverse)
  451
+  Array.prototype._reverse = Array.prototype.reverse;
451 452
 
452 453
 Object.extend(Array.prototype, {
453 454
   _each: function(iterator) {
@@ -476,7 +477,7 @@ Object.extend(Array.prototype, {
476 477
 
477 478
   flatten: function() {
478 479
     return this.inject([], function(array, value) {
479  
-      return array.concat(value.constructor == Array ?
  480
+      return array.concat(value && value.constructor == Array ?
480 481
         value.flatten() : [value]);
481 482
     });
482 483
   },
@@ -498,21 +499,13 @@ Object.extend(Array.prototype, {
498 499
     return (inline !== false ? this : this.toArray())._reverse();
499 500
   },
500 501
 
501  
-  shift: function() {
502  
-    var result = this[0];
503  
-    for (var i = 0; i < this.length - 1; i++)
504  
-      this[i] = this[i + 1];
505  
-    this.length--;
506  
-    return result;
507  
-  },
508  
-
509 502
   inspect: function() {
510 503
     return '[' + this.map(Object.inspect).join(', ') + ']';
511 504
   }
512 505
 });
513 506
 var Hash = {
514 507
   _each: function(iterator) {
515  
-    for (key in this) {
  508
+    for (var key in this) {
516 509
       var value = this[key];
517 510
       if (typeof value == 'function') continue;
518 511
 
@@ -590,9 +583,9 @@ var $R = function(start, end, exclusive) {
590 583
 var Ajax = {
591 584
   getTransport: function() {
592 585
     return Try.these(
  586
+      function() {return new XMLHttpRequest()},
593 587
       function() {return new ActiveXObject('Msxml2.XMLHTTP')},
594  
-      function() {return new ActiveXObject('Microsoft.XMLHTTP')},
595  
-      function() {return new XMLHttpRequest()}
  588
+      function() {return new ActiveXObject('Microsoft.XMLHTTP')}
596 589
     ) || false;
597 590
   },
598 591
 
@@ -644,6 +637,7 @@ Ajax.Base.prototype = {
644 637
     this.options = {
645 638
       method:       'post',
646 639
       asynchronous: true,
  640
+      contentType:  'application/x-www-form-urlencoded',
647 641
       parameters:   ''
648 642
     }
649 643
     Object.extend(this.options, options || {});
@@ -707,8 +701,7 @@ Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
707 701
        'Accept', 'text/javascript, text/html, application/xml, text/xml, */*'];
708 702
 
709 703
     if (this.options.method == 'post') {
710  
-      requestHeaders.push('Content-type',
711  
-        'application/x-www-form-urlencoded');
  704
+      requestHeaders.push('Content-type', this.options.contentType);
712 705
 
713 706
       /* Force "Connection: close" for Mozilla browsers to work around
714 707
        * a bug where XMLHttpReqeuest sends an incorrect Content-length
@@ -739,7 +732,7 @@ Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
739 732
 
740 733
   evalJSON: function() {
741 734
     try {
742  
-      return eval(this.header('X-JSON'));
  735
+      return eval('(' + this.header('X-JSON') + ')');
743 736
     } catch (e) {}
744 737
   },
745 738
 
@@ -900,13 +893,14 @@ if (!window.Element)
900 893
 
901 894
 Element.extend = function(element) {
902 895
   if (!element) return;
  896
+  if (_nativeExtensions) return element;
903 897
 
904 898
   if (!element._extended && element.tagName && element != window) {
905  
-    var methods = Element.Methods;
  899
+    var methods = Element.Methods, cache = Element.extend.cache;
906 900
     for (property in methods) {
907 901
       var value = methods[property];
908 902
       if (typeof value == 'function')
909  
-        element[property] = value.bind(null, element);
  903
+        element[property] = cache.findOrStore(value);
910 904
     }
911 905
   }
912 906
 
@@ -914,6 +908,14 @@ Element.extend = function(element) {
914 908
   return element;
915 909
 }
916 910
 
  911
+Element.extend.cache = {
  912
+  findOrStore: function(value) {
  913
+    return this[value] = this[value] || function() {
  914
+      return value.apply(null, [this].concat($A(arguments)));
  915
+    }
  916
+  }
  917
+}
  918
+