rails 1.2.6 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rails might be problematic. Click here for more details.
- data/CHANGELOG +491 -12
- data/MIT-LICENSE +1 -1
- data/README +17 -25
- data/Rakefile +41 -18
- data/bin/about +1 -1
- data/bin/console +1 -1
- data/bin/destroy +1 -1
- data/bin/generate +1 -1
- data/bin/performance/request +3 -0
- data/bin/plugin +1 -1
- data/bin/runner +1 -1
- data/bin/server +1 -1
- data/builtin/rails_info/rails/info.rb +2 -2
- data/configs/apache.conf +1 -1
- data/configs/databases/mysql.yml +9 -3
- data/configs/databases/postgresql.yml +16 -12
- data/configs/initializers/inflections.rb +10 -0
- data/configs/initializers/mime_types.rb +5 -0
- data/configs/routes.rb +23 -11
- data/doc/README_FOR_APP +1 -1
- data/environments/boot.rb +95 -26
- data/environments/development.rb +2 -5
- data/environments/environment.rb +24 -25
- data/environments/test.rb +4 -1
- data/helpers/application.rb +5 -2
- data/helpers/test_helper.rb +10 -0
- data/html/422.html +30 -0
- data/html/500.html +1 -1
- data/html/index.html +2 -2
- data/html/javascripts/controls.js +484 -354
- data/html/javascripts/dragdrop.js +88 -58
- data/html/javascripts/effects.js +396 -364
- data/html/javascripts/prototype.js +2817 -1107
- data/html/robots.txt +5 -1
- data/lib/commands/console.rb +12 -5
- data/lib/commands/performance/request.rb +6 -0
- data/lib/commands/plugin.rb +15 -10
- data/lib/commands/process/spawner.rb +14 -4
- data/lib/commands/servers/base.rb +12 -0
- data/lib/commands/servers/mongrel.rb +5 -1
- data/lib/commands/servers/webrick.rb +14 -7
- data/lib/console_app.rb +5 -2
- data/lib/console_with_helpers.rb +5 -2
- data/lib/dispatcher.rb +3 -151
- data/lib/fcgi_handler.rb +79 -81
- data/lib/initializer.rb +125 -169
- data/lib/rails/plugin.rb +84 -0
- data/lib/rails/plugin/loader.rb +150 -0
- data/lib/rails/plugin/locator.rb +78 -0
- data/lib/rails/version.rb +3 -3
- data/lib/rails_generator/base.rb +11 -9
- data/lib/rails_generator/commands.rb +20 -10
- data/lib/rails_generator/generators/applications/app/USAGE +0 -7
- data/lib/rails_generator/generators/applications/app/app_generator.rb +25 -6
- data/lib/rails_generator/generators/components/controller/USAGE +11 -12
- data/lib/rails_generator/generators/components/controller/controller_generator.rb +2 -2
- data/lib/rails_generator/generators/components/controller/templates/functional_test.rb +1 -11
- data/lib/rails_generator/generators/components/controller/templates/{view.rhtml → view.html.erb} +0 -0
- data/lib/rails_generator/generators/components/integration_test/USAGE +5 -11
- data/lib/rails_generator/generators/components/mailer/USAGE +8 -10
- data/lib/rails_generator/generators/components/mailer/mailer_generator.rb +3 -3
- data/lib/rails_generator/generators/components/mailer/templates/fixture.erb +3 -0
- data/lib/rails_generator/generators/components/mailer/templates/fixture.rhtml +0 -3
- data/lib/rails_generator/generators/components/mailer/templates/unit_test.rb +8 -24
- data/lib/rails_generator/generators/components/mailer/templates/view.erb +3 -0
- data/lib/rails_generator/generators/components/mailer/templates/view.rhtml +0 -3
- data/lib/rails_generator/generators/components/migration/USAGE +23 -8
- data/lib/rails_generator/generators/components/migration/migration_generator.rb +15 -2
- data/lib/rails_generator/generators/components/migration/templates/migration.rb +6 -2
- data/lib/rails_generator/generators/components/model/USAGE +15 -14
- data/lib/rails_generator/generators/components/model/model_generator.rb +10 -3
- data/lib/rails_generator/generators/components/model/templates/fixtures.yml +11 -3
- data/lib/rails_generator/generators/components/model/templates/migration.rb +4 -1
- data/lib/rails_generator/generators/components/model/templates/unit_test.rb +1 -3
- data/lib/rails_generator/generators/components/observer/USAGE +5 -7
- data/lib/rails_generator/generators/components/observer/templates/unit_test.rb +0 -2
- data/lib/rails_generator/generators/components/plugin/USAGE +8 -18
- data/lib/rails_generator/generators/components/plugin/plugin_generator.rb +1 -0
- data/lib/rails_generator/generators/components/plugin/templates/MIT-LICENSE +20 -0
- data/lib/rails_generator/generators/components/plugin/templates/README +10 -1
- data/lib/rails_generator/generators/components/plugin/templates/USAGE +1 -1
- data/lib/rails_generator/generators/components/plugin/templates/init.rb +1 -1
- data/lib/rails_generator/generators/components/plugin/templates/plugin.rb +1 -1
- data/lib/rails_generator/generators/components/plugin/templates/tasks.rake +1 -1
- data/lib/rails_generator/generators/components/resource/USAGE +23 -0
- data/lib/rails_generator/generators/components/resource/resource_generator.rb +13 -15
- data/lib/rails_generator/generators/components/resource/templates/controller.rb +1 -1
- data/lib/rails_generator/generators/components/resource/templates/functional_test.rb +2 -14
- data/lib/rails_generator/generators/components/scaffold/USAGE +24 -31
- data/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb +45 -146
- data/lib/rails_generator/generators/components/scaffold/templates/controller.rb +64 -37
- data/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb +23 -80
- data/lib/rails_generator/generators/components/scaffold/templates/{layout.rhtml → layout.html.erb} +0 -0
- data/lib/rails_generator/generators/components/scaffold/templates/style.css +1 -1
- data/lib/rails_generator/generators/components/{scaffold_resource/templates/view_edit.rhtml → scaffold/templates/view_edit.html.erb} +4 -4
- data/lib/rails_generator/generators/components/{scaffold_resource/templates/view_index.rhtml → scaffold/templates/view_index.html.erb} +4 -4
- data/lib/rails_generator/generators/components/{scaffold_resource/templates/view_new.rhtml → scaffold/templates/view_new.html.erb} +3 -3
- data/lib/rails_generator/generators/components/{scaffold_resource/templates/view_show.rhtml → scaffold/templates/view_show.html.erb} +1 -1
- data/lib/rails_generator/generators/components/session_migration/USAGE +6 -11
- data/lib/rails_generator/generators/components/session_migration/templates/migration.rb +3 -3
- data/lib/rails_generator/lookup.rb +45 -10
- data/lib/rails_generator/scripts.rb +6 -3
- data/lib/rails_generator/scripts/destroy.rb +23 -0
- data/lib/rails_generator/secret_key_generator.rb +160 -0
- data/lib/rails_generator/spec.rb +1 -1
- data/lib/source_annotation_extractor.rb +62 -0
- data/lib/tasks/annotations.rake +23 -0
- data/lib/tasks/databases.rake +249 -83
- data/lib/tasks/documentation.rake +11 -13
- data/lib/tasks/framework.rake +1 -1
- data/lib/tasks/rails.rb +1 -1
- data/lib/tasks/testing.rake +5 -7
- data/lib/test_help.rb +4 -3
- data/lib/webrick_server.rb +3 -4
- metadata +31 -49
- data/bin/breakpointer +0 -3
- data/lib/binding_of_caller.rb +0 -85
- data/lib/breakpoint.rb +0 -553
- data/lib/breakpoint_client.rb +0 -196
- data/lib/commands/breakpointer.rb +0 -1
- data/lib/rails_generator/generators/components/resource/templates/USAGE +0 -18
- data/lib/rails_generator/generators/components/resource/templates/fixtures.yml +0 -11
- data/lib/rails_generator/generators/components/resource/templates/migration.rb +0 -13
- data/lib/rails_generator/generators/components/resource/templates/model.rb +0 -2
- data/lib/rails_generator/generators/components/resource/templates/unit_test.rb +0 -10
- data/lib/rails_generator/generators/components/scaffold/templates/form.rhtml +0 -3
- data/lib/rails_generator/generators/components/scaffold/templates/form_scaffolding.rhtml +0 -1
- data/lib/rails_generator/generators/components/scaffold/templates/view_edit.rhtml +0 -9
- data/lib/rails_generator/generators/components/scaffold/templates/view_list.rhtml +0 -27
- data/lib/rails_generator/generators/components/scaffold/templates/view_new.rhtml +0 -8
- data/lib/rails_generator/generators/components/scaffold/templates/view_show.rhtml +0 -8
- data/lib/rails_generator/generators/components/scaffold_resource/USAGE +0 -29
- data/lib/rails_generator/generators/components/scaffold_resource/scaffold_resource_generator.rb +0 -93
- data/lib/rails_generator/generators/components/scaffold_resource/templates/controller.rb +0 -79
- data/lib/rails_generator/generators/components/scaffold_resource/templates/fixtures.yml +0 -11
- data/lib/rails_generator/generators/components/scaffold_resource/templates/functional_test.rb +0 -57
- data/lib/rails_generator/generators/components/scaffold_resource/templates/helper.rb +0 -2
- data/lib/rails_generator/generators/components/scaffold_resource/templates/layout.rhtml +0 -17
- data/lib/rails_generator/generators/components/scaffold_resource/templates/migration.rb +0 -13
- data/lib/rails_generator/generators/components/scaffold_resource/templates/model.rb +0 -2
- data/lib/rails_generator/generators/components/scaffold_resource/templates/style.css +0 -74
- data/lib/rails_generator/generators/components/scaffold_resource/templates/unit_test.rb +0 -10
- data/lib/rails_generator/generators/components/web_service/USAGE +0 -28
- data/lib/rails_generator/generators/components/web_service/templates/api_definition.rb +0 -5
- data/lib/rails_generator/generators/components/web_service/templates/controller.rb +0 -8
- data/lib/rails_generator/generators/components/web_service/templates/functional_test.rb +0 -19
- data/lib/rails_generator/generators/components/web_service/web_service_generator.rb +0 -29
- data/lib/tasks/pre_namespace_aliases.rake +0 -53
    
        data/doc/README_FOR_APP
    CHANGED
    
    | @@ -1,2 +1,2 @@ | |
| 1 1 | 
             
            Use this README file to introduce your application and point to useful places in the API for learning more.
         | 
| 2 | 
            -
            Run "rake  | 
| 2 | 
            +
            Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries.
         | 
    
        data/environments/boot.rb
    CHANGED
    
    | @@ -1,39 +1,108 @@ | |
| 1 | 
            -
            # Don't change this file | 
| 1 | 
            +
            # Don't change this file!
         | 
| 2 | 
            +
            # Configure your app in config/environment.rb and config/environments/*.rb
         | 
| 2 3 |  | 
| 3 4 | 
             
            RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)
         | 
| 4 5 |  | 
| 5 | 
            -
             | 
| 6 | 
            -
               | 
| 7 | 
            -
                 | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 6 | 
            +
            module Rails
         | 
| 7 | 
            +
              class << self
         | 
| 8 | 
            +
                def boot!
         | 
| 9 | 
            +
                  unless booted?
         | 
| 10 | 
            +
                    preinitialize
         | 
| 11 | 
            +
                    pick_boot.run
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def booted?
         | 
| 16 | 
            +
                  defined? Rails::Initializer
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def pick_boot
         | 
| 20 | 
            +
                  (vendor_rails? ? VendorBoot : GemBoot).new
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                def vendor_rails?
         | 
| 24 | 
            +
                  File.exist?("#{RAILS_ROOT}/vendor/rails")
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def preinitialize
         | 
| 28 | 
            +
                  load(preinitializer_path) if File.exists?(preinitializer_path)
         | 
| 29 | 
            +
                end
         | 
| 10 30 |  | 
| 11 | 
            -
                 | 
| 12 | 
            -
                   | 
| 13 | 
            -
             | 
| 31 | 
            +
                def preinitializer_path
         | 
| 32 | 
            +
                  "#{RAILS_ROOT}/config/preinitializer.rb"
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
              class Boot
         | 
| 37 | 
            +
                def run
         | 
| 38 | 
            +
                  load_initializer
         | 
| 39 | 
            +
                  Rails::Initializer.run(:set_load_path)
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
              end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
              class VendorBoot < Boot
         | 
| 44 | 
            +
                def load_initializer
         | 
| 45 | 
            +
                  require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer"
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
              end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
              class GemBoot < Boot
         | 
| 50 | 
            +
                def load_initializer
         | 
| 51 | 
            +
                  self.class.load_rubygems
         | 
| 52 | 
            +
                  load_rails_gem
         | 
| 53 | 
            +
                  require 'initializer'
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                def load_rails_gem
         | 
| 57 | 
            +
                  if version = self.class.gem_version
         | 
| 58 | 
            +
                    gem 'rails', version
         | 
| 14 59 | 
             
                  else
         | 
| 15 | 
            -
                     | 
| 16 | 
            -
                    $1
         | 
| 60 | 
            +
                    gem 'rails'
         | 
| 17 61 | 
             
                  end
         | 
| 62 | 
            +
                rescue Gem::LoadError => load_error
         | 
| 63 | 
            +
                  $stderr.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.)
         | 
| 64 | 
            +
                  exit 1
         | 
| 65 | 
            +
                end
         | 
| 18 66 |  | 
| 19 | 
            -
                 | 
| 20 | 
            -
                   | 
| 67 | 
            +
                class << self
         | 
| 68 | 
            +
                  def rubygems_version
         | 
| 69 | 
            +
                    Gem::RubyGemsVersion if defined? Gem::RubyGemsVersion
         | 
| 70 | 
            +
                  end
         | 
| 21 71 |  | 
| 22 | 
            -
                   | 
| 23 | 
            -
                     | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 72 | 
            +
                  def gem_version
         | 
| 73 | 
            +
                    if defined? RAILS_GEM_VERSION
         | 
| 74 | 
            +
                      RAILS_GEM_VERSION
         | 
| 75 | 
            +
                    elsif ENV.include?('RAILS_GEM_VERSION')
         | 
| 76 | 
            +
                      ENV['RAILS_GEM_VERSION']
         | 
| 77 | 
            +
                    else
         | 
| 78 | 
            +
                      parse_gem_version(read_environment_rb)
         | 
| 79 | 
            +
                    end
         | 
| 80 | 
            +
                  end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                  def load_rubygems
         | 
| 83 | 
            +
                    require 'rubygems'
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                    unless rubygems_version >= '0.9.4'
         | 
| 86 | 
            +
                      $stderr.puts %(Rails requires RubyGems >= 0.9.4 (you have #{rubygems_version}). Please `gem update --system` and try again.)
         | 
| 87 | 
            +
                      exit 1
         | 
| 88 | 
            +
                    end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                  rescue LoadError
         | 
| 91 | 
            +
                    $stderr.puts %(Rails requires RubyGems >= 0.9.4. Please install RubyGems and try again: http://rubygems.rubyforge.org)
         | 
| 30 92 | 
             
                    exit 1
         | 
| 31 93 | 
             
                  end
         | 
| 32 | 
            -
             | 
| 33 | 
            -
                   | 
| 34 | 
            -
             | 
| 94 | 
            +
             | 
| 95 | 
            +
                  def parse_gem_version(text)
         | 
| 96 | 
            +
                    $1 if text =~ /^[^#]*RAILS_GEM_VERSION\s*=\s*'([!~<>=]*\s*[\d.]+)'/
         | 
| 97 | 
            +
                  end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                  private
         | 
| 100 | 
            +
                    def read_environment_rb
         | 
| 101 | 
            +
                      File.read("#{RAILS_ROOT}/config/environment.rb")
         | 
| 102 | 
            +
                    end
         | 
| 35 103 | 
             
                end
         | 
| 36 104 | 
             
              end
         | 
| 37 | 
            -
             | 
| 38 | 
            -
              Rails::Initializer.run(:set_load_path)
         | 
| 39 105 | 
             
            end
         | 
| 106 | 
            +
             | 
| 107 | 
            +
            # All that for this:
         | 
| 108 | 
            +
            Rails.boot!
         | 
    
        data/environments/development.rb
    CHANGED
    
    | @@ -8,14 +8,11 @@ config.cache_classes = false | |
| 8 8 | 
             
            # Log error messages when you accidentally call methods on nil.
         | 
| 9 9 | 
             
            config.whiny_nils = true
         | 
| 10 10 |  | 
| 11 | 
            -
            # Enable the breakpoint server that script/breakpointer connects to
         | 
| 12 | 
            -
            config.breakpoint_server = true
         | 
| 13 | 
            -
             | 
| 14 11 | 
             
            # Show full error reports and disable caching
         | 
| 15 12 | 
             
            config.action_controller.consider_all_requests_local = true
         | 
| 13 | 
            +
            config.action_view.debug_rjs                         = true
         | 
| 16 14 | 
             
            config.action_controller.perform_caching             = false
         | 
| 17 15 | 
             
            config.action_view.cache_template_extensions         = false
         | 
| 18 | 
            -
            config.action_view.debug_rjs                         = true
         | 
| 19 16 |  | 
| 20 17 | 
             
            # Don't care if the mailer can't send
         | 
| 21 | 
            -
            config.action_mailer.raise_delivery_errors = false
         | 
| 18 | 
            +
            config.action_mailer.raise_delivery_errors = false
         | 
    
        data/environments/environment.rb
    CHANGED
    
    | @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            # Be sure to restart your  | 
| 1 | 
            +
            # Be sure to restart your server when you modify this file
         | 
| 2 2 |  | 
| 3 3 | 
             
            # Uncomment below to force Rails into production mode when
         | 
| 4 4 | 
             
            # you don't control web/app server and can't set it the proper way
         | 
| @@ -11,13 +11,19 @@ | |
| 11 11 | 
             
            require File.join(File.dirname(__FILE__), 'boot')
         | 
| 12 12 |  | 
| 13 13 | 
             
            Rails::Initializer.run do |config|
         | 
| 14 | 
            -
              # Settings in config/environments/* take precedence over those specified here
         | 
| 14 | 
            +
              # Settings in config/environments/* take precedence over those specified here.
         | 
| 15 | 
            +
              # Application configuration should go into files in config/initializers
         | 
| 16 | 
            +
              # -- all .rb files in that directory are automatically loaded.
         | 
| 17 | 
            +
              # See Rails::Configuration for more options.
         | 
| 15 18 |  | 
| 16 | 
            -
              # Skip frameworks you're not going to use (only works if using vendor/rails)
         | 
| 17 | 
            -
              #  | 
| 19 | 
            +
              # Skip frameworks you're not going to use (only works if using vendor/rails).
         | 
| 20 | 
            +
              # To use Rails without a database, you must remove the Active Record framework
         | 
| 21 | 
            +
              # config.frameworks -= [ :active_record, :active_resource, :action_mailer ]
         | 
| 18 22 |  | 
| 19 | 
            -
              # Only load the plugins named here,  | 
| 20 | 
            -
              #  | 
| 23 | 
            +
              # Only load the plugins named here, in the order given. By default, all plugins 
         | 
| 24 | 
            +
              # in vendor/plugins are loaded in alphabetical order.
         | 
| 25 | 
            +
              # :all can be used as a placeholder for all plugins not explicitly named
         | 
| 26 | 
            +
              # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
         | 
| 21 27 |  | 
| 22 28 | 
             
              # Add additional load paths for your own custom dirs
         | 
| 23 29 | 
             
              # config.load_paths += %W( #{RAILS_ROOT}/extras )
         | 
| @@ -26,7 +32,17 @@ Rails::Initializer.run do |config| | |
| 26 32 | 
             
              # (by default production uses :info, the others :debug)
         | 
| 27 33 | 
             
              # config.log_level = :debug
         | 
| 28 34 |  | 
| 29 | 
            -
              #  | 
| 35 | 
            +
              # Your secret key for verifying cookie session data integrity.
         | 
| 36 | 
            +
              # If you change this key, all old sessions will become invalid!
         | 
| 37 | 
            +
              # Make sure the secret is at least 30 characters and all random, 
         | 
| 38 | 
            +
              # no regular words or you'll be exposed to dictionary attacks.
         | 
| 39 | 
            +
              config.action_controller.session = {
         | 
| 40 | 
            +
                :session_key => '_<%= app_name %>_session',
         | 
| 41 | 
            +
                :secret      => '<%= app_secret %>'
         | 
| 42 | 
            +
              }
         | 
| 43 | 
            +
             | 
| 44 | 
            +
              # Use the database for sessions instead of the cookie-based default,
         | 
| 45 | 
            +
              # which shouldn't be used to store highly confidential information
         | 
| 30 46 | 
             
              # (create the session table with 'rake db:sessions:create')
         | 
| 31 47 | 
             
              # config.action_controller.session_store = :active_record_store
         | 
| 32 48 |  | 
| @@ -40,21 +56,4 @@ Rails::Initializer.run do |config| | |
| 40 56 |  | 
| 41 57 | 
             
              # Make Active Record use UTC-base instead of local time
         | 
| 42 58 | 
             
              # config.active_record.default_timezone = :utc
         | 
| 43 | 
            -
             | 
| 44 | 
            -
              # Add new inflection rules using the following format
         | 
| 45 | 
            -
              # (all these examples are active by default):
         | 
| 46 | 
            -
              # Inflector.inflections do |inflect|
         | 
| 47 | 
            -
              #   inflect.plural /^(ox)$/i, '\1en'
         | 
| 48 | 
            -
              #   inflect.singular /^(ox)en/i, '\1'
         | 
| 49 | 
            -
              #   inflect.irregular 'person', 'people'
         | 
| 50 | 
            -
              #   inflect.uncountable %w( fish sheep )
         | 
| 51 | 
            -
              # end
         | 
| 52 | 
            -
             | 
| 53 | 
            -
              # See Rails::Configuration for more options
         | 
| 54 | 
            -
            end
         | 
| 55 | 
            -
             | 
| 56 | 
            -
            # Add new mime types for use in respond_to blocks:
         | 
| 57 | 
            -
            # Mime::Type.register "text/richtext", :rtf
         | 
| 58 | 
            -
            # Mime::Type.register "application/x-mobile", :mobile
         | 
| 59 | 
            -
             | 
| 60 | 
            -
            # Include your application configuration below
         | 
| 59 | 
            +
            end
         | 
    
        data/environments/test.rb
    CHANGED
    
    | @@ -13,7 +13,10 @@ config.whiny_nils = true | |
| 13 13 | 
             
            config.action_controller.consider_all_requests_local = true
         | 
| 14 14 | 
             
            config.action_controller.perform_caching             = false
         | 
| 15 15 |  | 
| 16 | 
            +
            # Disable request forgery protection in test environment
         | 
| 17 | 
            +
            config.action_controller.allow_forgery_protection    = false
         | 
| 18 | 
            +
             | 
| 16 19 | 
             
            # Tell ActionMailer not to deliver emails to the real world.
         | 
| 17 20 | 
             
            # The :test delivery method accumulates sent emails in the
         | 
| 18 21 | 
             
            # ActionMailer::Base.deliveries array.
         | 
| 19 | 
            -
            config.action_mailer.delivery_method = :test
         | 
| 22 | 
            +
            config.action_mailer.delivery_method = :test
         | 
    
        data/helpers/application.rb
    CHANGED
    
    | @@ -2,6 +2,9 @@ | |
| 2 2 | 
             
            # Likewise, all the methods added will be available for all controllers.
         | 
| 3 3 |  | 
| 4 4 | 
             
            class ApplicationController < ActionController::Base
         | 
| 5 | 
            -
               | 
| 6 | 
            -
             | 
| 5 | 
            +
              helper :all # include all helpers, all the time
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              # See ActionController::RequestForgeryProtection for details
         | 
| 8 | 
            +
              # Uncomment the :secret if you're not using the cookie session store
         | 
| 9 | 
            +
              protect_from_forgery # :secret => '<%= app_secret %>'
         | 
| 7 10 | 
             
            end
         | 
    
        data/helpers/test_helper.rb
    CHANGED
    
    | @@ -15,6 +15,10 @@ class Test::Unit::TestCase | |
| 15 15 | 
             
              # in MySQL.  Turn off transactional fixtures in this case; however, if you
         | 
| 16 16 | 
             
              # don't care one way or the other, switching from MyISAM to InnoDB tables
         | 
| 17 17 | 
             
              # is recommended.
         | 
| 18 | 
            +
              #
         | 
| 19 | 
            +
              # The only drawback to using transactional fixtures is when you actually 
         | 
| 20 | 
            +
              # need to test transactions.  Since your test is bracketed by a transaction,
         | 
| 21 | 
            +
              # any transactions started in your code will be automatically rolled back.
         | 
| 18 22 | 
             
              self.use_transactional_fixtures = true
         | 
| 19 23 |  | 
| 20 24 | 
             
              # Instantiated fixtures are slow, but give you @david where otherwise you
         | 
| @@ -24,5 +28,11 @@ class Test::Unit::TestCase | |
| 24 28 | 
             
              # then set this back to true.
         | 
| 25 29 | 
             
              self.use_instantiated_fixtures  = false
         | 
| 26 30 |  | 
| 31 | 
            +
              # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
         | 
| 32 | 
            +
              #
         | 
| 33 | 
            +
              # Note: You'll currently still have to declare fixtures explicitly in integration tests
         | 
| 34 | 
            +
              # -- they do not yet inherit this setting
         | 
| 35 | 
            +
              fixtures :all
         | 
| 36 | 
            +
             | 
| 27 37 | 
             
              # Add more helper methods to be used by all tests here...
         | 
| 28 38 | 
             
            end
         | 
    
        data/html/422.html
    ADDED
    
    | @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
         | 
| 2 | 
            +
                   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            <head>
         | 
| 7 | 
            +
              <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
         | 
| 8 | 
            +
              <title>The change you wanted was rejected (422)</title>
         | 
| 9 | 
            +
            	<style type="text/css">
         | 
| 10 | 
            +
            		body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
         | 
| 11 | 
            +
            		div.dialog {
         | 
| 12 | 
            +
            			width: 25em;
         | 
| 13 | 
            +
            			padding: 0 4em;
         | 
| 14 | 
            +
            			margin: 4em auto 0 auto;
         | 
| 15 | 
            +
            			border: 1px solid #ccc;
         | 
| 16 | 
            +
            			border-right-color: #999;
         | 
| 17 | 
            +
            			border-bottom-color: #999;
         | 
| 18 | 
            +
            		}
         | 
| 19 | 
            +
            		h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
         | 
| 20 | 
            +
            	</style>
         | 
| 21 | 
            +
            </head>
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            <body>
         | 
| 24 | 
            +
              <!-- This file lives in public/422.html -->
         | 
| 25 | 
            +
              <div class="dialog">
         | 
| 26 | 
            +
                <h1>The change you wanted was rejected.</h1>
         | 
| 27 | 
            +
                <p>Maybe you tried to change something you didn't have access to.</p>
         | 
| 28 | 
            +
              </div>
         | 
| 29 | 
            +
            </body>
         | 
| 30 | 
            +
            </html>
         | 
    
        data/html/500.html
    CHANGED
    
    | @@ -5,7 +5,7 @@ | |
| 5 5 |  | 
| 6 6 | 
             
            <head>
         | 
| 7 7 | 
             
              <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
         | 
| 8 | 
            -
              <title>We're sorry, but something went wrong</title>
         | 
| 8 | 
            +
              <title>We're sorry, but something went wrong (500)</title>
         | 
| 9 9 | 
             
            	<style type="text/css">
         | 
| 10 10 | 
             
            		body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
         | 
| 11 11 | 
             
            		div.dialog {
         | 
    
        data/html/index.html
    CHANGED
    
    | @@ -240,7 +240,7 @@ | |
| 240 240 | 
             
                  <div id="content">
         | 
| 241 241 | 
             
                    <div id="header">
         | 
| 242 242 | 
             
                      <h1>Welcome aboard</h1>
         | 
| 243 | 
            -
                      <h2>You’re riding  | 
| 243 | 
            +
                      <h2>You’re riding Ruby on Rails!</h2>
         | 
| 244 244 | 
             
                    </div>
         | 
| 245 245 |  | 
| 246 246 | 
             
                    <div id="about">
         | 
| @@ -265,7 +265,7 @@ | |
| 265 265 |  | 
| 266 266 | 
             
                        <li>
         | 
| 267 267 | 
             
                          <h2>Set up a default route and remove or rename this file</h2>
         | 
| 268 | 
            -
                          <p>Routes are  | 
| 268 | 
            +
                          <p>Routes are set up in config/routes.rb.</p>
         | 
| 269 269 | 
             
                        </li>
         | 
| 270 270 | 
             
                      </ol>
         | 
| 271 271 | 
             
                    </div>
         | 
| @@ -1,6 +1,6 @@ | |
| 1 | 
            -
            // Copyright (c) 2005 | 
| 2 | 
            -
            //           (c) 2005 | 
| 3 | 
            -
            //           (c) 2005 | 
| 1 | 
            +
            // Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
         | 
| 2 | 
            +
            //           (c) 2005-2007 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
         | 
| 3 | 
            +
            //           (c) 2005-2007 Jon Tirsen (http://www.tirsen.com)
         | 
| 4 4 | 
             
            // Contributors:
         | 
| 5 5 | 
             
            //  Richard Livsey
         | 
| 6 6 | 
             
            //  Rahul Bhargava
         | 
| @@ -37,22 +37,23 @@ | |
| 37 37 | 
             
            if(typeof Effect == 'undefined')
         | 
| 38 38 | 
             
              throw("controls.js requires including script.aculo.us' effects.js library");
         | 
| 39 39 |  | 
| 40 | 
            -
            var Autocompleter = {}
         | 
| 41 | 
            -
            Autocompleter.Base =  | 
| 42 | 
            -
            Autocompleter.Base.prototype = {
         | 
| 40 | 
            +
            var Autocompleter = { }
         | 
| 41 | 
            +
            Autocompleter.Base = Class.create({
         | 
| 43 42 | 
             
              baseInitialize: function(element, update, options) {
         | 
| 44 | 
            -
                 | 
| 43 | 
            +
                element          = $(element)
         | 
| 44 | 
            +
                this.element     = element; 
         | 
| 45 45 | 
             
                this.update      = $(update);  
         | 
| 46 46 | 
             
                this.hasFocus    = false; 
         | 
| 47 47 | 
             
                this.changed     = false; 
         | 
| 48 48 | 
             
                this.active      = false; 
         | 
| 49 49 | 
             
                this.index       = 0;     
         | 
| 50 50 | 
             
                this.entryCount  = 0;
         | 
| 51 | 
            +
                this.oldElementValue = this.element.value;
         | 
| 51 52 |  | 
| 52 53 | 
             
                if(this.setOptions)
         | 
| 53 54 | 
             
                  this.setOptions(options);
         | 
| 54 55 | 
             
                else
         | 
| 55 | 
            -
                  this.options = options || {};
         | 
| 56 | 
            +
                  this.options = options || { };
         | 
| 56 57 |  | 
| 57 58 | 
             
                this.options.paramName    = this.options.paramName || this.element.name;
         | 
| 58 59 | 
             
                this.options.tokens       = this.options.tokens || [];
         | 
| @@ -74,6 +75,9 @@ Autocompleter.Base.prototype = { | |
| 74 75 |  | 
| 75 76 | 
             
                if(typeof(this.options.tokens) == 'string') 
         | 
| 76 77 | 
             
                  this.options.tokens = new Array(this.options.tokens);
         | 
| 78 | 
            +
                // Force carriage returns as token delimiters anyway
         | 
| 79 | 
            +
                if (!this.options.tokens.include('\n'))
         | 
| 80 | 
            +
                  this.options.tokens.push('\n');
         | 
| 77 81 |  | 
| 78 82 | 
             
                this.observer = null;
         | 
| 79 83 |  | 
| @@ -81,15 +85,14 @@ Autocompleter.Base.prototype = { | |
| 81 85 |  | 
| 82 86 | 
             
                Element.hide(this.update);
         | 
| 83 87 |  | 
| 84 | 
            -
                Event.observe(this.element,  | 
| 85 | 
            -
                Event.observe(this.element,  | 
| 88 | 
            +
                Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this));
         | 
| 89 | 
            +
                Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this));
         | 
| 86 90 | 
             
              },
         | 
| 87 91 |  | 
| 88 92 | 
             
              show: function() {
         | 
| 89 93 | 
             
                if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
         | 
| 90 94 | 
             
                if(!this.iefix && 
         | 
| 91 | 
            -
                  ( | 
| 92 | 
            -
                  (navigator.userAgent.indexOf('Opera')<0) &&
         | 
| 95 | 
            +
                  (Prototype.Browser.IE) &&
         | 
| 93 96 | 
             
                  (Element.getStyle(this.update, 'position')=='absolute')) {
         | 
| 94 97 | 
             
                  new Insertion.After(this.update, 
         | 
| 95 98 | 
             
                   '<iframe id="' + this.update.id + '_iefix" '+
         | 
| @@ -139,17 +142,17 @@ Autocompleter.Base.prototype = { | |
| 139 142 | 
             
                   case Event.KEY_UP:
         | 
| 140 143 | 
             
                     this.markPrevious();
         | 
| 141 144 | 
             
                     this.render();
         | 
| 142 | 
            -
                      | 
| 145 | 
            +
                     Event.stop(event);
         | 
| 143 146 | 
             
                     return;
         | 
| 144 147 | 
             
                   case Event.KEY_DOWN:
         | 
| 145 148 | 
             
                     this.markNext();
         | 
| 146 149 | 
             
                     this.render();
         | 
| 147 | 
            -
                      | 
| 150 | 
            +
                     Event.stop(event);
         | 
| 148 151 | 
             
                     return;
         | 
| 149 152 | 
             
                  }
         | 
| 150 153 | 
             
                 else 
         | 
| 151 154 | 
             
                   if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || 
         | 
| 152 | 
            -
                     ( | 
| 155 | 
            +
                     (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return;
         | 
| 153 156 |  | 
| 154 157 | 
             
                this.changed = true;
         | 
| 155 158 | 
             
                this.hasFocus = true;
         | 
| @@ -195,7 +198,6 @@ Autocompleter.Base.prototype = { | |
| 195 198 | 
             
                    this.index==i ? 
         | 
| 196 199 | 
             
                      Element.addClassName(this.getEntry(i),"selected") : 
         | 
| 197 200 | 
             
                      Element.removeClassName(this.getEntry(i),"selected");
         | 
| 198 | 
            -
                    
         | 
| 199 201 | 
             
                  if(this.hasFocus) { 
         | 
| 200 202 | 
             
                    this.show();
         | 
| 201 203 | 
             
                    this.active = true;
         | 
| @@ -238,21 +240,22 @@ Autocompleter.Base.prototype = { | |
| 238 240 | 
             
                }
         | 
| 239 241 | 
             
                var value = '';
         | 
| 240 242 | 
             
                if (this.options.select) {
         | 
| 241 | 
            -
                  var nodes =  | 
| 243 | 
            +
                  var nodes = $(selectedElement).select('.' + this.options.select) || [];
         | 
| 242 244 | 
             
                  if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
         | 
| 243 245 | 
             
                } else
         | 
| 244 246 | 
             
                  value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
         | 
| 245 247 |  | 
| 246 | 
            -
                var  | 
| 247 | 
            -
                if ( | 
| 248 | 
            -
                  var newValue = this.element.value.substr(0,  | 
| 249 | 
            -
                  var whitespace = this.element.value.substr( | 
| 248 | 
            +
                var bounds = this.getTokenBounds();
         | 
| 249 | 
            +
                if (bounds[0] != -1) {
         | 
| 250 | 
            +
                  var newValue = this.element.value.substr(0, bounds[0]);
         | 
| 251 | 
            +
                  var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/);
         | 
| 250 252 | 
             
                  if (whitespace)
         | 
| 251 253 | 
             
                    newValue += whitespace[0];
         | 
| 252 | 
            -
                  this.element.value = newValue + value;
         | 
| 254 | 
            +
                  this.element.value = newValue + value + this.element.value.substr(bounds[1]);
         | 
| 253 255 | 
             
                } else {
         | 
| 254 256 | 
             
                  this.element.value = value;
         | 
| 255 257 | 
             
                }
         | 
| 258 | 
            +
                this.oldElementValue = this.element.value;
         | 
| 256 259 | 
             
                this.element.focus();
         | 
| 257 260 |  | 
| 258 261 | 
             
                if (this.options.afterUpdateElement)
         | 
| @@ -296,39 +299,48 @@ Autocompleter.Base.prototype = { | |
| 296 299 |  | 
| 297 300 | 
             
              onObserverEvent: function() {
         | 
| 298 301 | 
             
                this.changed = false;   
         | 
| 302 | 
            +
                this.tokenBounds = null;
         | 
| 299 303 | 
             
                if(this.getToken().length>=this.options.minChars) {
         | 
| 300 | 
            -
                  this.startIndicator();
         | 
| 301 304 | 
             
                  this.getUpdatedChoices();
         | 
| 302 305 | 
             
                } else {
         | 
| 303 306 | 
             
                  this.active = false;
         | 
| 304 307 | 
             
                  this.hide();
         | 
| 305 308 | 
             
                }
         | 
| 309 | 
            +
                this.oldElementValue = this.element.value;
         | 
| 306 310 | 
             
              },
         | 
| 307 311 |  | 
| 308 312 | 
             
              getToken: function() {
         | 
| 309 | 
            -
                var  | 
| 310 | 
            -
                 | 
| 311 | 
            -
             | 
| 312 | 
            -
             | 
| 313 | 
            -
             | 
| 314 | 
            -
             | 
| 315 | 
            -
                 | 
| 316 | 
            -
             | 
| 317 | 
            -
             | 
| 318 | 
            -
             | 
| 319 | 
            -
                var  | 
| 320 | 
            -
             | 
| 321 | 
            -
                for (var  | 
| 322 | 
            -
                   | 
| 323 | 
            -
                  if ( | 
| 324 | 
            -
             | 
| 313 | 
            +
                var bounds = this.getTokenBounds();
         | 
| 314 | 
            +
                return this.element.value.substring(bounds[0], bounds[1]).strip();
         | 
| 315 | 
            +
              },
         | 
| 316 | 
            +
             | 
| 317 | 
            +
              getTokenBounds: function() {
         | 
| 318 | 
            +
                if (null != this.tokenBounds) return this.tokenBounds;
         | 
| 319 | 
            +
                var value = this.element.value;
         | 
| 320 | 
            +
                if (value.strip().empty()) return [-1, 0];
         | 
| 321 | 
            +
                var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue);
         | 
| 322 | 
            +
                var offset = (diff == this.oldElementValue.length ? 1 : 0);
         | 
| 323 | 
            +
                var prevTokenPos = -1, nextTokenPos = value.length;
         | 
| 324 | 
            +
                var tp;
         | 
| 325 | 
            +
                for (var index = 0, l = this.options.tokens.length; index < l; ++index) {
         | 
| 326 | 
            +
                  tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1);
         | 
| 327 | 
            +
                  if (tp > prevTokenPos) prevTokenPos = tp;
         | 
| 328 | 
            +
                  tp = value.indexOf(this.options.tokens[index], diff + offset);
         | 
| 329 | 
            +
                  if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp;
         | 
| 325 330 | 
             
                }
         | 
| 326 | 
            -
                return  | 
| 331 | 
            +
                return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]);
         | 
| 327 332 | 
             
              }
         | 
| 328 | 
            -
            }
         | 
| 333 | 
            +
            });
         | 
| 334 | 
            +
             | 
| 335 | 
            +
            Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) {
         | 
| 336 | 
            +
              var boundary = Math.min(newS.length, oldS.length);
         | 
| 337 | 
            +
              for (var index = 0; index < boundary; ++index)
         | 
| 338 | 
            +
                if (newS[index] != oldS[index])
         | 
| 339 | 
            +
                  return index;
         | 
| 340 | 
            +
              return boundary;
         | 
| 341 | 
            +
            };
         | 
| 329 342 |  | 
| 330 | 
            -
            Ajax.Autocompleter = Class.create( | 
| 331 | 
            -
            Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), {
         | 
| 343 | 
            +
            Ajax.Autocompleter = Class.create(Autocompleter.Base, {
         | 
| 332 344 | 
             
              initialize: function(element, update, url, options) {
         | 
| 333 345 | 
             
                this.baseInitialize(element, update, options);
         | 
| 334 346 | 
             
                this.options.asynchronous  = true;
         | 
| @@ -338,7 +350,9 @@ Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.pro | |
| 338 350 | 
             
              },
         | 
| 339 351 |  | 
| 340 352 | 
             
              getUpdatedChoices: function() {
         | 
| 341 | 
            -
                 | 
| 353 | 
            +
                this.startIndicator();
         | 
| 354 | 
            +
                
         | 
| 355 | 
            +
                var entry = encodeURIComponent(this.options.paramName) + '=' + 
         | 
| 342 356 | 
             
                  encodeURIComponent(this.getToken());
         | 
| 343 357 |  | 
| 344 358 | 
             
                this.options.parameters = this.options.callback ?
         | 
| @@ -346,14 +360,13 @@ Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.pro | |
| 346 360 |  | 
| 347 361 | 
             
                if(this.options.defaultParams) 
         | 
| 348 362 | 
             
                  this.options.parameters += '&' + this.options.defaultParams;
         | 
| 349 | 
            -
             | 
| 363 | 
            +
                
         | 
| 350 364 | 
             
                new Ajax.Request(this.url, this.options);
         | 
| 351 365 | 
             
              },
         | 
| 352 366 |  | 
| 353 367 | 
             
              onComplete: function(request) {
         | 
| 354 368 | 
             
                this.updateChoices(request.responseText);
         | 
| 355 369 | 
             
              }
         | 
| 356 | 
            -
             | 
| 357 370 | 
             
            });
         | 
| 358 371 |  | 
| 359 372 | 
             
            // The local array autocompleter. Used when you'd prefer to
         | 
| @@ -391,8 +404,7 @@ Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.pro | |
| 391 404 | 
             
            // In that case, the other options above will not apply unless
         | 
| 392 405 | 
             
            // you support them.
         | 
| 393 406 |  | 
| 394 | 
            -
            Autocompleter.Local = Class.create( | 
| 395 | 
            -
            Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), {
         | 
| 407 | 
            +
            Autocompleter.Local = Class.create(Autocompleter.Base, {
         | 
| 396 408 | 
             
              initialize: function(element, update, array, options) {
         | 
| 397 409 | 
             
                this.baseInitialize(element, update, options);
         | 
| 398 410 | 
             
                this.options.array = array;
         | 
| @@ -448,13 +460,12 @@ Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), { | |
| 448 460 | 
             
                      ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
         | 
| 449 461 | 
             
                    return "<ul>" + ret.join('') + "</ul>";
         | 
| 450 462 | 
             
                  }
         | 
| 451 | 
            -
                }, options || {});
         | 
| 463 | 
            +
                }, options || { });
         | 
| 452 464 | 
             
              }
         | 
| 453 465 | 
             
            });
         | 
| 454 466 |  | 
| 455 | 
            -
            // AJAX in-place editor
         | 
| 456 | 
            -
            //
         | 
| 457 | 
            -
            // see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor
         | 
| 467 | 
            +
            // AJAX in-place editor and collection editor
         | 
| 468 | 
            +
            // Full rewrite by Christophe Porteneuve <tdd@tddsworld.com> (April 2007).
         | 
| 458 469 |  | 
| 459 470 | 
             
            // Use this if you notice weird scrolling problems on some browsers,
         | 
| 460 471 | 
             
            // the DOM might be a bit confused when this gets called so do this
         | 
| @@ -465,353 +476,472 @@ Field.scrollFreeActivate = function(field) { | |
| 465 476 | 
             
              }, 1);
         | 
| 466 477 | 
             
            }
         | 
| 467 478 |  | 
| 468 | 
            -
            Ajax.InPlaceEditor = Class.create( | 
| 469 | 
            -
            Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99";
         | 
| 470 | 
            -
            Ajax.InPlaceEditor.prototype = {
         | 
| 479 | 
            +
            Ajax.InPlaceEditor = Class.create({
         | 
| 471 480 | 
             
              initialize: function(element, url, options) {
         | 
| 472 481 | 
             
                this.url = url;
         | 
| 473 | 
            -
                this.element = $(element);
         | 
| 474 | 
            -
             | 
| 475 | 
            -
                this. | 
| 476 | 
            -
             | 
| 477 | 
            -
             | 
| 478 | 
            -
             | 
| 479 | 
            -
                   | 
| 480 | 
            -
                   | 
| 481 | 
            -
             | 
| 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 | 
            -
                  }
         | 
| 482 | 
            +
                this.element = element = $(element);
         | 
| 483 | 
            +
                this.prepareOptions();
         | 
| 484 | 
            +
                this._controls = { };
         | 
| 485 | 
            +
                arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!!
         | 
| 486 | 
            +
                Object.extend(this.options, options || { });
         | 
| 487 | 
            +
                if (!this.options.formId && this.element.id) {
         | 
| 488 | 
            +
                  this.options.formId = this.element.id + '-inplaceeditor';
         | 
| 489 | 
            +
                  if ($(this.options.formId))
         | 
| 490 | 
            +
                    this.options.formId = '';
         | 
| 513 491 | 
             
                }
         | 
| 514 | 
            -
                
         | 
| 515 | 
            -
                if (this.options.externalControl) {
         | 
| 492 | 
            +
                if (this.options.externalControl)
         | 
| 516 493 | 
             
                  this.options.externalControl = $(this.options.externalControl);
         | 
| 517 | 
            -
                 | 
| 518 | 
            -
             | 
| 519 | 
            -
                this. | 
| 520 | 
            -
                if (!this.originalBackground) {
         | 
| 521 | 
            -
                  this.originalBackground = "transparent";
         | 
| 522 | 
            -
                }
         | 
| 523 | 
            -
                
         | 
| 494 | 
            +
                if (!this.options.externalControl)
         | 
| 495 | 
            +
                  this.options.externalControlOnly = false;
         | 
| 496 | 
            +
                this._originalBackground = this.element.getStyle('background-color') || 'transparent';
         | 
| 524 497 | 
             
                this.element.title = this.options.clickToEditText;
         | 
| 525 | 
            -
                
         | 
| 526 | 
            -
                this. | 
| 527 | 
            -
                this. | 
| 528 | 
            -
                this. | 
| 529 | 
            -
                 | 
| 530 | 
            -
                 | 
| 531 | 
            -
             | 
| 532 | 
            -
             | 
| 533 | 
            -
             | 
| 534 | 
            -
             | 
| 535 | 
            -
                   | 
| 498 | 
            +
                this._boundCancelHandler = this.handleFormCancellation.bind(this);
         | 
| 499 | 
            +
                this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this);
         | 
| 500 | 
            +
                this._boundFailureHandler = this.handleAJAXFailure.bind(this);
         | 
| 501 | 
            +
                this._boundSubmitHandler = this.handleFormSubmission.bind(this);
         | 
| 502 | 
            +
                this._boundWrapperHandler = this.wrapUp.bind(this);
         | 
| 503 | 
            +
                this.registerListeners();
         | 
| 504 | 
            +
              },
         | 
| 505 | 
            +
              checkForEscapeOrReturn: function(e) {
         | 
| 506 | 
            +
                if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return;
         | 
| 507 | 
            +
                if (Event.KEY_ESC == e.keyCode)
         | 
| 508 | 
            +
                  this.handleFormCancellation(e);
         | 
| 509 | 
            +
                else if (Event.KEY_RETURN == e.keyCode)
         | 
| 510 | 
            +
                  this.handleFormSubmission(e);
         | 
| 511 | 
            +
              },
         | 
| 512 | 
            +
              createControl: function(mode, handler, extraClasses) {
         | 
| 513 | 
            +
                var control = this.options[mode + 'Control'];
         | 
| 514 | 
            +
                var text = this.options[mode + 'Text'];
         | 
| 515 | 
            +
                if ('button' == control) {
         | 
| 516 | 
            +
                  var btn = document.createElement('input');
         | 
| 517 | 
            +
                  btn.type = 'submit';
         | 
| 518 | 
            +
                  btn.value = text;
         | 
| 519 | 
            +
                  btn.className = 'editor_' + mode + '_button';
         | 
| 520 | 
            +
                  if ('cancel' == mode)
         | 
| 521 | 
            +
                    btn.onclick = this._boundCancelHandler;
         | 
| 522 | 
            +
                  this._form.appendChild(btn);
         | 
| 523 | 
            +
                  this._controls[mode] = btn;
         | 
| 524 | 
            +
                } else if ('link' == control) {
         | 
| 525 | 
            +
                  var link = document.createElement('a');
         | 
| 526 | 
            +
                  link.href = '#';
         | 
| 527 | 
            +
                  link.appendChild(document.createTextNode(text));
         | 
| 528 | 
            +
                  link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler;
         | 
| 529 | 
            +
                  link.className = 'editor_' + mode + '_link';
         | 
| 530 | 
            +
                  if (extraClasses)
         | 
| 531 | 
            +
                    link.className += ' ' + extraClasses;
         | 
| 532 | 
            +
                  this._form.appendChild(link);
         | 
| 533 | 
            +
                  this._controls[mode] = link;
         | 
| 536 534 | 
             
                }
         | 
| 537 535 | 
             
              },
         | 
| 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);
         | 
| 584 | 
            -
                }
         | 
| 585 | 
            -
              },
         | 
| 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 536 | 
             
              createEditField: function() {
         | 
| 594 | 
            -
                var text;
         | 
| 595 | 
            -
                 | 
| 596 | 
            -
             | 
| 597 | 
            -
             | 
| 598 | 
            -
                   | 
| 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';
         | 
| 537 | 
            +
                var text = (this.options.loadTextURL ? this.options.loadingText : this.getText());
         | 
| 538 | 
            +
                var fld;
         | 
| 539 | 
            +
                if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) {
         | 
| 540 | 
            +
                  fld = document.createElement('input');
         | 
| 541 | 
            +
                  fld.type = 'text';
         | 
| 612 542 | 
             
                  var size = this.options.size || this.options.cols || 0;
         | 
| 613 | 
            -
                  if ( | 
| 614 | 
            -
                  if (this.options.submitOnBlur)
         | 
| 615 | 
            -
                    textField.onblur = this.onSubmit.bind(this);
         | 
| 616 | 
            -
                  this.editField = textField;
         | 
| 543 | 
            +
                  if (0 < size) fld.size = size;
         | 
| 617 544 | 
             
                } else {
         | 
| 618 | 
            -
                   | 
| 619 | 
            -
                   | 
| 620 | 
            -
                   | 
| 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;
         | 
| 545 | 
            +
                  fld = document.createElement('textarea');
         | 
| 546 | 
            +
                  fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows);
         | 
| 547 | 
            +
                  fld.cols = this.options.cols || 40;
         | 
| 629 548 | 
             
                }
         | 
| 630 | 
            -
                
         | 
| 631 | 
            -
                 | 
| 549 | 
            +
                fld.name = this.options.paramName;
         | 
| 550 | 
            +
                fld.value = text; // No HTML breaks conversion anymore
         | 
| 551 | 
            +
                fld.className = 'editor_field';
         | 
| 552 | 
            +
                if (this.options.submitOnBlur)
         | 
| 553 | 
            +
                  fld.onblur = this._boundSubmitHandler;
         | 
| 554 | 
            +
                this._controls.editor = fld;
         | 
| 555 | 
            +
                if (this.options.loadTextURL)
         | 
| 632 556 | 
             
                  this.loadExternalText();
         | 
| 633 | 
            -
                 | 
| 634 | 
            -
             | 
| 557 | 
            +
                this._form.appendChild(this._controls.editor);
         | 
| 558 | 
            +
              },
         | 
| 559 | 
            +
              createForm: function() {
         | 
| 560 | 
            +
                var ipe = this;
         | 
| 561 | 
            +
                function addText(mode, condition) {
         | 
| 562 | 
            +
                  var text = ipe.options['text' + mode + 'Controls'];
         | 
| 563 | 
            +
                  if (!text || condition === false) return;
         | 
| 564 | 
            +
                  ipe._form.appendChild(document.createTextNode(text));
         | 
| 565 | 
            +
                };
         | 
| 566 | 
            +
                this._form = $(document.createElement('form'));
         | 
| 567 | 
            +
                this._form.id = this.options.formId;
         | 
| 568 | 
            +
                this._form.addClassName(this.options.formClassName);
         | 
| 569 | 
            +
                this._form.onsubmit = this._boundSubmitHandler;
         | 
| 570 | 
            +
                this.createEditField();
         | 
| 571 | 
            +
                if ('textarea' == this._controls.editor.tagName.toLowerCase())
         | 
| 572 | 
            +
                  this._form.appendChild(document.createElement('br'));
         | 
| 573 | 
            +
                if (this.options.onFormCustomization)
         | 
| 574 | 
            +
                  this.options.onFormCustomization(this, this._form);
         | 
| 575 | 
            +
                addText('Before', this.options.okControl || this.options.cancelControl);
         | 
| 576 | 
            +
                this.createControl('ok', this._boundSubmitHandler);
         | 
| 577 | 
            +
                addText('Between', this.options.okControl && this.options.cancelControl);
         | 
| 578 | 
            +
                this.createControl('cancel', this._boundCancelHandler, 'editor_cancel');
         | 
| 579 | 
            +
                addText('After', this.options.okControl || this.options.cancelControl);
         | 
| 580 | 
            +
              },
         | 
| 581 | 
            +
              destroy: function() {
         | 
| 582 | 
            +
                if (this._oldInnerHTML)
         | 
| 583 | 
            +
                  this.element.innerHTML = this._oldInnerHTML;
         | 
| 584 | 
            +
                this.leaveEditMode();
         | 
| 585 | 
            +
                this.unregisterListeners();
         | 
| 586 | 
            +
              },
         | 
| 587 | 
            +
              enterEditMode: function(e) {
         | 
| 588 | 
            +
                if (this._saving || this._editing) return;
         | 
| 589 | 
            +
                this._editing = true;
         | 
| 590 | 
            +
                this.triggerCallback('onEnterEditMode');
         | 
| 591 | 
            +
                if (this.options.externalControl)
         | 
| 592 | 
            +
                  this.options.externalControl.hide();
         | 
| 593 | 
            +
                this.element.hide();
         | 
| 594 | 
            +
                this.createForm();
         | 
| 595 | 
            +
                this.element.parentNode.insertBefore(this._form, this.element);
         | 
| 596 | 
            +
                if (!this.options.loadTextURL)
         | 
| 597 | 
            +
                  this.postProcessEditField();
         | 
| 598 | 
            +
                if (e) Event.stop(e);
         | 
| 599 | 
            +
              },
         | 
| 600 | 
            +
              enterHover: function(e) {
         | 
| 601 | 
            +
                if (this.options.hoverClassName)
         | 
| 602 | 
            +
                  this.element.addClassName(this.options.hoverClassName);
         | 
| 603 | 
            +
                if (this._saving) return;
         | 
| 604 | 
            +
                this.triggerCallback('onEnterHover');
         | 
| 635 605 | 
             
              },
         | 
| 636 606 | 
             
              getText: function() {
         | 
| 637 607 | 
             
                return this.element.innerHTML;
         | 
| 638 608 | 
             
              },
         | 
| 639 | 
            -
               | 
| 640 | 
            -
                 | 
| 641 | 
            -
                this. | 
| 642 | 
            -
             | 
| 643 | 
            -
                  this. | 
| 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;
         | 
| 609 | 
            +
              handleAJAXFailure: function(transport) {
         | 
| 610 | 
            +
                this.triggerCallback('onFailure', transport);
         | 
| 611 | 
            +
                if (this._oldInnerHTML) {
         | 
| 612 | 
            +
                  this.element.innerHTML = this._oldInnerHTML;
         | 
| 613 | 
            +
                  this._oldInnerHTML = null;
         | 
| 666 614 | 
             
                }
         | 
| 667 | 
            -
                return false;
         | 
| 668 615 | 
             
              },
         | 
| 669 | 
            -
               | 
| 670 | 
            -
                 | 
| 671 | 
            -
                 | 
| 672 | 
            -
             | 
| 673 | 
            -
             | 
| 674 | 
            -
                 | 
| 675 | 
            -
                 | 
| 676 | 
            -
                 | 
| 677 | 
            -
                this. | 
| 678 | 
            -
                
         | 
| 679 | 
            -
             | 
| 680 | 
            -
             | 
| 681 | 
            -
             | 
| 682 | 
            -
             | 
| 683 | 
            -
             | 
| 684 | 
            -
             | 
| 685 | 
            -
             | 
| 686 | 
            -
             | 
| 687 | 
            -
             | 
| 688 | 
            -
             | 
| 689 | 
            -
             | 
| 690 | 
            -
             | 
| 691 | 
            -
             | 
| 692 | 
            -
             | 
| 693 | 
            -
                    this. | 
| 694 | 
            -
             | 
| 695 | 
            -
             | 
| 696 | 
            -
             | 
| 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]);
         | 
| 616 | 
            +
              handleFormCancellation: function(e) {
         | 
| 617 | 
            +
                this.wrapUp();
         | 
| 618 | 
            +
                if (e) Event.stop(e);
         | 
| 619 | 
            +
              },
         | 
| 620 | 
            +
              handleFormSubmission: function(e) {
         | 
| 621 | 
            +
                var form = this._form;
         | 
| 622 | 
            +
                var value = $F(this._controls.editor);
         | 
| 623 | 
            +
                this.prepareSubmission();
         | 
| 624 | 
            +
                var params = this.options.callback(form, value) || '';
         | 
| 625 | 
            +
                if (Object.isString(params))
         | 
| 626 | 
            +
                  params = params.toQueryParams();
         | 
| 627 | 
            +
                params.editorId = this.element.id;
         | 
| 628 | 
            +
                if (this.options.htmlResponse) {
         | 
| 629 | 
            +
                  var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions);
         | 
| 630 | 
            +
                  Object.extend(options, {
         | 
| 631 | 
            +
                    parameters: params,
         | 
| 632 | 
            +
                    onComplete: this._boundWrapperHandler,
         | 
| 633 | 
            +
                    onFailure: this._boundFailureHandler
         | 
| 634 | 
            +
                  });
         | 
| 635 | 
            +
                  new Ajax.Updater({ success: this.element }, this.url, options);
         | 
| 636 | 
            +
                } else {
         | 
| 637 | 
            +
                  var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
         | 
| 638 | 
            +
                  Object.extend(options, {
         | 
| 639 | 
            +
                    parameters: params,
         | 
| 640 | 
            +
                    onComplete: this._boundWrapperHandler,
         | 
| 641 | 
            +
                    onFailure: this._boundFailureHandler
         | 
| 642 | 
            +
                  });
         | 
| 643 | 
            +
                  new Ajax.Request(this.url, options);
         | 
| 702 644 | 
             
                }
         | 
| 703 | 
            -
                 | 
| 645 | 
            +
                if (e) Event.stop(e);
         | 
| 646 | 
            +
              },
         | 
| 647 | 
            +
              leaveEditMode: function() {
         | 
| 648 | 
            +
                this.element.removeClassName(this.options.savingClassName);
         | 
| 649 | 
            +
                this.removeForm();
         | 
| 650 | 
            +
                this.leaveHover();
         | 
| 651 | 
            +
                this.element.style.backgroundColor = this._originalBackground;
         | 
| 652 | 
            +
                this.element.show();
         | 
| 653 | 
            +
                if (this.options.externalControl)
         | 
| 654 | 
            +
                  this.options.externalControl.show();
         | 
| 655 | 
            +
                this._saving = false;
         | 
| 656 | 
            +
                this._editing = false;
         | 
| 657 | 
            +
                this._oldInnerHTML = null;
         | 
| 658 | 
            +
                this.triggerCallback('onLeaveEditMode');
         | 
| 659 | 
            +
              },
         | 
| 660 | 
            +
              leaveHover: function(e) {
         | 
| 661 | 
            +
                if (this.options.hoverClassName)
         | 
| 662 | 
            +
                  this.element.removeClassName(this.options.hoverClassName);
         | 
| 663 | 
            +
                if (this._saving) return;
         | 
| 664 | 
            +
                this.triggerCallback('onLeaveHover');
         | 
| 704 665 | 
             
              },
         | 
| 705 | 
            -
               | 
| 706 | 
            -
                this. | 
| 666 | 
            +
              loadExternalText: function() {
         | 
| 667 | 
            +
                this._form.addClassName(this.options.loadingClassName);
         | 
| 668 | 
            +
                this._controls.editor.disabled = true;
         | 
| 669 | 
            +
                var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
         | 
| 670 | 
            +
                Object.extend(options, {
         | 
| 671 | 
            +
                  parameters: 'editorId=' + encodeURIComponent(this.element.id),
         | 
| 672 | 
            +
                  onComplete: Prototype.emptyFunction,
         | 
| 673 | 
            +
                  onSuccess: function(transport) {
         | 
| 674 | 
            +
                    this._form.removeClassName(this.options.loadingClassName);
         | 
| 675 | 
            +
                    var text = transport.responseText;
         | 
| 676 | 
            +
                    if (this.options.stripLoadedTextTags)
         | 
| 677 | 
            +
                      text = text.stripTags();
         | 
| 678 | 
            +
                    this._controls.editor.value = text;
         | 
| 679 | 
            +
                    this._controls.editor.disabled = false;
         | 
| 680 | 
            +
                    this.postProcessEditField();
         | 
| 681 | 
            +
                  }.bind(this),
         | 
| 682 | 
            +
                  onFailure: this._boundFailureHandler
         | 
| 683 | 
            +
                });
         | 
| 684 | 
            +
                new Ajax.Request(this.options.loadTextURL, options);
         | 
| 685 | 
            +
              },
         | 
| 686 | 
            +
              postProcessEditField: function() {
         | 
| 687 | 
            +
                var fpc = this.options.fieldPostCreation;
         | 
| 688 | 
            +
                if (fpc)
         | 
| 689 | 
            +
                  $(this._controls.editor)['focus' == fpc ? 'focus' : 'activate']();
         | 
| 690 | 
            +
              },
         | 
| 691 | 
            +
              prepareOptions: function() {
         | 
| 692 | 
            +
                this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions);
         | 
| 693 | 
            +
                Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks);
         | 
| 694 | 
            +
                [this._extraDefaultOptions].flatten().compact().each(function(defs) {
         | 
| 695 | 
            +
                  Object.extend(this.options, defs);
         | 
| 696 | 
            +
                }.bind(this));
         | 
| 697 | 
            +
              },
         | 
| 698 | 
            +
              prepareSubmission: function() {
         | 
| 699 | 
            +
                this._saving = true;
         | 
| 707 700 | 
             
                this.removeForm();
         | 
| 708 701 | 
             
                this.leaveHover();
         | 
| 709 702 | 
             
                this.showSaving();
         | 
| 710 703 | 
             
              },
         | 
| 704 | 
            +
              registerListeners: function() {
         | 
| 705 | 
            +
                this._listeners = { };
         | 
| 706 | 
            +
                var listener;
         | 
| 707 | 
            +
                $H(Ajax.InPlaceEditor.Listeners).each(function(pair) {
         | 
| 708 | 
            +
                  listener = this[pair.value].bind(this);
         | 
| 709 | 
            +
                  this._listeners[pair.key] = listener;
         | 
| 710 | 
            +
                  if (!this.options.externalControlOnly)
         | 
| 711 | 
            +
                    this.element.observe(pair.key, listener);
         | 
| 712 | 
            +
                  if (this.options.externalControl)
         | 
| 713 | 
            +
                    this.options.externalControl.observe(pair.key, listener);
         | 
| 714 | 
            +
                }.bind(this));
         | 
| 715 | 
            +
              },
         | 
| 716 | 
            +
              removeForm: function() {
         | 
| 717 | 
            +
                if (!this._form) return;
         | 
| 718 | 
            +
                this._form.remove();
         | 
| 719 | 
            +
                this._form = null;
         | 
| 720 | 
            +
                this._controls = { };
         | 
| 721 | 
            +
              },
         | 
| 711 722 | 
             
              showSaving: function() {
         | 
| 712 | 
            -
                this. | 
| 723 | 
            +
                this._oldInnerHTML = this.element.innerHTML;
         | 
| 713 724 | 
             
                this.element.innerHTML = this.options.savingText;
         | 
| 714 | 
            -
                 | 
| 715 | 
            -
                this.element.style.backgroundColor = this. | 
| 716 | 
            -
                 | 
| 725 | 
            +
                this.element.addClassName(this.options.savingClassName);
         | 
| 726 | 
            +
                this.element.style.backgroundColor = this._originalBackground;
         | 
| 727 | 
            +
                this.element.show();
         | 
| 717 728 | 
             
              },
         | 
| 718 | 
            -
               | 
| 719 | 
            -
                if(this. | 
| 720 | 
            -
                   | 
| 721 | 
            -
                  this.form = null;
         | 
| 729 | 
            +
              triggerCallback: function(cbName, arg) {
         | 
| 730 | 
            +
                if ('function' == typeof this.options[cbName]) {
         | 
| 731 | 
            +
                  this.options[cbName](this, arg);
         | 
| 722 732 | 
             
                }
         | 
| 723 733 | 
             
              },
         | 
| 724 | 
            -
               | 
| 725 | 
            -
                 | 
| 726 | 
            -
             | 
| 727 | 
            -
             | 
| 728 | 
            -
                  this. | 
| 729 | 
            -
             | 
| 730 | 
            -
                 | 
| 734 | 
            +
              unregisterListeners: function() {
         | 
| 735 | 
            +
                $H(this._listeners).each(function(pair) {
         | 
| 736 | 
            +
                  if (!this.options.externalControlOnly)
         | 
| 737 | 
            +
                    this.element.stopObserving(pair.key, pair.value);
         | 
| 738 | 
            +
                  if (this.options.externalControl)
         | 
| 739 | 
            +
                    this.options.externalControl.stopObserving(pair.key, pair.value);
         | 
| 740 | 
            +
                }.bind(this));
         | 
| 731 741 | 
             
              },
         | 
| 732 | 
            -
               | 
| 733 | 
            -
                 | 
| 734 | 
            -
             | 
| 735 | 
            -
                 | 
| 736 | 
            -
                 | 
| 737 | 
            -
             | 
| 738 | 
            -
             | 
| 739 | 
            -
             | 
| 740 | 
            -
             | 
| 741 | 
            -
             | 
| 742 | 
            +
              wrapUp: function(transport) {
         | 
| 743 | 
            +
                this.leaveEditMode();
         | 
| 744 | 
            +
                // Can't use triggerCallback due to backward compatibility: requires
         | 
| 745 | 
            +
                // binding + direct element
         | 
| 746 | 
            +
                this._boundComplete(transport, this.element);
         | 
| 747 | 
            +
              }
         | 
| 748 | 
            +
            });
         | 
| 749 | 
            +
             | 
| 750 | 
            +
            Object.extend(Ajax.InPlaceEditor.prototype, {
         | 
| 751 | 
            +
              dispose: Ajax.InPlaceEditor.prototype.destroy
         | 
| 752 | 
            +
            });
         | 
| 753 | 
            +
             | 
| 754 | 
            +
            Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, {
         | 
| 755 | 
            +
              initialize: function($super, element, url, options) {
         | 
| 756 | 
            +
                this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions;
         | 
| 757 | 
            +
                $super(element, url, options);
         | 
| 758 | 
            +
              },
         | 
| 759 | 
            +
             | 
| 760 | 
            +
              createEditField: function() {
         | 
| 761 | 
            +
                var list = document.createElement('select');
         | 
| 762 | 
            +
                list.name = this.options.paramName;
         | 
| 763 | 
            +
                list.size = 1;
         | 
| 764 | 
            +
                this._controls.editor = list;
         | 
| 765 | 
            +
                this._collection = this.options.collection || [];
         | 
| 766 | 
            +
                if (this.options.loadCollectionURL)
         | 
| 767 | 
            +
                  this.loadCollection();
         | 
| 768 | 
            +
                else
         | 
| 769 | 
            +
                  this.checkForExternalText();
         | 
| 770 | 
            +
                this._form.appendChild(this._controls.editor);
         | 
| 771 | 
            +
              },
         | 
| 772 | 
            +
             | 
| 773 | 
            +
              loadCollection: function() {
         | 
| 774 | 
            +
                this._form.addClassName(this.options.loadingClassName);
         | 
| 775 | 
            +
                this.showLoadingText(this.options.loadingCollectionText);
         | 
| 776 | 
            +
                var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
         | 
| 777 | 
            +
                Object.extend(options, {
         | 
| 778 | 
            +
                  parameters: 'editorId=' + encodeURIComponent(this.element.id),
         | 
| 779 | 
            +
                  onComplete: Prototype.emptyFunction,
         | 
| 780 | 
            +
                  onSuccess: function(transport) {
         | 
| 781 | 
            +
                    var js = transport.responseText.strip();
         | 
| 782 | 
            +
                    if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check
         | 
| 783 | 
            +
                      throw 'Server returned an invalid collection representation.';
         | 
| 784 | 
            +
                    this._collection = eval(js);
         | 
| 785 | 
            +
                    this.checkForExternalText();
         | 
| 786 | 
            +
                  }.bind(this),
         | 
| 787 | 
            +
                  onFailure: this.onFailure
         | 
| 742 788 | 
             
                });
         | 
| 789 | 
            +
                new Ajax.Request(this.options.loadCollectionURL, options);
         | 
| 743 790 | 
             
              },
         | 
| 744 | 
            -
             | 
| 745 | 
            -
             | 
| 746 | 
            -
                this. | 
| 747 | 
            -
                this. | 
| 748 | 
            -
                 | 
| 749 | 
            -
             | 
| 750 | 
            -
             | 
| 751 | 
            -
                   | 
| 791 | 
            +
             | 
| 792 | 
            +
              showLoadingText: function(text) {
         | 
| 793 | 
            +
                this._controls.editor.disabled = true;
         | 
| 794 | 
            +
                var tempOption = this._controls.editor.firstChild;
         | 
| 795 | 
            +
                if (!tempOption) {
         | 
| 796 | 
            +
                  tempOption = document.createElement('option');
         | 
| 797 | 
            +
                  tempOption.value = '';
         | 
| 798 | 
            +
                  this._controls.editor.appendChild(tempOption);
         | 
| 799 | 
            +
                  tempOption.selected = true;
         | 
| 752 800 | 
             
                }
         | 
| 753 | 
            -
                 | 
| 754 | 
            -
                this.saving = false;
         | 
| 755 | 
            -
                this.oldInnerHTML = null;
         | 
| 756 | 
            -
                this.onLeaveEditMode();
         | 
| 801 | 
            +
                tempOption.update((text || '').stripScripts().stripTags());
         | 
| 757 802 | 
             
              },
         | 
| 758 | 
            -
             | 
| 759 | 
            -
             | 
| 760 | 
            -
                this. | 
| 803 | 
            +
             | 
| 804 | 
            +
              checkForExternalText: function() {
         | 
| 805 | 
            +
                this._text = this.getText();
         | 
| 806 | 
            +
                if (this.options.loadTextURL)
         | 
| 807 | 
            +
                  this.loadExternalText();
         | 
| 808 | 
            +
                else
         | 
| 809 | 
            +
                  this.buildOptionList();
         | 
| 761 810 | 
             
              },
         | 
| 762 | 
            -
             | 
| 763 | 
            -
               | 
| 764 | 
            -
             | 
| 765 | 
            -
                 | 
| 766 | 
            -
             | 
| 767 | 
            -
             | 
| 768 | 
            -
             | 
| 769 | 
            -
             | 
| 770 | 
            -
             | 
| 771 | 
            -
             | 
| 772 | 
            -
             | 
| 773 | 
            -
                   | 
| 774 | 
            -
             | 
| 775 | 
            -
             | 
| 776 | 
            -
             | 
| 811 | 
            +
             | 
| 812 | 
            +
              loadExternalText: function() {
         | 
| 813 | 
            +
                this.showLoadingText(this.options.loadingText);
         | 
| 814 | 
            +
                var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
         | 
| 815 | 
            +
                Object.extend(options, {
         | 
| 816 | 
            +
                  parameters: 'editorId=' + encodeURIComponent(this.element.id),
         | 
| 817 | 
            +
                  onComplete: Prototype.emptyFunction,
         | 
| 818 | 
            +
                  onSuccess: function(transport) {
         | 
| 819 | 
            +
                    this._text = transport.responseText.strip();
         | 
| 820 | 
            +
                    this.buildOptionList();
         | 
| 821 | 
            +
                  }.bind(this),
         | 
| 822 | 
            +
                  onFailure: this.onFailure
         | 
| 823 | 
            +
                });
         | 
| 824 | 
            +
                new Ajax.Request(this.options.loadTextURL, options);
         | 
| 825 | 
            +
              },
         | 
| 826 | 
            +
             | 
| 827 | 
            +
              buildOptionList: function() {
         | 
| 828 | 
            +
                this._form.removeClassName(this.options.loadingClassName);
         | 
| 829 | 
            +
                this._collection = this._collection.map(function(entry) {
         | 
| 830 | 
            +
                  return 2 === entry.length ? entry : [entry, entry].flatten();
         | 
| 831 | 
            +
                });
         | 
| 832 | 
            +
                var marker = ('value' in this.options) ? this.options.value : this._text;
         | 
| 833 | 
            +
                var textFound = this._collection.any(function(entry) {
         | 
| 834 | 
            +
                  return entry[0] == marker;
         | 
| 835 | 
            +
                }.bind(this));
         | 
| 836 | 
            +
                this._controls.editor.update('');
         | 
| 837 | 
            +
                var option;
         | 
| 838 | 
            +
                this._collection.each(function(entry, index) {
         | 
| 839 | 
            +
                  option = document.createElement('option');
         | 
| 840 | 
            +
                  option.value = entry[0];
         | 
| 841 | 
            +
                  option.selected = textFound ? entry[0] == marker : 0 == index;
         | 
| 842 | 
            +
                  option.appendChild(document.createTextNode(entry[1]));
         | 
| 843 | 
            +
                  this._controls.editor.appendChild(option);
         | 
| 844 | 
            +
                }.bind(this));
         | 
| 845 | 
            +
                this._controls.editor.disabled = false;
         | 
| 846 | 
            +
                Field.scrollFreeActivate(this._controls.editor);
         | 
| 777 847 | 
             
              }
         | 
| 778 | 
            -
            };
         | 
| 848 | 
            +
            });
         | 
| 779 849 |  | 
| 780 | 
            -
             | 
| 781 | 
            -
             | 
| 782 | 
            -
             | 
| 783 | 
            -
             | 
| 784 | 
            -
             | 
| 785 | 
            -
             | 
| 786 | 
            -
             | 
| 787 | 
            -
             | 
| 788 | 
            -
             | 
| 789 | 
            -
             | 
| 790 | 
            -
             | 
| 791 | 
            -
             | 
| 792 | 
            -
             | 
| 793 | 
            -
             | 
| 794 | 
            -
             | 
| 795 | 
            -
             | 
| 796 | 
            -
             | 
| 797 | 
            -
             | 
| 798 | 
            -
                }
         | 
| 850 | 
            +
            //**** DEPRECATION LAYER FOR InPlace[Collection]Editor! ****
         | 
| 851 | 
            +
            //**** This only  exists for a while,  in order to  let ****
         | 
| 852 | 
            +
            //**** users adapt to  the new API.  Read up on the new ****
         | 
| 853 | 
            +
            //**** API and convert your code to it ASAP!            ****
         | 
| 854 | 
            +
             | 
| 855 | 
            +
            Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options) {
         | 
| 856 | 
            +
              if (!options) return;
         | 
| 857 | 
            +
              function fallback(name, expr) {
         | 
| 858 | 
            +
                if (name in options || expr === undefined) return;
         | 
| 859 | 
            +
                options[name] = expr;
         | 
| 860 | 
            +
              };
         | 
| 861 | 
            +
              fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' :
         | 
| 862 | 
            +
                options.cancelLink == options.cancelButton == false ? false : undefined)));
         | 
| 863 | 
            +
              fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' :
         | 
| 864 | 
            +
                options.okLink == options.okButton == false ? false : undefined)));
         | 
| 865 | 
            +
              fallback('highlightColor', options.highlightcolor);
         | 
| 866 | 
            +
              fallback('highlightEndColor', options.highlightendcolor);
         | 
| 867 | 
            +
            };
         | 
| 799 868 |  | 
| 800 | 
            -
             | 
| 801 | 
            -
             | 
| 802 | 
            -
                 | 
| 803 | 
            -
                 | 
| 804 | 
            -
             | 
| 869 | 
            +
            Object.extend(Ajax.InPlaceEditor, {
         | 
| 870 | 
            +
              DefaultOptions: {
         | 
| 871 | 
            +
                ajaxOptions: { },
         | 
| 872 | 
            +
                autoRows: 3,                                // Use when multi-line w/ rows == 1
         | 
| 873 | 
            +
                cancelControl: 'link',                      // 'link'|'button'|false
         | 
| 874 | 
            +
                cancelText: 'cancel',
         | 
| 875 | 
            +
                clickToEditText: 'Click to edit',
         | 
| 876 | 
            +
                externalControl: null,                      // id|elt
         | 
| 877 | 
            +
                externalControlOnly: false,
         | 
| 878 | 
            +
                fieldPostCreation: 'activate',              // 'activate'|'focus'|false
         | 
| 879 | 
            +
                formClassName: 'inplaceeditor-form',
         | 
| 880 | 
            +
                formId: null,                               // id|elt
         | 
| 881 | 
            +
                highlightColor: '#ffff99',
         | 
| 882 | 
            +
                highlightEndColor: '#ffffff',
         | 
| 883 | 
            +
                hoverClassName: '',
         | 
| 884 | 
            +
                htmlResponse: true,
         | 
| 885 | 
            +
                loadingClassName: 'inplaceeditor-loading',
         | 
| 886 | 
            +
                loadingText: 'Loading...',
         | 
| 887 | 
            +
                okControl: 'button',                        // 'link'|'button'|false
         | 
| 888 | 
            +
                okText: 'ok',
         | 
| 889 | 
            +
                paramName: 'value',
         | 
| 890 | 
            +
                rows: 1,                                    // If 1 and multi-line, uses autoRows
         | 
| 891 | 
            +
                savingClassName: 'inplaceeditor-saving',
         | 
| 892 | 
            +
                savingText: 'Saving...',
         | 
| 893 | 
            +
                size: 0,
         | 
| 894 | 
            +
                stripLoadedTextTags: false,
         | 
| 895 | 
            +
                submitOnBlur: false,
         | 
| 896 | 
            +
                textAfterControls: '',
         | 
| 897 | 
            +
                textBeforeControls: '',
         | 
| 898 | 
            +
                textBetweenControls: ''
         | 
| 899 | 
            +
              },
         | 
| 900 | 
            +
              DefaultCallbacks: {
         | 
| 901 | 
            +
                callback: function(form) {
         | 
| 902 | 
            +
                  return Form.serialize(form);
         | 
| 903 | 
            +
                },
         | 
| 904 | 
            +
                onComplete: function(transport, element) {
         | 
| 905 | 
            +
                  // For backward compatibility, this one is bound to the IPE, and passes
         | 
| 906 | 
            +
                  // the element directly.  It was too often customized, so we don't break it.
         | 
| 907 | 
            +
                  new Effect.Highlight(element, {
         | 
| 908 | 
            +
                    startcolor: this.options.highlightColor, keepBackgroundImage: true });
         | 
| 909 | 
            +
                },
         | 
| 910 | 
            +
                onEnterEditMode: null,
         | 
| 911 | 
            +
                onEnterHover: function(ipe) {
         | 
| 912 | 
            +
                  ipe.element.style.backgroundColor = ipe.options.highlightColor;
         | 
| 913 | 
            +
                  if (ipe._effect)
         | 
| 914 | 
            +
                    ipe._effect.cancel();
         | 
| 915 | 
            +
                },
         | 
| 916 | 
            +
                onFailure: function(transport, ipe) {
         | 
| 917 | 
            +
                  alert('Error communication with the server: ' + transport.responseText.stripTags());
         | 
| 918 | 
            +
                },
         | 
| 919 | 
            +
                onFormCustomization: null, // Takes the IPE and its generated form, after editor, before controls.
         | 
| 920 | 
            +
                onLeaveEditMode: null,
         | 
| 921 | 
            +
                onLeaveHover: function(ipe) {
         | 
| 922 | 
            +
                  ipe._effect = new Effect.Highlight(ipe.element, {
         | 
| 923 | 
            +
                    startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor,
         | 
| 924 | 
            +
                    restorecolor: ipe._originalBackground, keepBackgroundImage: true
         | 
| 925 | 
            +
                  });
         | 
| 805 926 | 
             
                }
         | 
| 927 | 
            +
              },
         | 
| 928 | 
            +
              Listeners: {
         | 
| 929 | 
            +
                click: 'enterEditMode',
         | 
| 930 | 
            +
                keydown: 'checkForEscapeOrReturn',
         | 
| 931 | 
            +
                mouseover: 'enterHover',
         | 
| 932 | 
            +
                mouseout: 'leaveHover'
         | 
| 806 933 | 
             
              }
         | 
| 807 934 | 
             
            });
         | 
| 808 935 |  | 
| 936 | 
            +
            Ajax.InPlaceCollectionEditor.DefaultOptions = {
         | 
| 937 | 
            +
              loadingCollectionText: 'Loading options...'
         | 
| 938 | 
            +
            };
         | 
| 939 | 
            +
             | 
| 809 940 | 
             
            // Delayed observer, like Form.Element.Observer, 
         | 
| 810 941 | 
             
            // but waits for delay after last key input
         | 
| 811 942 | 
             
            // Ideal for live-search fields
         | 
| 812 943 |  | 
| 813 | 
            -
            Form.Element.DelayedObserver = Class.create( | 
| 814 | 
            -
            Form.Element.DelayedObserver.prototype = {
         | 
| 944 | 
            +
            Form.Element.DelayedObserver = Class.create({
         | 
| 815 945 | 
             
              initialize: function(element, delay, callback) {
         | 
| 816 946 | 
             
                this.delay     = delay || 0.5;
         | 
| 817 947 | 
             
                this.element   = $(element);
         | 
| @@ -830,4 +960,4 @@ Form.Element.DelayedObserver.prototype = { | |
| 830 960 | 
             
                this.timer = null;
         | 
| 831 961 | 
             
                this.callback(this.element, $F(this.element));
         | 
| 832 962 | 
             
              }
         | 
| 833 | 
            -
            };
         | 
| 963 | 
            +
            });
         |