diff options
| -rw-r--r-- | README-rails.txt | 188 | ||||
| -rw-r--r-- | Rakefile | 9 | ||||
| -rw-r--r-- | config.ru | 6 | ||||
| -rw-r--r-- | config/application.rb | 42 | ||||
| -rw-r--r-- | config/boot.rb | 137 | ||||
| -rw-r--r-- | config/initializers/backtrace_silencers.rb | 7 | ||||
| -rw-r--r-- | config/initializers/inflections.rb | 10 | ||||
| -rw-r--r-- | config/initializers/mime_types.rb | 5 | ||||
| -rw-r--r-- | config/initializers/secret_token.rb | 7 | ||||
| -rw-r--r-- | config/initializers/session_store.rb | 12 | ||||
| -rw-r--r-- | db/seeds.rb | 7 | ||||
| -rw-r--r-- | lib/tasks/.gitkeep | 0 | ||||
| -rw-r--r-- | public/404.html | 34 | ||||
| -rw-r--r-- | public/422.html | 26 | ||||
| -rw-r--r-- | public/500.html | 36 | ||||
| -rw-r--r-- | public/javascripts/controls.js | 148 | ||||
| -rw-r--r-- | public/javascripts/dragdrop.js | 340 | ||||
| -rw-r--r-- | public/javascripts/effects.js | 357 | ||||
| -rw-r--r-- | public/javascripts/prototype.js | 5198 | ||||
| -rw-r--r-- | public/javascripts/rails.js | 202 | ||||
| -rwxr-xr-x[-rw-r--r--] | script/cache-incoming-emails | 0 | ||||
| -rwxr-xr-x | script/rails | 6 | 
22 files changed, 4267 insertions, 2510 deletions
diff --git a/README-rails.txt b/README-rails.txt deleted file mode 100644 index 025ee5e84..000000000 --- a/README-rails.txt +++ /dev/null @@ -1,188 +0,0 @@ -== Welcome to Rails - -Rails is a web-application and persistence framework that includes everything -needed to create database-backed web-applications according to the -Model-View-Control pattern of separation. This pattern splits the view (also -called the presentation) into "dumb" templates that are primarily responsible -for inserting pre-built data in between HTML tags. The model contains the -"smart" domain objects (such as Account, Product, Person, Post) that holds all -the business logic and knows how to persist themselves to a database. The -controller handles the incoming requests (such as Save New Account, Update -Product, Show Post) by manipulating the model and directing data to the view. - -In Rails, the model is handled by what's called an object-relational mapping -layer entitled Active Record. This layer allows you to present the data from -database rows as objects and embellish these data objects with business logic -methods. You can read more about Active Record in -link:files/vendor/rails/activerecord/README.html. - -The controller and view are handled by the Action Pack, which handles both -layers by its two parts: Action View and Action Controller. These two layers -are bundled in a single package due to their heavy interdependence. This is -unlike the relationship between the Active Record and Action Pack that is much -more separate. Each of these packages can be used independently outside of -Rails.  You can read more about Action Pack in -link:files/vendor/rails/actionpack/README.html. - - -== Getting started - -1. At the command prompt, start a new rails application using the rails command -   and your application name. Ex: rails myapp -   (If you've downloaded rails in a complete tgz or zip, this step is already done) -2. Change directory into myapp and start the web server: <tt>script/server</tt> (run with --help for options) -3. Go to http://localhost:3000/ and get "Welcome aboard: You’re riding the Rails!" -4. Follow the guidelines to start developing your application - - -== Web Servers - -By default, Rails will try to use Mongrel and lighttpd if they are installed, otherwise -Rails will use the WEBrick, the webserver that ships with Ruby. When you run script/server, -Rails will check if Mongrel exists, then lighttpd and finally fall back to WEBrick. This ensures -that you can always get up and running quickly. - -Mongrel is a Ruby-based webserver with a C-component (which requires compilation) that is -suitable for development and deployment of Rails applications. If you have Ruby Gems installed, -getting up and running with mongrel is as easy as: <tt>gem install mongrel</tt>. -More info at: http://mongrel.rubyforge.org - -If Mongrel is not installed, Rails will look for lighttpd. It's considerably faster than -Mongrel and WEBrick and also suited for production use, but requires additional -installation and currently only works well on OS X/Unix (Windows users are encouraged -to start with Mongrel). We recommend version 1.4.11 and higher. You can download it from -http://www.lighttpd.net. - -And finally, if neither Mongrel or lighttpd are installed, Rails will use the built-in Ruby -web server, WEBrick. WEBrick is a small Ruby web server suitable for development, but not -for production. - -But of course its also possible to run Rails on any platform that supports FCGI. -Apache, LiteSpeed, IIS are just a few. For more information on FCGI, -please visit: http://wiki.rubyonrails.com/rails/pages/FastCGI - - -== Debugging Rails - -Have "tail -f" commands running on the server.log and development.log. Rails will -automatically display debugging and runtime information to these files. Debugging -info will also be shown in the browser on requests from 127.0.0.1. - - -== Breakpoints - -Breakpoint support is available through the script/breakpointer client. This -means that you can break out of execution at any point in the code, investigate -and change the model, AND then resume execution! Example: - -  class WeblogController < ActionController::Base -    def index -      @posts = Post.find(:all) -      breakpoint "Breaking out from the list" -    end -  end - -So the controller will accept the action, run the first line, then present you -with a IRB prompt in the breakpointer window. Here you can do things like: - -Executing breakpoint "Breaking out from the list" at .../webrick_server.rb:16 in 'breakpoint' - -  >> @posts.inspect -  => "[#<Post:0x14a6be8 @attributes={\"title\"=>nil, \"body\"=>nil, \"id\"=>\"1\"}>, -       #<Post:0x14a6620 @attributes={\"title\"=>\"Rails you know!\", \"body\"=>\"Only ten..\", \"id\"=>\"2\"}>]" -  >> @posts.first.title = "hello from a breakpoint" -  => "hello from a breakpoint" - -...and even better is that you can examine how your runtime objects actually work: - -  >> f = @posts.first -  => #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}> -  >> f. -  Display all 152 possibilities? (y or n) - -Finally, when you're ready to resume execution, you press CTRL-D - - -== Console - -You can interact with the domain model by starting the console through <tt>script/console</tt>. -Here you'll have all parts of the application configured, just like it is when the -application is running. You can inspect domain models, change values, and save to the -database. Starting the script without arguments will launch it in the development environment. -Passing an argument will specify a different environment, like <tt>script/console production</tt>. - -To reload your controllers and models after launching the console run <tt>reload!</tt> - -To reload your controllers and models after launching the console run <tt>reload!</tt> - - - -== Description of contents - -app -  Holds all the code that's specific to this particular application. - -app/controllers -  Holds controllers that should be named like weblogs_controller.rb for -  automated URL mapping. All controllers should descend from ApplicationController -  which itself descends from ActionController::Base. - -app/models -  Holds models that should be named like post.rb. -  Most models will descend from ActiveRecord::Base. - -app/views -  Holds the template files for the view that should be named like -  weblogs/index.rhtml for the WeblogsController#index action. All views use eRuby -  syntax. - -app/views/layouts -  Holds the template files for layouts to be used with views. This models the common -  header/footer method of wrapping views. In your views, define a layout using the -  <tt>layout :default</tt> and create a file named default.rhtml. Inside default.rhtml, -  call <% yield %> to render the view using this layout. - -app/helpers -  Holds view helpers that should be named like weblogs_helper.rb. These are generated -  for you automatically when using script/generate for controllers. Helpers can be used to -  wrap functionality for your views into methods. - -config -  Configuration files for the Rails environment, the routing map, the database, and other dependencies. - -components -  Self-contained mini-applications that can bundle together controllers, models, and views. - -db -  Contains the database schema in schema.rb.  db/migrate contains all -  the sequence of Migrations for your schema. - -doc -  This directory is where your application documentation will be stored when generated -  using <tt>rake doc:app</tt> - -lib -  Application specific libraries. Basically, any kind of custom code that doesn't -  belong under controllers, models, or helpers. This directory is in the load path. - -public -  The directory available for the web server. Contains subdirectories for images, stylesheets, -  and javascripts. Also contains the dispatchers and the default HTML files. This should be -  set as the DOCUMENT_ROOT of your web server. - -script -  Helper scripts for automation and generation. - -spec -  Unit and functional specifications along with fixtures, using rspec. We use -  this instead of test. - -test -  DEPRECATED for this project, see 'spec' instead. Unit and functional tests -  along with fixtures.  When using the script/generate scripts, template test -  files will be generated for you and placed in this directory. - -vendor -  External libraries that the application depends on. Also includes the plugins subdirectory. -  This directory is in the load path. - @@ -1,12 +1,7 @@  # Add your own tasks in files placed in lib/tasks ending in .rake,  # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. -require(File.join(File.dirname(__FILE__), 'config', 'boot')) - +require File.expand_path('../config/application', __FILE__)  require 'rake' -require 'rake/testtask' -require 'rdoc/task' - -require 'tasks/rails' -Dir[File.join(File.dirname(__FILE__),'commonlib','rblib','tests','*.rake')].each { |file| load(file) } +Alaveteli::Application.load_tasks @@ -1,2 +1,4 @@ -require File.dirname(__FILE__) + '/config/environment' -run ActionController::Dispatcher.new +# This file is used by Rack-based servers to start the application. + +require ::File.expand_path('../config/environment',  __FILE__) +run Alaveteli::Application diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 000000000..91bb930fa --- /dev/null +++ b/config/application.rb @@ -0,0 +1,42 @@ +require File.expand_path('../boot', __FILE__) + +require 'rails/all' + +# If you have a Gemfile, require the gems listed there, including any gems +# you've limited to :test, :development, or :production. +Bundler.require(:default, Rails.env) if defined?(Bundler) + +module Alaveteli +  class Application < Rails::Application +    # Settings in config/environments/* take precedence over those specified here. +    # Application configuration should go into files in config/initializers +    # -- all .rb files in that directory are automatically loaded. + +    # Custom directories with classes and modules you want to be autoloadable. +    # config.autoload_paths += %W(#{config.root}/extras) + +    # Only load the plugins named here, in the order given (default is alphabetical). +    # :all can be used as a placeholder for all plugins not explicitly named. +    # config.plugins = [ :exception_notification, :ssl_requirement, :all ] + +    # Activate observers that should always be running. +    # config.active_record.observers = :cacher, :garbage_collector, :forum_observer + +    # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. +    # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. +    # config.time_zone = 'Central Time (US & Canada)' + +    # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. +    # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] +    # config.i18n.default_locale = :de + +    # JavaScript files you want as :defaults (application.js is always included). +    # config.action_view.javascript_expansions[:defaults] = %w(jquery rails) + +    # Configure the default encoding used in templates for Ruby 1.9. +    config.encoding = "utf-8" + +    # Configure sensitive parameters which will be filtered from the log file. +    config.filter_parameters += [:password] +  end +end diff --git a/config/boot.rb b/config/boot.rb index 906a2bace..4489e5868 100644 --- a/config/boot.rb +++ b/config/boot.rb @@ -1,135 +1,6 @@ -# Don't change this file! -# Configure your app in config/environment.rb and config/environments/*.rb +require 'rubygems' -# Hmmm, that's a bit daft - 'production' needs setting not only in the web -# server, it also needs setting in all the scripts, so a central place seems -# better. Look for a config/rails_env file, and read stuff from there if  -# it exists. Put just a line like this in there: -#   ENV['RAILS_ENV'] = 'production' -rails_env_file = File.expand_path(File.join(File.dirname(__FILE__), 'rails_env.rb')) -if File.exists?(rails_env_file) -    require rails_env_file -end - -RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT) - -module Rails -  class << self -    def boot! -      unless booted? -        preinitialize -        pick_boot.run -      end -    end - -    def booted? -      defined? Rails::Initializer -    end - -    def pick_boot -      (vendor_rails? ? VendorBoot : GemBoot).new -    end - -    def vendor_rails? -      File.exist?("#{RAILS_ROOT}/vendor/rails/Rakefile") -    end - -    def preinitialize -      load(preinitializer_path) if File.exist?(preinitializer_path) -    end - -    def preinitializer_path -      "#{RAILS_ROOT}/config/preinitializer.rb" -    end -  end - -  class Boot -    def run -      load_initializer - -      Rails::Initializer.class_eval do -        def load_gems -          @bundler_loaded ||= Bundler.require :default, Rails.env -        end -      end - -      Rails::Initializer.run(:set_load_path) -    end -  end - -  class VendorBoot < Boot -    def load_initializer -      require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer" -      Rails::Initializer.run(:install_gem_spec_stubs) -      Rails::GemDependency.add_frozen_gem_path -    end -  end - -  class GemBoot < Boot -    def load_initializer -      self.class.load_rubygems -      load_rails_gem -      require 'initializer' -    end - -    def load_rails_gem -      if version = self.class.gem_version -        gem 'rails', version -      else -        gem 'rails' -      end -    rescue Gem::LoadError => load_error -      if load_error.message =~ /Could not find RubyGem rails/ -        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.) -        exit 1 -      else -        raise -      end -    end - -    class << self -      def rubygems_version -        Gem::RubyGemsVersion rescue nil -      end - -      def gem_version -        if defined? RAILS_GEM_VERSION -          RAILS_GEM_VERSION -        elsif ENV.include?('RAILS_GEM_VERSION') -          ENV['RAILS_GEM_VERSION'] -        else -          parse_gem_version(read_environment_rb) -        end -      end - -      def load_rubygems -        min_version = '1.3.2' -        require 'rubygems' - -        unless rubygems_version >= min_version -          $stderr.puts %Q(Rails requires RubyGems >= #{min_version} (you have #{rubygems_version}). Please `gem update --system` and try again.) -          exit 1 -        end - -      rescue LoadError -        $stderr.puts %Q(Rails requires RubyGems >= #{min_version}. Please install RubyGems and try again: http://rubygems.rubyforge.org) -        exit 1 -      end - -      def parse_gem_version(text) -        $1 if text =~ /^[^#]*RAILS_GEM_VERSION\s*=\s*["']([!~<>=]*\s*[\d.]+)["']/ -      end - -      private -        def read_environment_rb -          File.read("#{RAILS_ROOT}/config/environment.rb") -        end -    end -  end -end - - - -# All that for this: -Rails.boot! +# Set up gems listed in the Gemfile. +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) +require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) diff --git a/config/initializers/backtrace_silencers.rb b/config/initializers/backtrace_silencers.rb new file mode 100644 index 000000000..59385cdf3 --- /dev/null +++ b/config/initializers/backtrace_silencers.rb @@ -0,0 +1,7 @@ +# Be sure to restart your server when you modify this file. + +# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. +# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } + +# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. +# Rails.backtrace_cleaner.remove_silencers! diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 000000000..9e8b0131f --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,10 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format +# (all these examples are active by default): +# ActiveSupport::Inflector.inflections do |inflect| +#   inflect.plural /^(ox)$/i, '\1en' +#   inflect.singular /^(ox)en/i, '\1' +#   inflect.irregular 'person', 'people' +#   inflect.uncountable %w( fish sheep ) +# end diff --git a/config/initializers/mime_types.rb b/config/initializers/mime_types.rb new file mode 100644 index 000000000..72aca7e44 --- /dev/null +++ b/config/initializers/mime_types.rb @@ -0,0 +1,5 @@ +# Be sure to restart your server when you modify this file. + +# Add new mime types for use in respond_to blocks: +# Mime::Type.register "text/richtext", :rtf +# Mime::Type.register_alias "text/html", :iphone diff --git a/config/initializers/secret_token.rb b/config/initializers/secret_token.rb new file mode 100644 index 000000000..5277e8927 --- /dev/null +++ b/config/initializers/secret_token.rb @@ -0,0 +1,7 @@ +# Be sure to restart your server when you modify this file. + +# Your secret key for verifying the integrity of signed cookies. +# If you change this key, all old signed cookies will become invalid! +# Make sure the secret is at least 30 characters and all random, +# no regular words or you'll be exposed to dictionary attacks. +Alaveteli::Application.config.secret_token = Configuration::cookie_store_session_secret diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb index 8cfa333f2..ef1752c13 100644 --- a/config/initializers/session_store.rb +++ b/config/initializers/session_store.rb @@ -1,15 +1,5 @@  # Be sure to restart your server when you modify this file. - -# Your secret key for verifying cookie session data integrity. -# If you change this key, all old sessions will become invalid! -# Make sure the secret is at least 30 characters and all random, -# no regular words or you'll be exposed to dictionary attacks. - -ActionController::Base.session = { -  :key => '_wdtk_cookie_session', -  :secret => Configuration::cookie_store_session_secret -} -ActionController::Base.session_store = :cookie_store +Rails.application.config.session_store :cookie_store, :key => '_wdtk_cookie_session'  # Insert a bit of middleware code to prevent uneeded cookie setting.  require "#{Rails.root}/lib/whatdotheyknow/strip_empty_sessions" diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 000000000..664d8c74c --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,7 @@ +# This file should contain all the record creation needed to seed the database with its default values. +# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). +# +# Examples: +# +#   cities = City.create([{ :name => 'Chicago' }, { :name => 'Copenhagen' }]) +#   Mayor.create(:name => 'Daley', :city => cities.first) diff --git a/lib/tasks/.gitkeep b/lib/tasks/.gitkeep new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/lib/tasks/.gitkeep diff --git a/public/404.html b/public/404.html index eff660b90..9a48320a5 100644 --- a/public/404.html +++ b/public/404.html @@ -1,23 +1,19 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" -       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> - -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> - +<!DOCTYPE html> +<html>  <head> -  <meta http-equiv="content-type" content="text/html; charset=UTF-8" />    <title>The page you were looking for doesn't exist (404)</title> -	<style type="text/css"> -		body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; } -		div.dialog { -			width: 25em; -			padding: 0 4em; -			margin: 4em auto 0 auto; -			border: 1px solid #ccc; -			border-right-color: #999; -			border-bottom-color: #999; -		} -		h1 { font-size: 100%; color: #f00; line-height: 1.5em; } -	</style> +  <style type="text/css"> +    body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; } +    div.dialog { +      width: 25em; +      padding: 0 4em; +      margin: 4em auto 0 auto; +      border: 1px solid #ccc; +      border-right-color: #999; +      border-bottom-color: #999; +    } +    h1 { font-size: 100%; color: #f00; line-height: 1.5em; } +  </style>  </head>  <body> @@ -27,4 +23,4 @@      <p>You may have mistyped the address or the page may have moved.</p>    </div>  </body> -</html>
\ No newline at end of file +</html> diff --git a/public/422.html b/public/422.html new file mode 100644 index 000000000..83660ab18 --- /dev/null +++ b/public/422.html @@ -0,0 +1,26 @@ +<!DOCTYPE html> +<html> +<head> +  <title>The change you wanted was rejected (422)</title> +  <style type="text/css"> +    body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; } +    div.dialog { +      width: 25em; +      padding: 0 4em; +      margin: 4em auto 0 auto; +      border: 1px solid #ccc; +      border-right-color: #999; +      border-bottom-color: #999; +    } +    h1 { font-size: 100%; color: #f00; line-height: 1.5em; } +  </style> +</head> + +<body> +  <!-- This file lives in public/422.html --> +  <div class="dialog"> +    <h1>The change you wanted was rejected.</h1> +    <p>Maybe you tried to change something you didn't have access to.</p> +  </div> +</body> +</html> diff --git a/public/500.html b/public/500.html index f0aee0e9f..b80307fc1 100644 --- a/public/500.html +++ b/public/500.html @@ -1,23 +1,19 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" -       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> - -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> - +<!DOCTYPE html> +<html>  <head> -  <meta http-equiv="content-type" content="text/html; charset=UTF-8" /> -  <title>We're sorry, but something went wrong</title> -	<style type="text/css"> -		body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; } -		div.dialog { -			width: 25em; -			padding: 0 4em; -			margin: 4em auto 0 auto; -			border: 1px solid #ccc; -			border-right-color: #999; -			border-bottom-color: #999; -		} -		h1 { font-size: 100%; color: #f00; line-height: 1.5em; } -	</style> +  <title>We're sorry, but something went wrong (500)</title> +  <style type="text/css"> +    body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; } +    div.dialog { +      width: 25em; +      padding: 0 4em; +      margin: 4em auto 0 auto; +      border: 1px solid #ccc; +      border-right-color: #999; +      border-bottom-color: #999; +    } +    h1 { font-size: 100%; color: #f00; line-height: 1.5em; } +  </style>  </head>  <body> @@ -27,4 +23,4 @@      <p>We've been notified about this issue and we'll take a look at it shortly.</p>    </div>  </body> -</html>
\ No newline at end of file +</html> diff --git a/public/javascripts/controls.js b/public/javascripts/controls.js index 5aaf0bb2b..7392fb664 100644 --- a/public/javascripts/controls.js +++ b/public/javascripts/controls.js @@ -1,22 +1,24 @@ -// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) -//           (c) 2005-2007 Ivan Krstic (http://blogs.law.harvard.edu/ivan) -//           (c) 2005-2007 Jon Tirsen (http://www.tirsen.com) +// script.aculo.us controls.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009 + +// Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +//           (c) 2005-2009 Ivan Krstic (http://blogs.law.harvard.edu/ivan) +//           (c) 2005-2009 Jon Tirsen (http://www.tirsen.com)  // Contributors:  //  Richard Livsey  //  Rahul Bhargava  //  Rob Wills -//  +//  // script.aculo.us is freely distributable under the terms of an MIT-style license.  // For details, see the script.aculo.us web site: http://script.aculo.us/ -// Autocompleter.Base handles all the autocompletion functionality  +// Autocompleter.Base handles all the autocompletion functionality  // that's independent of the data source for autocompletion. This  // includes drawing the autocompletion menu, observing keyboard  // and mouse events, and similar.  // -// Specific autocompleters need to provide, at the very least,  +// Specific autocompleters need to provide, at the very least,  // a getUpdatedChoices function that will be invoked every time -// the text inside the monitored textbox changes. This method  +// the text inside the monitored textbox changes. This method  // should get the text for which to provide autocompletion by  // invoking this.getToken(), NOT by directly accessing  // this.element.value. This is to allow incremental tokenized @@ -30,23 +32,23 @@  // will incrementally autocomplete with a comma as the token.  // Additionally, ',' in the above example can be replaced with  // a token array, e.g. { tokens: [',', '\n'] } which -// enables autocompletion on multiple tokens. This is most  -// useful when one of the tokens is \n (a newline), as it  +// enables autocompletion on multiple tokens. This is most +// useful when one of the tokens is \n (a newline), as it  // allows smart autocompletion after linebreaks.  if(typeof Effect == 'undefined')    throw("controls.js requires including script.aculo.us' effects.js library"); -var Autocompleter = { } +var Autocompleter = { };  Autocompleter.Base = Class.create({    baseInitialize: function(element, update, options) { -    element          = $(element) -    this.element     = element;  -    this.update      = $(update);   -    this.hasFocus    = false;  -    this.changed     = false;  -    this.active      = false;  -    this.index       = 0;      +    element          = $(element); +    this.element     = element; +    this.update      = $(update); +    this.hasFocus    = false; +    this.changed     = false; +    this.active      = false; +    this.index       = 0;      this.entryCount  = 0;      this.oldElementValue = this.element.value; @@ -59,28 +61,28 @@ Autocompleter.Base = Class.create({      this.options.tokens       = this.options.tokens || [];      this.options.frequency    = this.options.frequency || 0.4;      this.options.minChars     = this.options.minChars || 1; -    this.options.onShow       = this.options.onShow ||  -      function(element, update){  +    this.options.onShow       = this.options.onShow || +      function(element, update){          if(!update.style.position || update.style.position=='absolute') {            update.style.position = 'absolute';            Position.clone(element, update, { -            setHeight: false,  +            setHeight: false,              offsetTop: element.offsetHeight            });          }          Effect.Appear(update,{duration:0.15});        }; -    this.options.onHide = this.options.onHide ||  +    this.options.onHide = this.options.onHide ||        function(element, update){ new Effect.Fade(update,{duration:0.15}) }; -    if(typeof(this.options.tokens) == 'string')  +    if(typeof(this.options.tokens) == 'string')        this.options.tokens = new Array(this.options.tokens);      // Force carriage returns as token delimiters anyway      if (!this.options.tokens.include('\n'))        this.options.tokens.push('\n');      this.observer = null; -     +      this.element.setAttribute('autocomplete','off');      Element.hide(this.update); @@ -91,10 +93,10 @@ Autocompleter.Base = Class.create({    show: function() {      if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update); -    if(!this.iefix &&  +    if(!this.iefix &&        (Prototype.Browser.IE) &&        (Element.getStyle(this.update, 'position')=='absolute')) { -      new Insertion.After(this.update,  +      new Insertion.After(this.update,         '<iframe id="' + this.update.id + '_iefix" '+         'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +         'src="javascript:false;" frameborder="0" scrolling="no"></iframe>'); @@ -102,7 +104,7 @@ Autocompleter.Base = Class.create({      }      if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);    }, -   +    fixIEOverlapping: function() {      Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});      this.iefix.style.zIndex = 1; @@ -150,15 +152,15 @@ Autocompleter.Base = Class.create({           Event.stop(event);           return;        } -     else  -       if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||  +     else +       if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||           (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return;      this.changed = true;      this.hasFocus = true;      if(this.observer) clearTimeout(this.observer); -      this.observer =  +      this.observer =          setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);    }, @@ -170,35 +172,35 @@ Autocompleter.Base = Class.create({    onHover: function(event) {      var element = Event.findElement(event, 'LI'); -    if(this.index != element.autocompleteIndex)  +    if(this.index != element.autocompleteIndex)      {          this.index = element.autocompleteIndex;          this.render();      }      Event.stop(event);    }, -   +    onClick: function(event) {      var element = Event.findElement(event, 'LI');      this.index = element.autocompleteIndex;      this.selectEntry();      this.hide();    }, -   +    onBlur: function(event) {      // needed to make click events working      setTimeout(this.hide.bind(this), 250);      this.hasFocus = false; -    this.active = false;      -  },  -   +    this.active = false; +  }, +    render: function() {      if(this.entryCount > 0) {        for (var i = 0; i < this.entryCount; i++) -        this.index==i ?  -          Element.addClassName(this.getEntry(i),"selected") :  +        this.index==i ? +          Element.addClassName(this.getEntry(i),"selected") :            Element.removeClassName(this.getEntry(i),"selected"); -      if(this.hasFocus) {  +      if(this.hasFocus) {          this.show();          this.active = true;        } @@ -207,27 +209,27 @@ Autocompleter.Base = Class.create({        this.hide();      }    }, -   +    markPrevious: function() { -    if(this.index > 0) this.index-- +    if(this.index > 0) this.index--;        else this.index = this.entryCount-1;      this.getEntry(this.index).scrollIntoView(true);    }, -   +    markNext: function() { -    if(this.index < this.entryCount-1) this.index++ +    if(this.index < this.entryCount-1) this.index++;        else this.index = 0;      this.getEntry(this.index).scrollIntoView(false);    }, -   +    getEntry: function(index) {      return this.update.firstChild.childNodes[index];    }, -   +    getCurrentEntry: function() {      return this.getEntry(this.index);    }, -   +    selectEntry: function() {      this.active = false;      this.updateElement(this.getCurrentEntry()); @@ -244,7 +246,7 @@ Autocompleter.Base = Class.create({        if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);      } else        value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal'); -     +      var bounds = this.getTokenBounds();      if (bounds[0] != -1) {        var newValue = this.element.value.substr(0, bounds[0]); @@ -257,7 +259,7 @@ Autocompleter.Base = Class.create({      }      this.oldElementValue = this.element.value;      this.element.focus(); -     +      if (this.options.afterUpdateElement)        this.options.afterUpdateElement(this.element, selectedElement);    }, @@ -269,20 +271,20 @@ Autocompleter.Base = Class.create({        Element.cleanWhitespace(this.update.down());        if(this.update.firstChild && this.update.down().childNodes) { -        this.entryCount =  +        this.entryCount =            this.update.down().childNodes.length;          for (var i = 0; i < this.entryCount; i++) {            var entry = this.getEntry(i);            entry.autocompleteIndex = i;            this.addObservers(entry);          } -      } else {  +      } else {          this.entryCount = 0;        }        this.stopIndicator();        this.index = 0; -       +        if(this.entryCount==1 && this.options.autoSelect) {          this.selectEntry();          this.hide(); @@ -298,7 +300,7 @@ Autocompleter.Base = Class.create({    },    onObserverEvent: function() { -    this.changed = false;    +    this.changed = false;      this.tokenBounds = null;      if(this.getToken().length>=this.options.minChars) {        this.getUpdatedChoices(); @@ -351,16 +353,16 @@ Ajax.Autocompleter = Class.create(Autocompleter.Base, {    getUpdatedChoices: function() {      this.startIndicator(); -     -    var entry = encodeURIComponent(this.options.paramName) + '=' +  + +    var entry = encodeURIComponent(this.options.paramName) + '=' +        encodeURIComponent(this.getToken());      this.options.parameters = this.options.callback ?        this.options.callback(this.element, entry) : entry; -    if(this.options.defaultParams)  +    if(this.options.defaultParams)        this.options.parameters += '&' + this.options.defaultParams; -     +      new Ajax.Request(this.url, this.options);    }, @@ -382,7 +384,7 @@ Ajax.Autocompleter = Class.create(Autocompleter.Base, {  // - choices - How many autocompletion choices to offer  //  // - partialSearch - If false, the autocompleter will match entered -//                    text only at the beginning of strings in the  +//                    text only at the beginning of strings in the  //                    autocomplete array. Defaults to true, which will  //                    match text at the beginning of any *word* in the  //                    strings in the autocomplete array. If you want to @@ -399,7 +401,7 @@ Ajax.Autocompleter = Class.create(Autocompleter.Base, {  // - ignoreCase - Whether to ignore case when autocompleting.  //                 Defaults to true.  // -// It's possible to pass in a custom function as the 'selector'  +// It's possible to pass in a custom function as the 'selector'  // option, if you prefer to write your own autocompletion logic.  // In that case, the other options above will not apply unless  // you support them. @@ -427,20 +429,20 @@ Autocompleter.Local = Class.create(Autocompleter.Base, {          var entry     = instance.getToken();          var count     = 0; -        for (var i = 0; i < instance.options.array.length &&   -          ret.length < instance.options.choices ; i++) {  +        for (var i = 0; i < instance.options.array.length && +          ret.length < instance.options.choices ; i++) {            var elem = instance.options.array[i]; -          var foundPos = instance.options.ignoreCase ?  -            elem.toLowerCase().indexOf(entry.toLowerCase()) :  +          var foundPos = instance.options.ignoreCase ? +            elem.toLowerCase().indexOf(entry.toLowerCase()) :              elem.indexOf(entry);            while (foundPos != -1) { -            if (foundPos == 0 && elem.length != entry.length) {  -              ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" +  +            if (foundPos == 0 && elem.length != entry.length) { +              ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" +                  elem.substr(entry.length) + "</li>");                break; -            } else if (entry.length >= instance.options.partialChars &&  +            } else if (entry.length >= instance.options.partialChars &&                instance.options.partialSearch && foundPos != -1) {                if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) {                  partial.push("<li>" + elem.substr(0, foundPos) + "<strong>" + @@ -450,14 +452,14 @@ Autocompleter.Local = Class.create(Autocompleter.Base, {                }              } -            foundPos = instance.options.ignoreCase ?  -              elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) :  +            foundPos = instance.options.ignoreCase ? +              elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) :                elem.indexOf(entry, foundPos + 1);            }          }          if (partial.length) -          ret = ret.concat(partial.slice(0, instance.options.choices - ret.length)) +          ret = ret.concat(partial.slice(0, instance.options.choices - ret.length));          return "<ul>" + ret.join('') + "</ul>";        }      }, options || { }); @@ -474,7 +476,7 @@ Field.scrollFreeActivate = function(field) {    setTimeout(function() {      Field.activate(field);    }, 1); -} +};  Ajax.InPlaceEditor = Class.create({    initialize: function(element, url, options) { @@ -604,7 +606,7 @@ Ajax.InPlaceEditor = Class.create({      this.triggerCallback('onEnterHover');    },    getText: function() { -    return this.element.innerHTML; +    return this.element.innerHTML.unescapeHTML();    },    handleAJAXFailure: function(transport) {      this.triggerCallback('onFailure', transport); @@ -780,7 +782,7 @@ Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, {        onSuccess: function(transport) {          var js = transport.responseText.strip();          if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check -          throw 'Server returned an invalid collection representation.'; +          throw('Server returned an invalid collection representation.');          this._collection = eval(js);          this.checkForExternalText();        }.bind(this), @@ -937,7 +939,7 @@ Ajax.InPlaceCollectionEditor.DefaultOptions = {    loadingCollectionText: 'Loading options...'  }; -// Delayed observer, like Form.Element.Observer,  +// Delayed observer, like Form.Element.Observer,  // but waits for delay after last key input  // Ideal for live-search fields @@ -947,7 +949,7 @@ Form.Element.DelayedObserver = Class.create({      this.element   = $(element);      this.callback  = callback;      this.timer     = null; -    this.lastValue = $F(this.element);  +    this.lastValue = $F(this.element);      Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));    },    delayedListener: function(event) { @@ -960,4 +962,4 @@ Form.Element.DelayedObserver = Class.create({      this.timer = null;      this.callback(this.element, $F(this.element));    } -}); +});
\ No newline at end of file diff --git a/public/javascripts/dragdrop.js b/public/javascripts/dragdrop.js index bf5cfea66..15c6dbca6 100644 --- a/public/javascripts/dragdrop.js +++ b/public/javascripts/dragdrop.js @@ -1,6 +1,7 @@ -// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) -//           (c) 2005-2007 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz) -//  +// script.aculo.us dragdrop.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009 + +// Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +//  // script.aculo.us is freely distributable under the terms of an MIT-style license.  // For details, see the script.aculo.us web site: http://script.aculo.us/ @@ -32,7 +33,7 @@ var Droppables = {          options._containers.push($(containment));        }      } -     +      if(options.accept) options.accept = [options.accept].flatten();      Element.makePositioned(element); // fix IE @@ -40,34 +41,34 @@ var Droppables = {      this.drops.push(options);    }, -   +    findDeepestChild: function(drops) {      deepest = drops[0]; -       +      for (i = 1; i < drops.length; ++i)        if (Element.isParent(drops[i].element, deepest.element))          deepest = drops[i]; -     +      return deepest;    },    isContained: function(element, drop) {      var containmentNode;      if(drop.tree) { -      containmentNode = element.treeNode;  +      containmentNode = element.treeNode;      } else {        containmentNode = element.parentNode;      }      return drop._containers.detect(function(c) { return containmentNode == c });    }, -   +    isAffected: function(point, element, drop) {      return (        (drop.element!=element) &&        ((!drop._containers) ||          this.isContained(element, drop)) &&        ((!drop.accept) || -        (Element.classNames(element).detect(  +        (Element.classNames(element).detect(            function(v) { return drop.accept.include(v) } ) )) &&        Position.within(drop.element, point[0], point[1]) );    }, @@ -87,12 +88,12 @@ var Droppables = {    show: function(point, element) {      if(!this.drops.length) return;      var drop, affected = []; -     +      this.drops.each( function(drop) {        if(Droppables.isAffected(point, element, drop))          affected.push(drop);      }); -         +      if(affected.length>0)        drop = Droppables.findDeepestChild(affected); @@ -101,7 +102,7 @@ var Droppables = {        Position.within(drop.element, point[0], point[1]);        if(drop.onHover)          drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element)); -       +        if (drop != this.last_active) Droppables.activate(drop);      }    }, @@ -112,8 +113,8 @@ var Droppables = {      if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))        if (this.last_active.onDrop) { -        this.last_active.onDrop(element, this.last_active.element, event);  -        return true;  +        this.last_active.onDrop(element, this.last_active.element, event); +        return true;        }    }, @@ -121,25 +122,25 @@ var Droppables = {      if(this.last_active)        this.deactivate(this.last_active);    } -} +};  var Draggables = {    drags: [],    observers: [], -   +    register: function(draggable) {      if(this.drags.length == 0) {        this.eventMouseUp   = this.endDrag.bindAsEventListener(this);        this.eventMouseMove = this.updateDrag.bindAsEventListener(this);        this.eventKeypress  = this.keyPress.bindAsEventListener(this); -       +        Event.observe(document, "mouseup", this.eventMouseUp);        Event.observe(document, "mousemove", this.eventMouseMove);        Event.observe(document, "keypress", this.eventKeypress);      }      this.drags.push(draggable);    }, -   +    unregister: function(draggable) {      this.drags = this.drags.reject(function(d) { return d==draggable });      if(this.drags.length == 0) { @@ -148,24 +149,24 @@ var Draggables = {        Event.stopObserving(document, "keypress", this.eventKeypress);      }    }, -   +    activate: function(draggable) { -    if(draggable.options.delay) {  -      this._timeout = setTimeout(function() {  -        Draggables._timeout = null;  -        window.focus();  -        Draggables.activeDraggable = draggable;  -      }.bind(this), draggable.options.delay);  +    if(draggable.options.delay) { +      this._timeout = setTimeout(function() { +        Draggables._timeout = null; +        window.focus(); +        Draggables.activeDraggable = draggable; +      }.bind(this), draggable.options.delay);      } else {        window.focus(); // allows keypress events if window isn't currently focused, fails for Safari        this.activeDraggable = draggable;      }    }, -   +    deactivate: function() {      this.activeDraggable = null;    }, -   +    updateDrag: function(event) {      if(!this.activeDraggable) return;      var pointer = [Event.pointerX(event), Event.pointerY(event)]; @@ -173,36 +174,36 @@ var Draggables = {      // the same coordinates, prevent needless redrawing (moz bug?)      if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;      this._lastPointer = pointer; -     +      this.activeDraggable.updateDrag(event, pointer);    }, -   +    endDrag: function(event) { -    if(this._timeout) {  -      clearTimeout(this._timeout);  -      this._timeout = null;  +    if(this._timeout) { +      clearTimeout(this._timeout); +      this._timeout = null;      }      if(!this.activeDraggable) return;      this._lastPointer = null;      this.activeDraggable.endDrag(event);      this.activeDraggable = null;    }, -   +    keyPress: function(event) {      if(this.activeDraggable)        this.activeDraggable.keyPress(event);    }, -   +    addObserver: function(observer) {      this.observers.push(observer);      this._cacheObserverCallbacks();    }, -   +    removeObserver: function(element) {  // element instead of observer fixes mem leaks      this.observers = this.observers.reject( function(o) { return o.element==element });      this._cacheObserverCallbacks();    }, -   +    notify: function(eventName, draggable, event) {  // 'onStart', 'onEnd', 'onDrag'      if(this[eventName+'Count'] > 0)        this.observers.each( function(o) { @@ -210,7 +211,7 @@ var Draggables = {        });      if(draggable.options[eventName]) draggable.options[eventName](draggable, event);    }, -   +    _cacheObserverCallbacks: function() {      ['onStart','onEnd','onDrag'].each( function(eventName) {        Draggables[eventName+'Count'] = Draggables.observers.select( @@ -218,7 +219,7 @@ var Draggables = {        ).length;      });    } -} +};  /*--------------------------------------------------------------------------*/ @@ -234,12 +235,12 @@ var Draggable = Class.create({        },        endeffect: function(element) {          var toOpacity = Object.isNumber(element._opacity) ? element._opacity : 1.0; -        new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,  +        new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,            queue: {scope:'_draggable', position:'end'}, -          afterFinish: function(){  -            Draggable._dragging[element] = false  +          afterFinish: function(){ +            Draggable._dragging[element] = false            } -        });  +        });        },        zindex: 1000,        revert: false, @@ -250,57 +251,57 @@ var Draggable = Class.create({        snap: false,  // false, or xy or [x,y] or function(x,y){ return [x,y] }        delay: 0      }; -     +      if(!arguments[1] || Object.isUndefined(arguments[1].endeffect))        Object.extend(defaults, {          starteffect: function(element) {            element._opacity = Element.getOpacity(element);            Draggable._dragging[element] = true; -          new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7});  +          new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7});          }        }); -     +      var options = Object.extend(defaults, arguments[1] || { });      this.element = $(element); -     +      if(options.handle && Object.isString(options.handle))        this.handle = this.element.down('.'+options.handle, 0); -     +      if(!this.handle) this.handle = $(options.handle);      if(!this.handle) this.handle = this.element; -     +      if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {        options.scroll = $(options.scroll);        this._isScrollChild = Element.childOf(this.element, options.scroll);      } -    Element.makePositioned(this.element); // fix IE     +    Element.makePositioned(this.element); // fix IE      this.options  = options; -    this.dragging = false;    +    this.dragging = false;      this.eventMouseDown = this.initDrag.bindAsEventListener(this);      Event.observe(this.handle, "mousedown", this.eventMouseDown); -     +      Draggables.register(this);    }, -   +    destroy: function() {      Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);      Draggables.unregister(this);    }, -   +    currentDelta: function() {      return([        parseInt(Element.getStyle(this.element,'left') || '0'),        parseInt(Element.getStyle(this.element,'top') || '0')]);    }, -   +    initDrag: function(event) {      if(!Object.isUndefined(Draggable._dragging[this.element]) &&        Draggable._dragging[this.element]) return; -    if(Event.isLeftClick(event)) {     +    if(Event.isLeftClick(event)) {        // abort on form elements, fixes a Firefox issue        var src = Event.element(event);        if((tag_name = src.tagName.toUpperCase()) && ( @@ -309,34 +310,34 @@ var Draggable = Class.create({          tag_name=='OPTION' ||          tag_name=='BUTTON' ||          tag_name=='TEXTAREA')) return; -         +        var pointer = [Event.pointerX(event), Event.pointerY(event)]; -      var pos     = Position.cumulativeOffset(this.element); +      var pos     = this.element.cumulativeOffset();        this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) }); -       +        Draggables.activate(this);        Event.stop(event);      }    }, -   +    startDrag: function(event) {      this.dragging = true;      if(!this.delta)        this.delta = this.currentDelta(); -     +      if(this.options.zindex) {        this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);        this.element.style.zIndex = this.options.zindex;      } -     +      if(this.options.ghosting) {        this._clone = this.element.cloneNode(true); -      this.element._originallyAbsolute = (this.element.getStyle('position') == 'absolute'); -      if (!this.element._originallyAbsolute) +      this._originallyAbsolute = (this.element.getStyle('position') == 'absolute'); +      if (!this._originallyAbsolute)          Position.absolutize(this.element);        this.element.parentNode.insertBefore(this._clone, this.element);      } -     +      if(this.options.scroll) {        if (this.options.scroll == window) {          var where = this._getWindowScroll(this.options.scroll); @@ -347,28 +348,28 @@ var Draggable = Class.create({          this.originalScrollTop = this.options.scroll.scrollTop;        }      } -     +      Draggables.notify('onStart', this, event); -         +      if(this.options.starteffect) this.options.starteffect(this.element);    }, -   +    updateDrag: function(event, pointer) {      if(!this.dragging) this.startDrag(event); -     +      if(!this.options.quiet){        Position.prepare();        Droppables.show(pointer, this.element);      } -     +      Draggables.notify('onDrag', this, event); -     +      this.draw(pointer);      if(this.options.change) this.options.change(this); -     +      if(this.options.scroll) {        this.stopScrolling(); -       +        var p;        if (this.options.scroll == window) {          with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; } @@ -386,16 +387,16 @@ var Draggable = Class.create({        if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);        this.startScrolling(speed);      } -     +      // fix AppleWebKit rendering      if(Prototype.Browser.WebKit) window.scrollBy(0,0); -     +      Event.stop(event);    }, -   +    finishDrag: function(event, success) {      this.dragging = false; -     +      if(this.options.quiet){        Position.prepare();        var pointer = [Event.pointerX(event), Event.pointerY(event)]; @@ -403,24 +404,24 @@ var Draggable = Class.create({      }      if(this.options.ghosting) { -      if (!this.element._originallyAbsolute) +      if (!this._originallyAbsolute)          Position.relativize(this.element); -      delete this.element._originallyAbsolute; +      delete this._originallyAbsolute;        Element.remove(this._clone);        this._clone = null;      } -    var dropped = false;  -    if(success) {  -      dropped = Droppables.fire(event, this.element);  -      if (!dropped) dropped = false;  +    var dropped = false; +    if(success) { +      dropped = Droppables.fire(event, this.element); +      if (!dropped) dropped = false;      }      if(dropped && this.options.onDropped) this.options.onDropped(this.element);      Draggables.notify('onEnd', this, event);      var revert = this.options.revert;      if(revert && Object.isFunction(revert)) revert = revert(this.element); -     +      var d = this.currentDelta();      if(revert && this.options.reverteffect) {        if (dropped == 0 || revert != 'failure') @@ -433,67 +434,67 @@ var Draggable = Class.create({      if(this.options.zindex)        this.element.style.zIndex = this.originalZ; -    if(this.options.endeffect)  +    if(this.options.endeffect)        this.options.endeffect(this.element); -       +      Draggables.deactivate(this);      Droppables.reset();    }, -   +    keyPress: function(event) {      if(event.keyCode!=Event.KEY_ESC) return;      this.finishDrag(event, false);      Event.stop(event);    }, -   +    endDrag: function(event) {      if(!this.dragging) return;      this.stopScrolling();      this.finishDrag(event, true);      Event.stop(event);    }, -   +    draw: function(point) { -    var pos = Position.cumulativeOffset(this.element); +    var pos = this.element.cumulativeOffset();      if(this.options.ghosting) {        var r   = Position.realOffset(this.element);        pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;      } -     +      var d = this.currentDelta();      pos[0] -= d[0]; pos[1] -= d[1]; -     +      if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {        pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;        pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;      } -     -    var p = [0,1].map(function(i){  -      return (point[i]-pos[i]-this.offset[i])  + +    var p = [0,1].map(function(i){ +      return (point[i]-pos[i]-this.offset[i])      }.bind(this)); -     +      if(this.options.snap) {        if(Object.isFunction(this.options.snap)) {          p = this.options.snap(p[0],p[1],this);        } else {        if(Object.isArray(this.options.snap)) {          p = p.map( function(v, i) { -          return (v/this.options.snap[i]).round()*this.options.snap[i] }.bind(this)) +          return (v/this.options.snap[i]).round()*this.options.snap[i] }.bind(this));        } else {          p = p.map( function(v) { -          return (v/this.options.snap).round()*this.options.snap }.bind(this)) +          return (v/this.options.snap).round()*this.options.snap }.bind(this));        }      }} -     +      var style = this.element.style;      if((!this.options.constraint) || (this.options.constraint=='horizontal'))        style.left = p[0] + "px";      if((!this.options.constraint) || (this.options.constraint=='vertical'))        style.top  = p[1] + "px"; -     +      if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering    }, -   +    stopScrolling: function() {      if(this.scrollInterval) {        clearInterval(this.scrollInterval); @@ -501,14 +502,14 @@ var Draggable = Class.create({        Draggables._lastScrollPointer = null;      }    }, -   +    startScrolling: function(speed) {      if(!(speed[0] || speed[1])) return;      this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];      this.lastScrolled = new Date();      this.scrollInterval = setInterval(this.scroll.bind(this), 10);    }, -   +    scroll: function() {      var current = new Date();      var delta = current - this.lastScrolled; @@ -524,7 +525,7 @@ var Draggable = Class.create({        this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;        this.options.scroll.scrollTop  += this.scrollSpeed[1] * delta / 1000;      } -     +      Position.prepare();      Droppables.show(Draggables._lastPointer, this.element);      Draggables.notify('onDrag', this); @@ -538,10 +539,10 @@ var Draggable = Class.create({          Draggables._lastScrollPointer[1] = 0;        this.draw(Draggables._lastScrollPointer);      } -     +      if(this.options.change) this.options.change(this);    }, -   +    _getWindowScroll: function(w) {      var T, L, W, H;      with (w.document) { @@ -560,7 +561,7 @@ var Draggable = Class.create({          H = documentElement.clientHeight;        } else {          W = body.offsetWidth; -        H = body.offsetHeight +        H = body.offsetHeight;        }      }      return { top: T, left: L, width: W, height: H }; @@ -577,11 +578,11 @@ var SortableObserver = Class.create({      this.observer  = observer;      this.lastValue = Sortable.serialize(this.element);    }, -   +    onStart: function() {      this.lastValue = Sortable.serialize(this.element);    }, -   +    onEnd: function() {      Sortable.unmark();      if(this.lastValue != Sortable.serialize(this.element)) @@ -591,11 +592,11 @@ var SortableObserver = Class.create({  var Sortable = {    SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/, -   +    sortables: { }, -   +    _findRootElement: function(element) { -    while (element.tagName.toUpperCase() != "BODY") {   +    while (element.tagName.toUpperCase() != "BODY") {        if(element.id && Sortable.sortables[element.id]) return element;        element = element.parentNode;      } @@ -606,22 +607,23 @@ var Sortable = {      if(!element) return;      return Sortable.sortables[element.id];    }, -   +    destroy: function(element){ -    var s = Sortable.options(element); -     +    element = $(element); +    var s = Sortable.sortables[element.id]; +      if(s) {        Draggables.removeObserver(s.element);        s.droppables.each(function(d){ Droppables.remove(d) });        s.draggables.invoke('destroy'); -       +        delete Sortable.sortables[s.element.id];      }    },    create: function(element) {      element = $(element); -    var options = Object.extend({  +    var options = Object.extend({        element:     element,        tag:         'li',       // assumes li children, override with tag: 'tagname'        dropOnEmpty: false, @@ -635,17 +637,17 @@ var Sortable = {        delay:       0,        hoverclass:  null,        ghosting:    false, -      quiet:       false,  +      quiet:       false,        scroll:      false,        scrollSensitivity: 20,        scrollSpeed: 15,        format:      this.SERIALIZE_RULE, -       -      // these take arrays of elements or ids and can be  + +      // these take arrays of elements or ids and can be        // used for better initialization performance        elements:    false,        handles:     false, -       +        onChange:    Prototype.emptyFunction,        onUpdate:    Prototype.emptyFunction      }, arguments[1] || { }); @@ -682,24 +684,24 @@ var Sortable = {      if(options.zindex)        options_for_draggable.zindex = options.zindex; -    // build options for the droppables   +    // build options for the droppables      var options_for_droppable = {        overlap:     options.overlap,        containment: options.containment,        tree:        options.tree,        hoverclass:  options.hoverclass,        onHover:     Sortable.onHover -    } -     +    }; +      var options_for_tree = {        onHover:      Sortable.onEmptyHover,        overlap:      options.overlap,        containment:  options.containment,        hoverclass:   options.hoverclass -    } +    };      // fix for gecko engine -    Element.cleanWhitespace(element);  +    Element.cleanWhitespace(element);      options.draggables = [];      options.droppables = []; @@ -712,14 +714,14 @@ var Sortable = {      (options.elements || this.findElements(element, options) || []).each( function(e,i) {        var handle = options.handles ? $(options.handles[i]) : -        (options.handle ? $(e).select('.' + options.handle)[0] : e);  +        (options.handle ? $(e).select('.' + options.handle)[0] : e);        options.draggables.push(          new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));        Droppables.add(e, options_for_droppable);        if(options.tree) e.treeNode = element; -      options.droppables.push(e);       +      options.droppables.push(e);      }); -     +      if(options.tree) {        (Sortable.findTreeElements(element, options) || []).each( function(e) {          Droppables.add(e, options_for_tree); @@ -729,7 +731,7 @@ var Sortable = {      }      // keep reference -    this.sortables[element.id] = options; +    this.sortables[element.identify()] = options;      // for onupdate      Draggables.addObserver(new SortableObserver(element, options.onUpdate)); @@ -741,7 +743,7 @@ var Sortable = {      return Element.findChildren(        element, options.only, options.tree ? true : false, options.tag);    }, -   +    findTreeElements: function(element, options) {      return Element.findChildren(        element, options.only, options.tree ? true : false, options.treeTag); @@ -758,7 +760,7 @@ var Sortable = {          var oldParentNode = element.parentNode;          element.style.visibility = "hidden"; // fix gecko rendering          dropon.parentNode.insertBefore(element, dropon); -        if(dropon.parentNode!=oldParentNode)  +        if(dropon.parentNode!=oldParentNode)            Sortable.options(oldParentNode).onChange(element);          Sortable.options(dropon.parentNode).onChange(element);        } @@ -769,26 +771,26 @@ var Sortable = {          var oldParentNode = element.parentNode;          element.style.visibility = "hidden"; // fix gecko rendering          dropon.parentNode.insertBefore(element, nextElement); -        if(dropon.parentNode!=oldParentNode)  +        if(dropon.parentNode!=oldParentNode)            Sortable.options(oldParentNode).onChange(element);          Sortable.options(dropon.parentNode).onChange(element);        }      }    }, -   +    onEmptyHover: function(element, dropon, overlap) {      var oldParentNode = element.parentNode;      var droponOptions = Sortable.options(dropon); -         +      if(!Element.isParent(dropon, element)) {        var index; -       +        var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only});        var child = null; -             +        if(children) {          var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap); -         +          for (index = 0; index < children.length; index += 1) {            if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) {              offset -= Element.offsetSize (children[index], droponOptions.overlap); @@ -801,9 +803,9 @@ var Sortable = {            }          }        } -       +        dropon.insertBefore(element, child); -       +        Sortable.options(oldParentNode).onChange(element);        droponOptions.onChange(element);      } @@ -816,34 +818,34 @@ var Sortable = {    mark: function(dropon, position) {      // mark on ghosting only      var sortable = Sortable.options(dropon.parentNode); -    if(sortable && !sortable.ghosting) return;  +    if(sortable && !sortable.ghosting) return;      if(!Sortable._marker) { -      Sortable._marker =  +      Sortable._marker =          ($('dropmarker') || Element.extend(document.createElement('DIV'))).            hide().addClassName('dropmarker').setStyle({position:'absolute'});        document.getElementsByTagName("body").item(0).appendChild(Sortable._marker); -    }     -    var offsets = Position.cumulativeOffset(dropon); +    } +    var offsets = dropon.cumulativeOffset();      Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'}); -     +      if(position=='after') -      if(sortable.overlap == 'horizontal')  +      if(sortable.overlap == 'horizontal')          Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'});        else          Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'}); -     +      Sortable._marker.show();    }, -   +    _tree: function(element, options, parent) {      var children = Sortable.findElements(element, options) || []; -   +      for (var i = 0; i < children.length; ++i) {        var match = children[i].id.match(options.format);        if (!match) continue; -       +        var child = {          id: encodeURIComponent(match ? match[1] : null),          element: element, @@ -851,16 +853,16 @@ var Sortable = {          children: [],          position: parent.children.length,          container: $(children[i]).down(options.treeTag) -      } -       +      }; +        /* Get the element containing the children and recurse over it */        if (child.container) -        this._tree(child.container, options, child) -       +        this._tree(child.container, options, child); +        parent.children.push (child);      } -    return parent;  +    return parent;    },    tree: function(element) { @@ -873,15 +875,15 @@ var Sortable = {        name: element.id,        format: sortableOptions.format      }, arguments[1] || { }); -     +      var root = {        id: null,        parent: null,        children: [],        container: element,        position: 0 -    } -     +    }; +      return Sortable._tree(element, options, root);    }, @@ -897,7 +899,7 @@ var Sortable = {    sequence: function(element) {      element = $(element);      var options = Object.extend(this.options(element), arguments[1] || { }); -     +      return $(this.findElements(element, options) || []).map( function(item) {        return item.id.match(options.format) ? item.id.match(options.format)[1] : '';      }); @@ -906,14 +908,14 @@ var Sortable = {    setSequence: function(element, new_sequence) {      element = $(element);      var options = Object.extend(this.options(element), arguments[2] || { }); -     +      var nodeMap = { };      this.findElements(element, options).each( function(n) {          if (n.id.match(options.format))              nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];          n.parentNode.removeChild(n);      }); -    +      new_sequence.each(function(ident) {        var n = nodeMap[ident];        if (n) { @@ -922,16 +924,16 @@ var Sortable = {        }      });    }, -   +    serialize: function(element) {      element = $(element);      var options = Object.extend(Sortable.options(element), arguments[1] || { });      var name = encodeURIComponent(        (arguments[1] && arguments[1].name) ? arguments[1].name : element.id); -     +      if (options.tree) {        return Sortable.tree(element, arguments[1]).children.map( function (item) { -        return [name + Sortable._constructIndex(item) + "[id]=" +  +        return [name + Sortable._constructIndex(item) + "[id]=" +                  encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));        }).flatten().join('&');      } else { @@ -940,16 +942,16 @@ var Sortable = {        }).join('&');      }    } -} +};  // Returns true if child is contained within element  Element.isParent = function(child, element) {    if (!child.parentNode || child == element) return false;    if (child.parentNode == element) return true;    return Element.isParent(child.parentNode, element); -} +}; -Element.findChildren = function(element, only, recursive, tagName) {    +Element.findChildren = function(element, only, recursive, tagName) {    if(!element.hasChildNodes()) return null;    tagName = tagName.toUpperCase();    if(only) only = [only].flatten(); @@ -965,8 +967,8 @@ Element.findChildren = function(element, only, recursive, tagName) {    });    return (elements.length>0 ? elements.flatten() : []); -} +};  Element.offsetSize = function (element, type) {    return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')]; -} +};
\ No newline at end of file diff --git a/public/javascripts/effects.js b/public/javascripts/effects.js index f030b5dbe..c81e6c7d5 100644 --- a/public/javascripts/effects.js +++ b/public/javascripts/effects.js @@ -1,48 +1,50 @@ -// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// script.aculo.us effects.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009 + +// Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)  // Contributors:  //  Justin Palmer (http://encytemedia.com/)  //  Mark Pilgrim (http://diveintomark.org/)  //  Martin Bialasinki -//  +//  // script.aculo.us is freely distributable under the terms of an MIT-style license. -// For details, see the script.aculo.us web site: http://script.aculo.us/  +// For details, see the script.aculo.us web site: http://script.aculo.us/ -// converts rgb() and #xxx to #xxxxxx format,   -// returns self (or first argument) if not convertable   -String.prototype.parseColor = function() {   +// converts rgb() and #xxx to #xxxxxx format, +// returns self (or first argument) if not convertable +String.prototype.parseColor = function() {    var color = '#'; -  if (this.slice(0,4) == 'rgb(') {   -    var cols = this.slice(4,this.length-1).split(',');   -    var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);   -  } else {   -    if (this.slice(0,1) == '#') {   -      if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();   -      if (this.length==7) color = this.toLowerCase();   -    }   -  }   -  return (color.length==7 ? color : (arguments[0] || this));   +  if (this.slice(0,4) == 'rgb(') { +    var cols = this.slice(4,this.length-1).split(','); +    var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3); +  } else { +    if (this.slice(0,1) == '#') { +      if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase(); +      if (this.length==7) color = this.toLowerCase(); +    } +  } +  return (color.length==7 ? color : (arguments[0] || this));  };  /*--------------------------------------------------------------------------*/ -Element.collectTextNodes = function(element) {   +Element.collectTextNodes = function(element) {    return $A($(element).childNodes).collect( function(node) { -    return (node.nodeType==3 ? node.nodeValue :  +    return (node.nodeType==3 ? node.nodeValue :        (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));    }).flatten().join('');  }; -Element.collectTextNodesIgnoreClass = function(element, className) {   +Element.collectTextNodesIgnoreClass = function(element, className) {    return $A($(element).childNodes).collect( function(node) { -    return (node.nodeType==3 ? node.nodeValue :  -      ((node.hasChildNodes() && !Element.hasClassName(node,className)) ?  +    return (node.nodeType==3 ? node.nodeValue : +      ((node.hasChildNodes() && !Element.hasClassName(node,className)) ?          Element.collectTextNodesIgnoreClass(node, className) : ''));    }).flatten().join('');  };  Element.setContentZoom = function(element, percent) { -  element = $(element);   -  element.setStyle({fontSize: (percent/100) + 'em'});    +  element = $(element); +  element.setStyle({fontSize: (percent/100) + 'em'});    if (Prototype.Browser.WebKit) window.scrollBy(0,0);    return element;  }; @@ -70,28 +72,23 @@ var Effect = {    Transitions: {      linear: Prototype.K,      sinoidal: function(pos) { -      return (-Math.cos(pos*Math.PI)/2) + 0.5; +      return (-Math.cos(pos*Math.PI)/2) + .5;      },      reverse: function(pos) {        return 1-pos;      },      flicker: function(pos) { -      var pos = ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4; +      var pos = ((-Math.cos(pos*Math.PI)/4) + .75) + Math.random()/4;        return pos > 1 ? 1 : pos;      },      wobble: function(pos) { -      return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5; +      return (-Math.cos(pos*Math.PI*(9*pos))/2) + .5;      }, -    pulse: function(pos, pulses) {  -      pulses = pulses || 5;  -      return ( -        ((pos % (1/pulses)) * pulses).round() == 0 ?  -              ((pos * pulses * 2) - (pos * pulses * 2).floor()) :  -          1 - ((pos * pulses * 2) - (pos * pulses * 2).floor()) -        ); +    pulse: function(pos, pulses) { +      return (-Math.cos((pos*((pulses||5)-.5)*2)*Math.PI)/2) + .5;      }, -    spring: function(pos) {  -      return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));  +    spring: function(pos) { +      return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));      },      none: function(pos) {        return 0; @@ -112,14 +109,14 @@ var Effect = {    tagifyText: function(element) {      var tagifyStyle = 'position:relative';      if (Prototype.Browser.IE) tagifyStyle += ';zoom:1'; -     +      element = $(element);      $A(element.childNodes).each( function(child) {        if (child.nodeType==3) {          child.nodeValue.toArray().each( function(character) {            element.insertBefore(              new Element('span', {style: tagifyStyle}).update( -              character == ' ' ? String.fromCharCode(160) : character),  +              character == ' ' ? String.fromCharCode(160) : character),                child);          });          Element.remove(child); @@ -128,13 +125,13 @@ var Effect = {    },    multiple: function(element, effect) {      var elements; -    if (((typeof element == 'object') ||  -        Object.isFunction(element)) &&  +    if (((typeof element == 'object') || +        Object.isFunction(element)) &&         (element.length))        elements = element;      else        elements = $(element).childNodes; -       +      var options = Object.extend({        speed: 0.1,        delay: 0.0 @@ -150,14 +147,13 @@ var Effect = {      'blind':  ['BlindDown','BlindUp'],      'appear': ['Appear','Fade']    }, -  toggle: function(element, effect) { +  toggle: function(element, effect, options) {      element = $(element); -    effect = (effect || 'appear').toLowerCase(); -    var options = Object.extend({ +    effect  = (effect || 'appear').toLowerCase(); + +    return Effect[ Effect.PAIRS[ effect ][ element.visible() ? 1 : 0 ] ](element, Object.extend({        queue: { position:'end', scope:(element.id || 'global'), limit: 1 } -    }, arguments[2] || { }); -    Effect[element.visible() ?  -      Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options); +    }, options || {}));    }  }; @@ -168,20 +164,20 @@ Effect.DefaultOptions.transition = Effect.Transitions.sinoidal;  Effect.ScopedQueue = Class.create(Enumerable, {    initialize: function() {      this.effects  = []; -    this.interval = null;     +    this.interval = null;    },    _each: function(iterator) {      this.effects._each(iterator);    },    add: function(effect) {      var timestamp = new Date().getTime(); -     -    var position = Object.isString(effect.options.queue) ?  + +    var position = Object.isString(effect.options.queue) ?        effect.options.queue : effect.options.queue.position; -     +      switch(position) {        case 'front': -        // move unstarted effects after this effect   +        // move unstarted effects after this effect          this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {              e.startOn  += effect.finishOn;              e.finishOn += effect.finishOn; @@ -195,13 +191,13 @@ Effect.ScopedQueue = Class.create(Enumerable, {          timestamp = this.effects.pluck('finishOn').max() || timestamp;          break;      } -     +      effect.startOn  += timestamp;      effect.finishOn += timestamp;      if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))        this.effects.push(effect); -     +      if (!this.interval)        this.interval = setInterval(this.loop.bind(this), 15);    }, @@ -214,7 +210,7 @@ Effect.ScopedQueue = Class.create(Enumerable, {    },    loop: function() {      var timePos = new Date().getTime(); -    for(var i=0, len=this.effects.length;i<len;i++)  +    for(var i=0, len=this.effects.length;i<len;i++)        this.effects[i] && this.effects[i].loop(timePos);    }  }); @@ -223,7 +219,7 @@ Effect.Queues = {    instances: $H(),    get: function(queueName) {      if (!Object.isString(queueName)) return queueName; -     +      return this.instances.get(queueName) ||        this.instances.set(queueName, new Effect.ScopedQueue());    } @@ -233,12 +229,6 @@ Effect.Queue = Effect.Queues.get('global');  Effect.Base = Class.create({    position: null,    start: function(options) { -    function codeForEvent(options,eventName){ -      return ( -        (options[eventName+'Internal'] ? 'this.options.'+eventName+'Internal(this);' : '') + -        (options[eventName] ? 'this.options.'+eventName+'(this);' : '') -      ); -    }      if (options && options.transition === false) options.transition = Effect.Transitions.linear;      this.options      = Object.extend(Object.extend({ },Effect.DefaultOptions), options || { });      this.currentFrame = 0; @@ -248,23 +238,35 @@ Effect.Base = Class.create({      this.fromToDelta  = this.options.to-this.options.from;      this.totalTime    = this.finishOn-this.startOn;      this.totalFrames  = this.options.fps*this.options.duration; -     -    eval('this.render = function(pos){ '+ -      'if (this.state=="idle"){this.state="running";'+ -      codeForEvent(this.options,'beforeSetup')+ -      (this.setup ? 'this.setup();':'')+  -      codeForEvent(this.options,'afterSetup')+ -      '};if (this.state=="running"){'+ -      'pos=this.options.transition(pos)*'+this.fromToDelta+'+'+this.options.from+';'+ -      'this.position=pos;'+ -      codeForEvent(this.options,'beforeUpdate')+ -      (this.update ? 'this.update(pos);':'')+ -      codeForEvent(this.options,'afterUpdate')+ -      '}}'); -     + +    this.render = (function() { +      function dispatch(effect, eventName) { +        if (effect.options[eventName + 'Internal']) +          effect.options[eventName + 'Internal'](effect); +        if (effect.options[eventName]) +          effect.options[eventName](effect); +      } + +      return function(pos) { +        if (this.state === "idle") { +          this.state = "running"; +          dispatch(this, 'beforeSetup'); +          if (this.setup) this.setup(); +          dispatch(this, 'afterSetup'); +        } +        if (this.state === "running") { +          pos = (this.options.transition(pos) * this.fromToDelta) + this.options.from; +          this.position = pos; +          dispatch(this, 'beforeUpdate'); +          if (this.update) this.update(pos); +          dispatch(this, 'afterUpdate'); +        } +      }; +    })(); +      this.event('beforeStart');      if (!this.options.sync) -      Effect.Queues.get(Object.isString(this.options.queue) ?  +      Effect.Queues.get(Object.isString(this.options.queue) ?          'global' : this.options.queue.scope).add(this);    },    loop: function(timePos) { @@ -273,9 +275,9 @@ Effect.Base = Class.create({          this.render(1.0);          this.cancel();          this.event('beforeFinish'); -        if (this.finish) this.finish();  +        if (this.finish) this.finish();          this.event('afterFinish'); -        return;   +        return;        }        var pos   = (timePos - this.startOn) / this.totalTime,            frame = (pos * this.totalFrames).round(); @@ -287,7 +289,7 @@ Effect.Base = Class.create({    },    cancel: function() {      if (!this.options.sync) -      Effect.Queues.get(Object.isString(this.options.queue) ?  +      Effect.Queues.get(Object.isString(this.options.queue) ?          'global' : this.options.queue.scope).remove(this);      this.state = 'finished';    }, @@ -325,10 +327,10 @@ Effect.Parallel = Class.create(Effect.Base, {  Effect.Tween = Class.create(Effect.Base, {    initialize: function(object, from, to) {      object = Object.isString(object) ? $(object) : object; -    var args = $A(arguments), method = args.last(),  +    var args = $A(arguments), method = args.last(),        options = args.length == 5 ? args[3] : null;      this.method = Object.isFunction(method) ? method.bind(object) : -      Object.isFunction(object[method]) ? object[method].bind(object) :  +      Object.isFunction(object[method]) ? object[method].bind(object) :        function(value) { object[method] = value };      this.start(Object.extend({ from: from, to: to }, options || { }));    }, @@ -392,7 +394,7 @@ Effect.Move = Class.create(Effect.Base, {  // for backwards compatibility  Effect.MoveBy = function(element, toTop, toLeft) { -  return new Effect.Move(element,  +  return new Effect.Move(element,      Object.extend({ x: toLeft, y: toTop }, arguments[3] || { }));  }; @@ -414,15 +416,15 @@ Effect.Scale = Class.create(Effect.Base, {    setup: function() {      this.restoreAfterFinish = this.options.restoreAfterFinish || false;      this.elementPositioning = this.element.getStyle('position'); -     +      this.originalStyle = { };      ['top','left','width','height','fontSize'].each( function(k) {        this.originalStyle[k] = this.element.style[k];      }.bind(this)); -       +      this.originalTop  = this.element.offsetTop;      this.originalLeft = this.element.offsetLeft; -     +      var fontSize = this.element.getStyle('font-size') || '100%';      ['em','px','%','pt'].each( function(fontSizeType) {        if (fontSize.indexOf(fontSizeType)>0) { @@ -430,9 +432,9 @@ Effect.Scale = Class.create(Effect.Base, {          this.fontSizeType = fontSizeType;        }      }.bind(this)); -     +      this.factor = (this.options.scaleTo - this.options.scaleFrom)/100; -     +      this.dims = null;      if (this.options.scaleMode=='box')        this.dims = [this.element.offsetHeight, this.element.offsetWidth]; @@ -507,17 +509,16 @@ Effect.Highlight = Class.create(Effect.Base, {  Effect.ScrollTo = function(element) {    var options = arguments[1] || { }, -    scrollOffsets = document.viewport.getScrollOffsets(), -    elementOffsets = $(element).cumulativeOffset(), -    max = (window.height || document.body.scrollHeight) - document.viewport.getHeight();   +  scrollOffsets = document.viewport.getScrollOffsets(), +  elementOffsets = $(element).cumulativeOffset();    if (options.offset) elementOffsets[1] += options.offset;    return new Effect.Tween(null,      scrollOffsets.top, -    elementOffsets[1] > max ? max : elementOffsets[1], +    elementOffsets[1],      options, -    function(p){ scrollTo(scrollOffsets.left, p.round()) } +    function(p){ scrollTo(scrollOffsets.left, p.round()); }    );  }; @@ -529,9 +530,9 @@ Effect.Fade = function(element) {    var options = Object.extend({      from: element.getOpacity() || 1.0,      to:   0.0, -    afterFinishInternal: function(effect) {  +    afterFinishInternal: function(effect) {        if (effect.options.to!=0) return; -      effect.element.hide().setStyle({opacity: oldOpacity});  +      effect.element.hide().setStyle({opacity: oldOpacity});      }    }, arguments[1] || { });    return new Effect.Opacity(element,options); @@ -547,15 +548,15 @@ Effect.Appear = function(element) {      effect.element.forceRerendering();    },    beforeSetup: function(effect) { -    effect.element.setOpacity(effect.options.from).show();  +    effect.element.setOpacity(effect.options.from).show();    }}, arguments[1] || { });    return new Effect.Opacity(element,options);  };  Effect.Puff = function(element) {    element = $(element); -  var oldStyle = {  -    opacity: element.getInlineOpacity(),  +  var oldStyle = { +    opacity: element.getInlineOpacity(),      position: element.getStyle('position'),      top:  element.style.top,      left: element.style.left, @@ -563,12 +564,12 @@ Effect.Puff = function(element) {      height: element.style.height    };    return new Effect.Parallel( -   [ new Effect.Scale(element, 200,  -      { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),  -     new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],  -     Object.extend({ duration: 1.0,  +   [ new Effect.Scale(element, 200, +      { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), +     new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], +     Object.extend({ duration: 1.0,        beforeSetupInternal: function(effect) { -        Position.absolutize(effect.effects[0].element) +        Position.absolutize(effect.effects[0].element);        },        afterFinishInternal: function(effect) {           effect.effects[0].element.hide().setStyle(oldStyle); } @@ -580,12 +581,12 @@ Effect.BlindUp = function(element) {    element = $(element);    element.makeClipping();    return new Effect.Scale(element, 0, -    Object.extend({ scaleContent: false,  -      scaleX: false,  +    Object.extend({ scaleContent: false, +      scaleX: false,        restoreAfterFinish: true,        afterFinishInternal: function(effect) {          effect.element.hide().undoClipping(); -      }  +      }      }, arguments[1] || { })    );  }; @@ -593,15 +594,15 @@ Effect.BlindUp = function(element) {  Effect.BlindDown = function(element) {    element = $(element);    var elementDimensions = element.getDimensions(); -  return new Effect.Scale(element, 100, Object.extend({  -    scaleContent: false,  +  return new Effect.Scale(element, 100, Object.extend({ +    scaleContent: false,      scaleX: false,      scaleFrom: 0,      scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},      restoreAfterFinish: true,      afterSetup: function(effect) { -      effect.element.makeClipping().setStyle({height: '0px'}).show();  -    },   +      effect.element.makeClipping().setStyle({height: '0px'}).show(); +    },      afterFinishInternal: function(effect) {        effect.element.undoClipping();      } @@ -616,16 +617,16 @@ Effect.SwitchOff = function(element) {      from: 0,      transition: Effect.Transitions.flicker,      afterFinishInternal: function(effect) { -      new Effect.Scale(effect.element, 1, {  +      new Effect.Scale(effect.element, 1, {          duration: 0.3, scaleFromCenter: true,          scaleX: false, scaleContent: false, restoreAfterFinish: true, -        beforeSetup: function(effect) {  +        beforeSetup: function(effect) {            effect.element.makePositioned().makeClipping();          },          afterFinishInternal: function(effect) {            effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});          } -      }) +      });      }    }, arguments[1] || { }));  }; @@ -637,16 +638,16 @@ Effect.DropOut = function(element) {      left: element.getStyle('left'),      opacity: element.getInlineOpacity() };    return new Effect.Parallel( -    [ new Effect.Move(element, {x: 0, y: 100, sync: true }),  +    [ new Effect.Move(element, {x: 0, y: 100, sync: true }),        new Effect.Opacity(element, { sync: true, to: 0.0 }) ],      Object.extend(        { duration: 0.5,          beforeSetup: function(effect) { -          effect.effects[0].element.makePositioned();  +          effect.effects[0].element.makePositioned();          },          afterFinishInternal: function(effect) {            effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle); -        }  +        }        }, arguments[1] || { }));  }; @@ -674,7 +675,7 @@ Effect.Shake = function(element) {      new Effect.Move(effect.element,        { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) {          effect.element.undoPositioned().setStyle(oldStyle); -  }}) }}) }}) }}) }}) }}); +  }}); }}); }}); }}); }}); }});  };  Effect.SlideDown = function(element) { @@ -682,9 +683,9 @@ Effect.SlideDown = function(element) {    // SlideDown need to have the content of the element wrapped in a container element with fixed height!    var oldInnerBottom = element.down().getStyle('bottom');    var elementDimensions = element.getDimensions(); -  return new Effect.Scale(element, 100, Object.extend({  -    scaleContent: false,  -    scaleX: false,  +  return new Effect.Scale(element, 100, Object.extend({ +    scaleContent: false, +    scaleX: false,      scaleFrom: window.opera ? 0 : 1,      scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},      restoreAfterFinish: true, @@ -692,11 +693,11 @@ Effect.SlideDown = function(element) {        effect.element.makePositioned();        effect.element.down().makePositioned();        if (window.opera) effect.element.setStyle({top: ''}); -      effect.element.makeClipping().setStyle({height: '0px'}).show();  +      effect.element.makeClipping().setStyle({height: '0px'}).show();      },      afterUpdateInternal: function(effect) {        effect.element.down().setStyle({bottom: -        (effect.dims[0] - effect.element.clientHeight) + 'px' });  +        (effect.dims[0] - effect.element.clientHeight) + 'px' });      },      afterFinishInternal: function(effect) {        effect.element.undoClipping().undoPositioned(); @@ -710,8 +711,8 @@ Effect.SlideUp = function(element) {    var oldInnerBottom = element.down().getStyle('bottom');    var elementDimensions = element.getDimensions();    return new Effect.Scale(element, window.opera ? 0 : 1, -   Object.extend({ scaleContent: false,  -    scaleX: false,  +   Object.extend({ scaleContent: false, +    scaleX: false,      scaleMode: 'box',      scaleFrom: 100,      scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, @@ -721,7 +722,7 @@ Effect.SlideUp = function(element) {        effect.element.down().makePositioned();        if (window.opera) effect.element.setStyle({top: ''});        effect.element.makeClipping().show(); -    },   +    },      afterUpdateInternal: function(effect) {        effect.element.down().setStyle({bottom:          (effect.dims[0] - effect.element.clientHeight) + 'px' }); @@ -734,15 +735,15 @@ Effect.SlideUp = function(element) {    );  }; -// Bug in opera makes the TD containing this element expand for a instance after finish  +// Bug in opera makes the TD containing this element expand for a instance after finish  Effect.Squish = function(element) { -  return new Effect.Scale(element, window.opera ? 1 : 0, {  +  return new Effect.Scale(element, window.opera ? 1 : 0, {      restoreAfterFinish: true,      beforeSetup: function(effect) { -      effect.element.makeClipping();  -    },   +      effect.element.makeClipping(); +    },      afterFinishInternal: function(effect) { -      effect.element.hide().undoClipping();  +      effect.element.hide().undoClipping();      }    });  }; @@ -762,13 +763,13 @@ Effect.Grow = function(element) {      width: element.style.width,      opacity: element.getInlineOpacity() }; -  var dims = element.getDimensions();     +  var dims = element.getDimensions();    var initialMoveX, initialMoveY;    var moveX, moveY; -   +    switch (options.direction) {      case 'top-left': -      initialMoveX = initialMoveY = moveX = moveY = 0;  +      initialMoveX = initialMoveY = moveX = moveY = 0;        break;      case 'top-right':        initialMoveX = dims.width; @@ -793,11 +794,11 @@ Effect.Grow = function(element) {        moveY = -dims.height / 2;        break;    } -   +    return new Effect.Move(element, {      x: initialMoveX,      y: initialMoveY, -    duration: 0.01,  +    duration: 0.01,      beforeSetup: function(effect) {        effect.element.hide().makeClipping().makePositioned();      }, @@ -806,17 +807,17 @@ Effect.Grow = function(element) {          [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),            new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),            new Effect.Scale(effect.element, 100, { -            scaleMode: { originalHeight: dims.height, originalWidth: dims.width },  +            scaleMode: { originalHeight: dims.height, originalWidth: dims.width },              sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})          ], Object.extend({               beforeSetup: function(effect) { -               effect.effects[0].element.setStyle({height: '0px'}).show();  +               effect.effects[0].element.setStyle({height: '0px'}).show();               },               afterFinishInternal: function(effect) { -               effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle);  +               effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle);               }             }, options) -      ) +      );      }    });  }; @@ -838,7 +839,7 @@ Effect.Shrink = function(element) {    var dims = element.getDimensions();    var moveX, moveY; -   +    switch (options.direction) {      case 'top-left':        moveX = moveY = 0; @@ -855,19 +856,19 @@ Effect.Shrink = function(element) {        moveX = dims.width;        moveY = dims.height;        break; -    case 'center':   +    case 'center':        moveX = dims.width / 2;        moveY = dims.height / 2;        break;    } -   +    return new Effect.Parallel(      [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),        new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),        new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }) -    ], Object.extend({             +    ], Object.extend({           beforeStartInternal: function(effect) { -           effect.effects[0].element.makePositioned().makeClipping();  +           effect.effects[0].element.makePositioned().makeClipping();           },           afterFinishInternal: function(effect) {             effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); } @@ -877,12 +878,14 @@ Effect.Shrink = function(element) {  Effect.Pulsate = function(element) {    element = $(element); -  var options    = arguments[1] || { }; -  var oldOpacity = element.getInlineOpacity(); -  var transition = options.transition || Effect.Transitions.sinoidal; -  var reverser   = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) }; -  reverser.bind(transition); -  return new Effect.Opacity(element,  +  var options    = arguments[1] || { }, +    oldOpacity = element.getInlineOpacity(), +    transition = options.transition || Effect.Transitions.linear, +    reverser   = function(pos){ +      return 1 - transition((-Math.cos((pos*(options.pulses||5)*2)*Math.PI)/2) + .5); +    }; + +  return new Effect.Opacity(element,      Object.extend(Object.extend({  duration: 2.0, from: 0,        afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }      }, options), {transition: reverser})); @@ -896,12 +899,12 @@ Effect.Fold = function(element) {      width: element.style.width,      height: element.style.height };    element.makeClipping(); -  return new Effect.Scale(element, 5, Object.extend({    +  return new Effect.Scale(element, 5, Object.extend({      scaleContent: false,      scaleX: false,      afterFinishInternal: function(effect) { -    new Effect.Scale(element, 1, {  -      scaleContent: false,  +    new Effect.Scale(element, 1, { +      scaleContent: false,        scaleY: false,        afterFinishInternal: function(effect) {          effect.element.hide().undoClipping().setStyle(oldStyle); @@ -916,7 +919,7 @@ Effect.Morph = Class.create(Effect.Base, {      var options = Object.extend({        style: { }      }, arguments[1] || { }); -     +      if (!Object.isString(options.style)) this.style = $H(options.style);      else {        if (options.style.include(':')) @@ -934,18 +937,18 @@ Effect.Morph = Class.create(Effect.Base, {            effect.transforms.each(function(transform) {              effect.element.style[transform.style] = '';            }); -        } +        };        }      }      this.start(options);    }, -   +    setup: function(){      function parseColor(color){        if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';        color = color.parseColor();        return $R(0,2).map(function(i){ -        return parseInt( color.slice(i*2+1,i*2+3), 16 )  +        return parseInt( color.slice(i*2+1,i*2+3), 16 );        });      }      this.transforms = this.style.map(function(pair){ @@ -965,9 +968,9 @@ Effect.Morph = Class.create(Effect.Base, {        }        var originalValue = this.element.getStyle(property); -      return {  -        style: property.camelize(),  -        originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0),  +      return { +        style: property.camelize(), +        originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0),          targetValue: unit=='color' ? parseColor(value) : value,          unit: unit        }; @@ -978,13 +981,13 @@ Effect.Morph = Class.create(Effect.Base, {            transform.unit != 'color' &&            (isNaN(transform.originalValue) || isNaN(transform.targetValue))          ) -      ) +      );      });    },    update: function(position) {      var style = { }, transform, i = this.transforms.length;      while(i--) -      style[(transform = this.transforms[i]).style] =  +      style[(transform = this.transforms[i]).style] =          transform.unit=='color' ? '#'+            (Math.round(transform.originalValue[0]+              (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() + @@ -993,7 +996,7 @@ Effect.Morph = Class.create(Effect.Base, {            (Math.round(transform.originalValue[2]+              (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() :          (transform.originalValue + -          (transform.targetValue - transform.originalValue) * position).toFixed(3) +  +          (transform.targetValue - transform.originalValue) * position).toFixed(3) +              (transform.unit === null ? '' : transform.unit);      this.element.setStyle(style, true);    } @@ -1030,7 +1033,7 @@ Effect.Transform = Class.create({  });  Element.CSS_PROPERTIES = $w( -  'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' +  +  'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' +    'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +    'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +    'borderTopColor borderTopStyle borderTopWidth bottom clip color ' + @@ -1039,7 +1042,7 @@ Element.CSS_PROPERTIES = $w(    'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +    'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +    'right textIndent top width wordSpacing zIndex'); -   +  Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;  String.__parseStyleElement = document.createElement('div'); @@ -1051,11 +1054,11 @@ String.prototype.parseStyle = function(){      String.__parseStyleElement.innerHTML = '<div style="' + this + '"></div>';      style = String.__parseStyleElement.childNodes[0].style;    } -   +    Element.CSS_PROPERTIES.each(function(property){ -    if (style[property]) styleRules.set(property, style[property]);  +    if (style[property]) styleRules.set(property, style[property]);    }); -   +    if (Prototype.Browser.IE && this.include('opacity'))      styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]); @@ -1074,14 +1077,14 @@ if (document.defaultView && document.defaultView.getComputedStyle) {    Element.getStyles = function(element) {      element = $(element);      var css = element.currentStyle, styles; -    styles = Element.CSS_PROPERTIES.inject({ }, function(hash, property) { -      hash.set(property, css[property]); -      return hash; +    styles = Element.CSS_PROPERTIES.inject({ }, function(results, property) { +      results[property] = css[property]; +      return results;      }); -    if (!styles.opacity) styles.set('opacity', element.getOpacity()); +    if (!styles.opacity) styles.opacity = element.getOpacity();      return styles;    }; -}; +}  Effect.Methods = {    morph: function(element, style) { @@ -1090,7 +1093,7 @@ Effect.Methods = {      return element;    },    visualEffect: function(element, effect, options) { -    element = $(element) +    element = $(element);      var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1);      new Effect[klass](element, options);      return element; @@ -1104,17 +1107,17 @@ Effect.Methods = {  $w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+    'pulsate shake puff squish switchOff dropOut').each( -  function(effect) {  +  function(effect) {      Effect.Methods[effect] = function(element, options){        element = $(element);        Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options);        return element; -    } +    };    }  ); -$w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each(  +$w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each(    function(f) { Effect.Methods[f] = Element[f]; }  ); -Element.addMethods(Effect.Methods); +Element.addMethods(Effect.Methods);
\ No newline at end of file diff --git a/public/javascripts/prototype.js b/public/javascripts/prototype.js index 546f9fe44..06249a6ae 100644 --- a/public/javascripts/prototype.js +++ b/public/javascripts/prototype.js @@ -1,5 +1,5 @@ -/*  Prototype JavaScript framework, version 1.6.0.1 - *  (c) 2005-2007 Sam Stephenson +/*  Prototype JavaScript framework, version 1.7_rc2 + *  (c) 2005-2010 Sam Stephenson   *   *  Prototype is freely distributable under the terms of an MIT-style license.   *  For details, see the Prototype web site: http://www.prototypejs.org/ @@ -7,29 +7,53 @@   *--------------------------------------------------------------------------*/  var Prototype = { -  Version: '1.6.0.1', -  Browser: { -    IE:     !!(window.attachEvent && !window.opera), -    Opera:  !!window.opera, -    WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1, -    Gecko:  navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1, -    MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/) -  }, +  Version: '1.7_rc2', + +  Browser: (function(){ +    var ua = navigator.userAgent; +    var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]'; +    return { +      IE:             !!window.attachEvent && !isOpera, +      Opera:          isOpera, +      WebKit:         ua.indexOf('AppleWebKit/') > -1, +      Gecko:          ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1, +      MobileSafari:   /Apple.*Mobile/.test(ua) +    } +  })(),    BrowserFeatures: {      XPath: !!document.evaluate, -    ElementExtensions: !!window.HTMLElement, -    SpecificElementExtensions: -      document.createElement('div').__proto__ && -      document.createElement('div').__proto__ !== -        document.createElement('form').__proto__ + +    SelectorsAPI: !!document.querySelector, + +    ElementExtensions: (function() { +      var constructor = window.Element || window.HTMLElement; +      return !!(constructor && constructor.prototype); +    })(), +    SpecificElementExtensions: (function() { +      if (typeof window.HTMLDivElement !== 'undefined') +        return true; + +      var div = document.createElement('div'), +          form = document.createElement('form'), +          isSupported = false; + +      if (div['__proto__'] && (div['__proto__'] !== form['__proto__'])) { +        isSupported = true; +      } + +      div = form = null; + +      return isSupported; +    })()    },    ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',    JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,    emptyFunction: function() { }, +    K: function(x) { return x }  }; @@ -37,9 +61,38 @@ if (Prototype.Browser.MobileSafari)    Prototype.BrowserFeatures.SpecificElementExtensions = false; +var Abstract = { }; + + +var Try = { +  these: function() { +    var returnValue; + +    for (var i = 0, length = arguments.length; i < length; i++) { +      var lambda = arguments[i]; +      try { +        returnValue = lambda(); +        break; +      } catch (e) { } +    } + +    return returnValue; +  } +}; +  /* Based on Alex Arnell's inheritance implementation. */ -var Class = { -  create: function() { + +var Class = (function() { + +  var IS_DONTENUM_BUGGY = (function(){ +    for (var p in { toString: 1 }) { +      if (p === 'toString') return false; +    } +    return true; +  })(); + +  function subclass() {}; +  function create() {      var parent = null, properties = $A(arguments);      if (Object.isFunction(properties[0]))        parent = properties.shift(); @@ -53,235 +106,374 @@ var Class = {      klass.subclasses = [];      if (parent) { -      var subclass = function() { };        subclass.prototype = parent.prototype;        klass.prototype = new subclass;        parent.subclasses.push(klass);      } -    for (var i = 0; i < properties.length; i++) +    for (var i = 0, length = properties.length; i < length; i++)        klass.addMethods(properties[i]);      if (!klass.prototype.initialize)        klass.prototype.initialize = Prototype.emptyFunction;      klass.prototype.constructor = klass; -      return klass;    } -}; -Class.Methods = { -  addMethods: function(source) { -    var ancestor   = this.superclass && this.superclass.prototype; -    var properties = Object.keys(source); +  function addMethods(source) { +    var ancestor   = this.superclass && this.superclass.prototype, +        properties = Object.keys(source); -    if (!Object.keys({ toString: true }).length) -      properties.push("toString", "valueOf"); +    if (IS_DONTENUM_BUGGY) { +      if (source.toString != Object.prototype.toString) +        properties.push("toString"); +      if (source.valueOf != Object.prototype.valueOf) +        properties.push("valueOf"); +    }      for (var i = 0, length = properties.length; i < length; i++) {        var property = properties[i], value = source[property];        if (ancestor && Object.isFunction(value) && -          value.argumentNames().first() == "$super") { -        var method = value, value = Object.extend((function(m) { -          return function() { return ancestor[m].apply(this, arguments) }; -        })(property).wrap(method), { -          valueOf:  function() { return method }, -          toString: function() { return method.toString() } -        }); +          value.argumentNames()[0] == "$super") { +        var method = value; +        value = (function(m) { +          return function() { return ancestor[m].apply(this, arguments); }; +        })(property).wrap(method); + +        value.valueOf = method.valueOf.bind(method); +        value.toString = method.toString.bind(method);        }        this.prototype[property] = value;      }      return this;    } -}; -var Abstract = { }; +  return { +    create: create, +    Methods: { +      addMethods: addMethods +    } +  }; +})(); +(function() { -Object.extend = function(destination, source) { -  for (var property in source) -    destination[property] = source[property]; -  return destination; -}; +  var _toString = Object.prototype.toString, +      NULL_TYPE = 'Null', +      UNDEFINED_TYPE = 'Undefined', +      BOOLEAN_TYPE = 'Boolean', +      NUMBER_TYPE = 'Number', +      STRING_TYPE = 'String', +      OBJECT_TYPE = 'Object', +      BOOLEAN_CLASS = '[object Boolean]', +      NUMBER_CLASS = '[object Number]', +      STRING_CLASS = '[object String]', +      ARRAY_CLASS = '[object Array]', +      NATIVE_JSON_STRINGIFY_SUPPORT = window.JSON && +        typeof JSON.stringify === 'function' && +        JSON.stringify(0) === '0' && +        typeof JSON.stringify(Prototype.K) === 'undefined'; + +  function Type(o) { +    switch(o) { +      case null: return NULL_TYPE; +      case (void 0): return UNDEFINED_TYPE; +    } +    var type = typeof o; +    switch(type) { +      case 'boolean': return BOOLEAN_TYPE; +      case 'number':  return NUMBER_TYPE; +      case 'string':  return STRING_TYPE; +    } +    return OBJECT_TYPE; +  } -Object.extend(Object, { -  inspect: function(object) { +  function extend(destination, source) { +    for (var property in source) +      destination[property] = source[property]; +    return destination; +  } + +  function inspect(object) {      try { -      if (Object.isUndefined(object)) return 'undefined'; +      if (isUndefined(object)) return 'undefined';        if (object === null) return 'null'; -      return object.inspect ? object.inspect() : object.toString(); +      return object.inspect ? object.inspect() : String(object);      } catch (e) {        if (e instanceof RangeError) return '...';        throw e;      } -  }, +  } -  toJSON: function(object) { -    var type = typeof object; -    switch (type) { -      case 'undefined': -      case 'function': -      case 'unknown': return; -      case 'boolean': return object.toString(); +  function toJSON(value) { +    return Str('', { '': value }, []); +  } + +  function Str(key, holder, stack) { +    var value = holder[key], +        type = typeof value; + +    if (Type(value) === OBJECT_TYPE && typeof value.toJSON === 'function') { +      value = value.toJSON(key);      } -    if (object === null) return 'null'; -    if (object.toJSON) return object.toJSON(); -    if (Object.isElement(object)) return; +    var _class = _toString.call(value); -    var results = []; -    for (var property in object) { -      var value = Object.toJSON(object[property]); -      if (!Object.isUndefined(value)) -        results.push(property.toJSON() + ': ' + value); +    switch (_class) { +      case NUMBER_CLASS: +      case BOOLEAN_CLASS: +      case STRING_CLASS: +        value = value.valueOf();      } -    return '{' + results.join(', ') + '}'; -  }, +    switch (value) { +      case null: return 'null'; +      case true: return 'true'; +      case false: return 'false'; +    } + +    type = typeof value; +    switch (type) { +      case 'string': +        return value.inspect(true); +      case 'number': +        return isFinite(value) ? String(value) : 'null'; +      case 'object': + +        for (var i = 0, length = stack.length; i < length; i++) { +          if (stack[i] === value) { throw new TypeError(); } +        } +        stack.push(value); -  toQueryString: function(object) { +        var partial = []; +        if (_class === ARRAY_CLASS) { +          for (var i = 0, length = value.length; i < length; i++) { +            var str = Str(i, value, stack); +            partial.push(typeof str === 'undefined' ? 'null' : str); +          } +          partial = '[' + partial.join(',') + ']'; +        } else { +          var keys = Object.keys(value); +          for (var i = 0, length = keys.length; i < length; i++) { +            var key = keys[i], str = Str(key, value, stack); +            if (typeof str !== "undefined") { +               partial.push(key.inspect(true)+ ':' + str); +             } +          } +          partial = '{' + partial.join(',') + '}'; +        } +        stack.pop(); +        return partial; +    } +  } + +  function stringify(object) { +    return JSON.stringify(object); +  } + +  function toQueryString(object) {      return $H(object).toQueryString(); -  }, +  } -  toHTML: function(object) { +  function toHTML(object) {      return object && object.toHTML ? object.toHTML() : String.interpret(object); -  }, +  } -  keys: function(object) { -    var keys = []; -    for (var property in object) -      keys.push(property); -    return keys; -  }, +  function keys(object) { +    if (Type(object) !== OBJECT_TYPE) { throw new TypeError(); } +    var results = []; +    for (var property in object) { +      if (object.hasOwnProperty(property)) { +        results.push(property); +      } +    } +    return results; +  } -  values: function(object) { -    var values = []; +  function values(object) { +    var results = [];      for (var property in object) -      values.push(object[property]); -    return values; -  }, +      results.push(object[property]); +    return results; +  } -  clone: function(object) { -    return Object.extend({ }, object); -  }, +  function clone(object) { +    return extend({ }, object); +  } -  isElement: function(object) { -    return object && object.nodeType == 1; -  }, +  function isElement(object) { +    return !!(object && object.nodeType == 1); +  } -  isArray: function(object) { -    return object && object.constructor === Array; -  }, +  function isArray(object) { +    return _toString.call(object) === ARRAY_CLASS; +  } + +  var hasNativeIsArray = (typeof Array.isArray == 'function') +    && Array.isArray([]) && !Array.isArray({}); -  isHash: function(object) { +  if (hasNativeIsArray) { +    isArray = Array.isArray; +  } + +  function isHash(object) {      return object instanceof Hash; -  }, +  } -  isFunction: function(object) { -    return typeof object == "function"; -  }, +  function isFunction(object) { +    return typeof object === "function"; +  } -  isString: function(object) { -    return typeof object == "string"; -  }, +  function isString(object) { +    return _toString.call(object) === STRING_CLASS; +  } -  isNumber: function(object) { -    return typeof object == "number"; -  }, +  function isNumber(object) { +    return _toString.call(object) === NUMBER_CLASS; +  } -  isUndefined: function(object) { -    return typeof object == "undefined"; +  function isUndefined(object) { +    return typeof object === "undefined";    } -}); -Object.extend(Function.prototype, { -  argumentNames: function() { -    var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip"); +  extend(Object, { +    extend:        extend, +    inspect:       inspect, +    toJSON:        NATIVE_JSON_STRINGIFY_SUPPORT ? stringify : toJSON, +    toQueryString: toQueryString, +    toHTML:        toHTML, +    keys:          Object.keys || keys, +    values:        values, +    clone:         clone, +    isElement:     isElement, +    isArray:       isArray, +    isHash:        isHash, +    isFunction:    isFunction, +    isString:      isString, +    isNumber:      isNumber, +    isUndefined:   isUndefined +  }); +})(); +Object.extend(Function.prototype, (function() { +  var slice = Array.prototype.slice; + +  function update(array, args) { +    var arrayLength = array.length, length = args.length; +    while (length--) array[arrayLength + length] = args[length]; +    return array; +  } + +  function merge(array, args) { +    array = slice.call(array, 0); +    return update(array, args); +  } + +  function argumentNames() { +    var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1] +      .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '') +      .replace(/\s+/g, '').split(',');      return names.length == 1 && !names[0] ? [] : names; -  }, +  } -  bind: function() { +  function bind(context) {      if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this; -    var __method = this, args = $A(arguments), object = args.shift(); +    var __method = this, args = slice.call(arguments, 1);      return function() { -      return __method.apply(object, args.concat($A(arguments))); +      var a = merge(args, arguments); +      return __method.apply(context, a);      } -  }, +  } -  bindAsEventListener: function() { -    var __method = this, args = $A(arguments), object = args.shift(); +  function bindAsEventListener(context) { +    var __method = this, args = slice.call(arguments, 1);      return function(event) { -      return __method.apply(object, [event || window.event].concat(args)); +      var a = update([event || window.event], args); +      return __method.apply(context, a);      } -  }, +  } -  curry: function() { +  function curry() {      if (!arguments.length) return this; -    var __method = this, args = $A(arguments); +    var __method = this, args = slice.call(arguments, 0);      return function() { -      return __method.apply(this, args.concat($A(arguments))); +      var a = merge(args, arguments); +      return __method.apply(this, a);      } -  }, +  } -  delay: function() { -    var __method = this, args = $A(arguments), timeout = args.shift() * 1000; +  function delay(timeout) { +    var __method = this, args = slice.call(arguments, 1); +    timeout = timeout * 1000;      return window.setTimeout(function() {        return __method.apply(__method, args);      }, timeout); -  }, +  } + +  function defer() { +    var args = update([0.01], arguments); +    return this.delay.apply(this, args); +  } -  wrap: function(wrapper) { +  function wrap(wrapper) {      var __method = this;      return function() { -      return wrapper.apply(this, [__method.bind(this)].concat($A(arguments))); +      var a = update([__method.bind(this)], arguments); +      return wrapper.apply(this, a);      } -  }, +  } -  methodize: function() { +  function methodize() {      if (this._methodized) return this._methodized;      var __method = this;      return this._methodized = function() { -      return __method.apply(null, [this].concat($A(arguments))); +      var a = update([this], arguments); +      return __method.apply(null, a);      };    } -}); -Function.prototype.defer = Function.prototype.delay.curry(0.01); +  return { +    argumentNames:       argumentNames, +    bind:                bind, +    bindAsEventListener: bindAsEventListener, +    curry:               curry, +    delay:               delay, +    defer:               defer, +    wrap:                wrap, +    methodize:           methodize +  } +})()); -Date.prototype.toJSON = function() { -  return '"' + this.getUTCFullYear() + '-' + -    (this.getUTCMonth() + 1).toPaddedString(2) + '-' + -    this.getUTCDate().toPaddedString(2) + 'T' + -    this.getUTCHours().toPaddedString(2) + ':' + -    this.getUTCMinutes().toPaddedString(2) + ':' + -    this.getUTCSeconds().toPaddedString(2) + 'Z"'; -}; -var Try = { -  these: function() { -    var returnValue; -    for (var i = 0, length = arguments.length; i < length; i++) { -      var lambda = arguments[i]; -      try { -        returnValue = lambda(); -        break; -      } catch (e) { } -    } +(function(proto) { -    return returnValue; + +  function toISOString() { +    return this.getUTCFullYear() + '-' + +      (this.getUTCMonth() + 1).toPaddedString(2) + '-' + +      this.getUTCDate().toPaddedString(2) + 'T' + +      this.getUTCHours().toPaddedString(2) + ':' + +      this.getUTCMinutes().toPaddedString(2) + ':' + +      this.getUTCSeconds().toPaddedString(2) + 'Z';    } -}; + + +  function toJSON() { +    return this.toISOString(); +  } + +  if (!proto.toISOString) proto.toISOString = toISOString; +  if (!proto.toJSON) proto.toJSON = toJSON; + +})(Date.prototype); +  RegExp.prototype.match = RegExp.prototype.test;  RegExp.escape = function(str) {    return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');  }; - -/*--------------------------------------------------------------------------*/ -  var PeriodicalExecuter = Class.create({    initialize: function(callback, frequency) {      this.callback = callback; @@ -310,8 +502,10 @@ var PeriodicalExecuter = Class.create({        try {          this.currentlyExecuting = true;          this.execute(); -      } finally {          this.currentlyExecuting = false; +      } catch(e) { +        this.currentlyExecuting = false; +        throw e;        }      }    } @@ -330,10 +524,28 @@ Object.extend(String, {    }  }); -Object.extend(String.prototype, { -  gsub: function(pattern, replacement) { +Object.extend(String.prototype, (function() { +  var NATIVE_JSON_PARSE_SUPPORT = window.JSON && +    typeof JSON.parse === 'function' && +    JSON.parse('{"test": true}').test; + +  function prepareReplacement(replacement) { +    if (Object.isFunction(replacement)) return replacement; +    var template = new Template(replacement); +    return function(match) { return template.evaluate(match) }; +  } + +  function gsub(pattern, replacement) {      var result = '', source = this, match; -    replacement = arguments.callee.prepareReplacement(replacement); +    replacement = prepareReplacement(replacement); + +    if (Object.isString(pattern)) +      pattern = RegExp.escape(pattern); + +    if (!(pattern.length || pattern.source)) { +      replacement = replacement(''); +      return replacement + source.split('').join(replacement) + replacement; +    }      while (source.length > 0) {        if (match = source.match(pattern)) { @@ -345,76 +557,72 @@ Object.extend(String.prototype, {        }      }      return result; -  }, +  } -  sub: function(pattern, replacement, count) { -    replacement = this.gsub.prepareReplacement(replacement); +  function sub(pattern, replacement, count) { +    replacement = prepareReplacement(replacement);      count = Object.isUndefined(count) ? 1 : count;      return this.gsub(pattern, function(match) {        if (--count < 0) return match[0];        return replacement(match);      }); -  }, +  } -  scan: function(pattern, iterator) { +  function scan(pattern, iterator) {      this.gsub(pattern, iterator);      return String(this); -  }, +  } -  truncate: function(length, truncation) { +  function truncate(length, truncation) {      length = length || 30;      truncation = Object.isUndefined(truncation) ? '...' : truncation;      return this.length > length ?        this.slice(0, length - truncation.length) + truncation : String(this); -  }, +  } -  strip: function() { +  function strip() {      return this.replace(/^\s+/, '').replace(/\s+$/, ''); -  }, +  } -  stripTags: function() { -    return this.replace(/<\/?[^>]+>/gi, ''); -  }, +  function stripTags() { +    return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?>|<\/\w+>/gi, ''); +  } -  stripScripts: function() { +  function stripScripts() {      return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); -  }, +  } -  extractScripts: function() { -    var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); -    var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); +  function extractScripts() { +    var matchAll = new RegExp(Prototype.ScriptFragment, 'img'), +        matchOne = new RegExp(Prototype.ScriptFragment, 'im');      return (this.match(matchAll) || []).map(function(scriptTag) {        return (scriptTag.match(matchOne) || ['', ''])[1];      }); -  }, +  } -  evalScripts: function() { +  function evalScripts() {      return this.extractScripts().map(function(script) { return eval(script) }); -  }, +  } -  escapeHTML: function() { -    var self = arguments.callee; -    self.text.data = this; -    return self.div.innerHTML; -  }, +  function escapeHTML() { +    return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); +  } + +  function unescapeHTML() { +    return this.stripTags().replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&'); +  } -  unescapeHTML: function() { -    var div = new Element('div'); -    div.innerHTML = this.stripTags(); -    return div.childNodes[0] ? (div.childNodes.length > 1 ? -      $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) : -      div.childNodes[0].nodeValue) : ''; -  }, -  toQueryParams: function(separator) { +  function toQueryParams(separator) {      var match = this.strip().match(/([^?#]*)(#.*)?$/);      if (!match) return { };      return match[1].split(separator || '&').inject({ }, function(hash, pair) {        if ((pair = pair.split('='))[0]) { -        var key = decodeURIComponent(pair.shift()); -        var value = pair.length > 1 ? pair.join('=') : pair[0]; +        var key = decodeURIComponent(pair.shift()), +            value = pair.length > 1 ? pair.join('=') : pair[0]; +          if (value != undefined) value = decodeURIComponent(value);          if (key in hash) { @@ -425,128 +633,144 @@ Object.extend(String.prototype, {        }        return hash;      }); -  }, +  } -  toArray: function() { +  function toArray() {      return this.split(''); -  }, +  } -  succ: function() { +  function succ() {      return this.slice(0, this.length - 1) +        String.fromCharCode(this.charCodeAt(this.length - 1) + 1); -  }, +  } -  times: function(count) { +  function times(count) {      return count < 1 ? '' : new Array(count + 1).join(this); -  }, - -  camelize: function() { -    var parts = this.split('-'), len = parts.length; -    if (len == 1) return parts[0]; - -    var camelized = this.charAt(0) == '-' -      ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) -      : parts[0]; - -    for (var i = 1; i < len; i++) -      camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); +  } -    return camelized; -  }, +  function camelize() { +    return this.replace(/-+(.)?/g, function(match, chr) { +      return chr ? chr.toUpperCase() : ''; +    }); +  } -  capitalize: function() { +  function capitalize() {      return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); -  }, +  } -  underscore: function() { -    return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase(); -  }, +  function underscore() { +    return this.replace(/::/g, '/') +               .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2') +               .replace(/([a-z\d])([A-Z])/g, '$1_$2') +               .replace(/-/g, '_') +               .toLowerCase(); +  } -  dasherize: function() { -    return this.gsub(/_/,'-'); -  }, +  function dasherize() { +    return this.replace(/_/g, '-'); +  } -  inspect: function(useDoubleQuotes) { -    var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) { -      var character = String.specialChar[match[0]]; -      return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16); +  function inspect(useDoubleQuotes) { +    var escapedString = this.replace(/[\x00-\x1f\\]/g, function(character) { +      if (character in String.specialChar) { +        return String.specialChar[character]; +      } +      return '\\u00' + character.charCodeAt().toPaddedString(2, 16);      });      if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';      return "'" + escapedString.replace(/'/g, '\\\'') + "'"; -  }, - -  toJSON: function() { -    return this.inspect(true); -  }, +  } -  unfilterJSON: function(filter) { -    return this.sub(filter || Prototype.JSONFilter, '#{1}'); -  }, +  function unfilterJSON(filter) { +    return this.replace(filter || Prototype.JSONFilter, '$1'); +  } -  isJSON: function() { +  function isJSON() {      var str = this;      if (str.blank()) return false; -    str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''); -    return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str); -  }, +    str = str.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@'); +    str = str.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'); +    str = str.replace(/(?:^|:|,)(?:\s*\[)+/g, ''); +    return (/^[\],:{}\s]*$/).test(str); +  } -  evalJSON: function(sanitize) { -    var json = this.unfilterJSON(); +  function evalJSON(sanitize) { +    var json = this.unfilterJSON(), +        cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; +    if (cx.test(json)) { +      json = json.replace(cx, function (a) { +        return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); +      }); +    }      try {        if (!sanitize || json.isJSON()) return eval('(' + json + ')');      } catch (e) { }      throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); -  }, +  } -  include: function(pattern) { +  function parseJSON() { +    var json = this.unfilterJSON(); +    return JSON.parse(json); +  } + +  function include(pattern) {      return this.indexOf(pattern) > -1; -  }, +  } -  startsWith: function(pattern) { -    return this.indexOf(pattern) === 0; -  }, +  function startsWith(pattern) { +    return this.lastIndexOf(pattern, 0) === 0; +  } -  endsWith: function(pattern) { +  function endsWith(pattern) {      var d = this.length - pattern.length; -    return d >= 0 && this.lastIndexOf(pattern) === d; -  }, +    return d >= 0 && this.indexOf(pattern, d) === d; +  } -  empty: function() { +  function empty() {      return this == ''; -  }, +  } -  blank: function() { +  function blank() {      return /^\s*$/.test(this); -  }, - -  interpolate: function(object, pattern) { -    return new Template(this, pattern).evaluate(object);    } -}); -if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, { -  escapeHTML: function() { -    return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); -  }, -  unescapeHTML: function() { -    return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); +  function interpolate(object, pattern) { +    return new Template(this, pattern).evaluate(object);    } -}); - -String.prototype.gsub.prepareReplacement = function(replacement) { -  if (Object.isFunction(replacement)) return replacement; -  var template = new Template(replacement); -  return function(match) { return template.evaluate(match) }; -}; -String.prototype.parseQuery = String.prototype.toQueryParams; - -Object.extend(String.prototype.escapeHTML, { -  div:  document.createElement('div'), -  text: document.createTextNode('') -}); - -with (String.prototype.escapeHTML) div.appendChild(text); +  return { +    gsub:           gsub, +    sub:            sub, +    scan:           scan, +    truncate:       truncate, +    strip:          String.prototype.trim || strip, +    stripTags:      stripTags, +    stripScripts:   stripScripts, +    extractScripts: extractScripts, +    evalScripts:    evalScripts, +    escapeHTML:     escapeHTML, +    unescapeHTML:   unescapeHTML, +    toQueryParams:  toQueryParams, +    parseQuery:     toQueryParams, +    toArray:        toArray, +    succ:           succ, +    times:          times, +    camelize:       camelize, +    capitalize:     capitalize, +    underscore:     underscore, +    dasherize:      dasherize, +    inspect:        inspect, +    unfilterJSON:   unfilterJSON, +    isJSON:         isJSON, +    evalJSON:       NATIVE_JSON_PARSE_SUPPORT ? parseJSON : evalJSON, +    include:        include, +    startsWith:     startsWith, +    endsWith:       endsWith, +    empty:          empty, +    blank:          blank, +    interpolate:    interpolate +  }; +})());  var Template = Class.create({    initialize: function(template, pattern) { @@ -555,22 +779,23 @@ var Template = Class.create({    },    evaluate: function(object) { -    if (Object.isFunction(object.toTemplateReplacements)) +    if (object && Object.isFunction(object.toTemplateReplacements))        object = object.toTemplateReplacements();      return this.template.gsub(this.pattern, function(match) { -      if (object == null) return ''; +      if (object == null) return (match[1] + '');        var before = match[1] || '';        if (before == '\\') return match[2]; -      var ctx = object, expr = match[3]; -      var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/; +      var ctx = object, expr = match[3], +          pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/; +        match = pattern.exec(expr);        if (match == null) return before;        while (match != null) { -        var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1]; +        var comp = match[1].startsWith('[') ? match[2].replace(/\\\\]/g, ']') : match[1];          ctx = ctx[comp];          if (null == ctx || '' == match[3]) break;          expr = expr.substring('[' == match[3] ? match[1].length : match[0].length); @@ -578,101 +803,98 @@ var Template = Class.create({        }        return before + String.interpret(ctx); -    }.bind(this)); +    });    }  });  Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;  var $break = { }; -var Enumerable = { -  each: function(iterator, context) { +var Enumerable = (function() { +  function each(iterator, context) {      var index = 0; -    iterator = iterator.bind(context);      try {        this._each(function(value) { -        iterator(value, index++); +        iterator.call(context, value, index++);        });      } catch (e) {        if (e != $break) throw e;      }      return this; -  }, +  } -  eachSlice: function(number, iterator, context) { -    iterator = iterator ? iterator.bind(context) : Prototype.K; +  function eachSlice(number, iterator, context) {      var index = -number, slices = [], array = this.toArray(); +    if (number < 1) return array;      while ((index += number) < array.length)        slices.push(array.slice(index, index+number));      return slices.collect(iterator, context); -  }, +  } -  all: function(iterator, context) { -    iterator = iterator ? iterator.bind(context) : Prototype.K; +  function all(iterator, context) { +    iterator = iterator || Prototype.K;      var result = true;      this.each(function(value, index) { -      result = result && !!iterator(value, index); +      result = result && !!iterator.call(context, value, index);        if (!result) throw $break;      });      return result; -  }, +  } -  any: function(iterator, context) { -    iterator = iterator ? iterator.bind(context) : Prototype.K; +  function any(iterator, context) { +    iterator = iterator || Prototype.K;      var result = false;      this.each(function(value, index) { -      if (result = !!iterator(value, index)) +      if (result = !!iterator.call(context, value, index))          throw $break;      });      return result; -  }, +  } -  collect: function(iterator, context) { -    iterator = iterator ? iterator.bind(context) : Prototype.K; +  function collect(iterator, context) { +    iterator = iterator || Prototype.K;      var results = [];      this.each(function(value, index) { -      results.push(iterator(value, index)); +      results.push(iterator.call(context, value, index));      });      return results; -  }, +  } -  detect: function(iterator, context) { -    iterator = iterator.bind(context); +  function detect(iterator, context) {      var result;      this.each(function(value, index) { -      if (iterator(value, index)) { +      if (iterator.call(context, value, index)) {          result = value;          throw $break;        }      });      return result; -  }, +  } -  findAll: function(iterator, context) { -    iterator = iterator.bind(context); +  function findAll(iterator, context) {      var results = [];      this.each(function(value, index) { -      if (iterator(value, index)) +      if (iterator.call(context, value, index))          results.push(value);      });      return results; -  }, +  } -  grep: function(filter, iterator, context) { -    iterator = iterator ? iterator.bind(context) : Prototype.K; +  function grep(filter, iterator, context) { +    iterator = iterator || Prototype.K;      var results = [];      if (Object.isString(filter)) -      filter = new RegExp(filter); +      filter = new RegExp(RegExp.escape(filter));      this.each(function(value, index) {        if (filter.match(value)) -        results.push(iterator(value, index)); +        results.push(iterator.call(context, value, index));      });      return results; -  }, +  } -  include: function(object) { +  function include(object) {      if (Object.isFunction(this.indexOf))        if (this.indexOf(object) != -1) return true; @@ -684,96 +906,96 @@ var Enumerable = {        }      });      return found; -  }, +  } -  inGroupsOf: function(number, fillWith) { +  function inGroupsOf(number, fillWith) {      fillWith = Object.isUndefined(fillWith) ? null : fillWith;      return this.eachSlice(number, function(slice) {        while(slice.length < number) slice.push(fillWith);        return slice;      }); -  }, +  } -  inject: function(memo, iterator, context) { -    iterator = iterator.bind(context); +  function inject(memo, iterator, context) {      this.each(function(value, index) { -      memo = iterator(memo, value, index); +      memo = iterator.call(context, memo, value, index);      });      return memo; -  }, +  } -  invoke: function(method) { +  function invoke(method) {      var args = $A(arguments).slice(1);      return this.map(function(value) {        return value[method].apply(value, args);      }); -  }, +  } -  max: function(iterator, context) { -    iterator = iterator ? iterator.bind(context) : Prototype.K; +  function max(iterator, context) { +    iterator = iterator || Prototype.K;      var result;      this.each(function(value, index) { -      value = iterator(value, index); +      value = iterator.call(context, value, index);        if (result == null || value >= result)          result = value;      });      return result; -  }, +  } -  min: function(iterator, context) { -    iterator = iterator ? iterator.bind(context) : Prototype.K; +  function min(iterator, context) { +    iterator = iterator || Prototype.K;      var result;      this.each(function(value, index) { -      value = iterator(value, index); +      value = iterator.call(context, value, index);        if (result == null || value < result)          result = value;      });      return result; -  }, +  } -  partition: function(iterator, context) { -    iterator = iterator ? iterator.bind(context) : Prototype.K; +  function partition(iterator, context) { +    iterator = iterator || Prototype.K;      var trues = [], falses = [];      this.each(function(value, index) { -      (iterator(value, index) ? +      (iterator.call(context, value, index) ?          trues : falses).push(value);      });      return [trues, falses]; -  }, +  } -  pluck: function(property) { +  function pluck(property) {      var results = [];      this.each(function(value) {        results.push(value[property]);      });      return results; -  }, +  } -  reject: function(iterator, context) { -    iterator = iterator.bind(context); +  function reject(iterator, context) {      var results = [];      this.each(function(value, index) { -      if (!iterator(value, index)) +      if (!iterator.call(context, value, index))          results.push(value);      });      return results; -  }, +  } -  sortBy: function(iterator, context) { -    iterator = iterator.bind(context); +  function sortBy(iterator, context) {      return this.map(function(value, index) { -      return {value: value, criteria: iterator(value, index)}; +      return { +        value: value, +        criteria: iterator.call(context, value, index) +      };      }).sort(function(left, right) {        var a = left.criteria, b = right.criteria;        return a < b ? -1 : a > b ? 1 : 0;      }).pluck('value'); -  }, +  } -  toArray: function() { +  function toArray() {      return this.map(); -  }, +  } -  zip: function() { +  function zip() {      var iterator = Prototype.K, args = $A(arguments);      if (Object.isFunction(args.last()))        iterator = args.pop(); @@ -782,330 +1004,409 @@ var Enumerable = {      return this.map(function(value, index) {        return iterator(collections.pluck(index));      }); -  }, +  } -  size: function() { +  function size() {      return this.toArray().length; -  }, +  } -  inspect: function() { +  function inspect() {      return '#<Enumerable:' + this.toArray().inspect() + '>';    } -}; -Object.extend(Enumerable, { -  map:     Enumerable.collect, -  find:    Enumerable.detect, -  select:  Enumerable.findAll, -  filter:  Enumerable.findAll, -  member:  Enumerable.include, -  entries: Enumerable.toArray, -  every:   Enumerable.all, -  some:    Enumerable.any -}); + + + + + + + + +  return { +    each:       each, +    eachSlice:  eachSlice, +    all:        all, +    every:      all, +    any:        any, +    some:       any, +    collect:    collect, +    map:        collect, +    detect:     detect, +    findAll:    findAll, +    select:     findAll, +    filter:     findAll, +    grep:       grep, +    include:    include, +    member:     include, +    inGroupsOf: inGroupsOf, +    inject:     inject, +    invoke:     invoke, +    max:        max, +    min:        min, +    partition:  partition, +    pluck:      pluck, +    reject:     reject, +    sortBy:     sortBy, +    toArray:    toArray, +    entries:    toArray, +    zip:        zip, +    size:       size, +    inspect:    inspect, +    find:       detect +  }; +})(); +  function $A(iterable) {    if (!iterable) return []; -  if (iterable.toArray) return iterable.toArray(); -  var length = iterable.length, results = new Array(length); +  if ('toArray' in Object(iterable)) return iterable.toArray(); +  var length = iterable.length || 0, results = new Array(length);    while (length--) results[length] = iterable[length];    return results;  } -if (Prototype.Browser.WebKit) { -  function $A(iterable) { -    if (!iterable) return []; -    if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') && -        iterable.toArray) return iterable.toArray(); -    var length = iterable.length, results = new Array(length); -    while (length--) results[length] = iterable[length]; -    return results; -  } + +function $w(string) { +  if (!Object.isString(string)) return []; +  string = string.strip(); +  return string ? string.split(/\s+/) : [];  }  Array.from = $A; -Object.extend(Array.prototype, Enumerable); -if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse; +(function() { +  var arrayProto = Array.prototype, +      slice = arrayProto.slice, +      _each = arrayProto.forEach; // use native browser JS 1.6 implementation if available -Object.extend(Array.prototype, { -  _each: function(iterator) { +  function each(iterator) {      for (var i = 0, length = this.length; i < length; i++)        iterator(this[i]); -  }, +  } +  if (!_each) _each = each; -  clear: function() { +  function clear() {      this.length = 0;      return this; -  }, +  } -  first: function() { +  function first() {      return this[0]; -  }, +  } -  last: function() { +  function last() {      return this[this.length - 1]; -  }, +  } -  compact: function() { +  function compact() {      return this.select(function(value) {        return value != null;      }); -  }, +  } -  flatten: function() { +  function flatten() {      return this.inject([], function(array, value) { -      return array.concat(Object.isArray(value) ? -        value.flatten() : [value]); +      if (Object.isArray(value)) +        return array.concat(value.flatten()); +      array.push(value); +      return array;      }); -  }, +  } -  without: function() { -    var values = $A(arguments); +  function without() { +    var values = slice.call(arguments, 0);      return this.select(function(value) {        return !values.include(value);      }); -  }, - -  reverse: function(inline) { -    return (inline !== false ? this : this.toArray())._reverse(); -  }, +  } -  reduce: function() { -    return this.length > 1 ? this : this[0]; -  }, +  function reverse(inline) { +    return (inline === false ? this.toArray() : this)._reverse(); +  } -  uniq: function(sorted) { +  function uniq(sorted) {      return this.inject([], function(array, value, index) {        if (0 == index || (sorted ? array.last() != value : !array.include(value)))          array.push(value);        return array;      }); -  }, +  } -  intersect: function(array) { +  function intersect(array) {      return this.uniq().findAll(function(item) {        return array.detect(function(value) { return item === value });      }); -  }, +  } -  clone: function() { -    return [].concat(this); -  }, -  size: function() { +  function clone() { +    return slice.call(this, 0); +  } + +  function size() {      return this.length; -  }, +  } -  inspect: function() { +  function inspect() {      return '[' + this.map(Object.inspect).join(', ') + ']'; -  }, - -  toJSON: function() { -    var results = []; -    this.each(function(object) { -      var value = Object.toJSON(object); -      if (!Object.isUndefined(value)) results.push(value); -    }); -    return '[' + results.join(', ') + ']';    } -}); - -// use native browser JS 1.6 implementation if available -if (Object.isFunction(Array.prototype.forEach)) -  Array.prototype._each = Array.prototype.forEach; - -if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) { -  i || (i = 0); -  var length = this.length; -  if (i < 0) i = length + i; -  for (; i < length; i++) -    if (this[i] === item) return i; -  return -1; -}; - -if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) { -  i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1; -  var n = this.slice(0, i).reverse().indexOf(item); -  return (n < 0) ? n : i - n - 1; -}; -Array.prototype.toArray = Array.prototype.clone; +  function indexOf(item, i) { +    i || (i = 0); +    var length = this.length; +    if (i < 0) i = length + i; +    for (; i < length; i++) +      if (this[i] === item) return i; +    return -1; +  } -function $w(string) { -  if (!Object.isString(string)) return []; -  string = string.strip(); -  return string ? string.split(/\s+/) : []; -} +  function lastIndexOf(item, i) { +    i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1; +    var n = this.slice(0, i).reverse().indexOf(item); +    return (n < 0) ? n : i - n - 1; +  } -if (Prototype.Browser.Opera){ -  Array.prototype.concat = function() { -    var array = []; -    for (var i = 0, length = this.length; i < length; i++) array.push(this[i]); +  function concat() { +    var array = slice.call(this, 0), item;      for (var i = 0, length = arguments.length; i < length; i++) { -      if (Object.isArray(arguments[i])) { -        for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++) -          array.push(arguments[i][j]); +      item = arguments[i]; +      if (Object.isArray(item) && !('callee' in item)) { +        for (var j = 0, arrayLength = item.length; j < arrayLength; j++) +          array.push(item[j]);        } else { -        array.push(arguments[i]); +        array.push(item);        }      }      return array; -  }; -} -Object.extend(Number.prototype, { -  toColorPart: function() { -    return this.toPaddedString(2, 16); -  }, - -  succ: function() { -    return this + 1; -  }, +  } -  times: function(iterator) { -    $R(0, this, true).each(iterator); -    return this; -  }, +  Object.extend(arrayProto, Enumerable); + +  if (!arrayProto._reverse) +    arrayProto._reverse = arrayProto.reverse; + +  Object.extend(arrayProto, { +    _each:     _each, +    clear:     clear, +    first:     first, +    last:      last, +    compact:   compact, +    flatten:   flatten, +    without:   without, +    reverse:   reverse, +    uniq:      uniq, +    intersect: intersect, +    clone:     clone, +    toArray:   clone, +    size:      size, +    inspect:   inspect +  }); -  toPaddedString: function(length, radix) { -    var string = this.toString(radix || 10); -    return '0'.times(length - string.length) + string; -  }, +  var CONCAT_ARGUMENTS_BUGGY = (function() { +    return [].concat(arguments)[0][0] !== 1; +  })(1,2) -  toJSON: function() { -    return isFinite(this) ? this.toString() : 'null'; -  } -}); +  if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat; -$w('abs round ceil floor').each(function(method){ -  Number.prototype[method] = Math[method].methodize(); -}); +  if (!arrayProto.indexOf) arrayProto.indexOf = indexOf; +  if (!arrayProto.lastIndexOf) arrayProto.lastIndexOf = lastIndexOf; +})();  function $H(object) {    return new Hash(object);  };  var Hash = Class.create(Enumerable, (function() { - -  function toQueryPair(key, value) { -    if (Object.isUndefined(value)) return key; -    return key + '=' + encodeURIComponent(String.interpret(value)); +  function initialize(object) { +    this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);    } -  return { -    initialize: function(object) { -      this._object = Object.isHash(object) ? object.toObject() : Object.clone(object); -    }, -    _each: function(iterator) { -      for (var key in this._object) { -        var value = this._object[key], pair = [key, value]; -        pair.key = key; -        pair.value = value; -        iterator(pair); -      } -    }, +  function _each(iterator) { +    for (var key in this._object) { +      var value = this._object[key], pair = [key, value]; +      pair.key = key; +      pair.value = value; +      iterator(pair); +    } +  } -    set: function(key, value) { -      return this._object[key] = value; -    }, +  function set(key, value) { +    return this._object[key] = value; +  } -    get: function(key) { +  function get(key) { +    if (this._object[key] !== Object.prototype[key])        return this._object[key]; -    }, +  } -    unset: function(key) { -      var value = this._object[key]; -      delete this._object[key]; -      return value; -    }, +  function unset(key) { +    var value = this._object[key]; +    delete this._object[key]; +    return value; +  } -    toObject: function() { -      return Object.clone(this._object); -    }, +  function toObject() { +    return Object.clone(this._object); +  } -    keys: function() { -      return this.pluck('key'); -    }, -    values: function() { -      return this.pluck('value'); -    }, -    index: function(value) { -      var match = this.detect(function(pair) { -        return pair.value === value; -      }); -      return match && match.key; -    }, +  function keys() { +    return this.pluck('key'); +  } -    merge: function(object) { -      return this.clone().update(object); -    }, +  function values() { +    return this.pluck('value'); +  } -    update: function(object) { -      return new Hash(object).inject(this, function(result, pair) { -        result.set(pair.key, pair.value); -        return result; -      }); -    }, +  function index(value) { +    var match = this.detect(function(pair) { +      return pair.value === value; +    }); +    return match && match.key; +  } -    toQueryString: function() { -      return this.map(function(pair) { -        var key = encodeURIComponent(pair.key), values = pair.value; +  function merge(object) { +    return this.clone().update(object); +  } -        if (values && typeof values == 'object') { -          if (Object.isArray(values)) -            return values.map(toQueryPair.curry(key)).join('&'); -        } -        return toQueryPair(key, values); -      }).join('&'); -    }, +  function update(object) { +    return new Hash(object).inject(this, function(result, pair) { +      result.set(pair.key, pair.value); +      return result; +    }); +  } -    inspect: function() { -      return '#<Hash:{' + this.map(function(pair) { -        return pair.map(Object.inspect).join(': '); -      }).join(', ') + '}>'; -    }, +  function toQueryPair(key, value) { +    if (Object.isUndefined(value)) return key; +    return key + '=' + encodeURIComponent(String.interpret(value)); +  } -    toJSON: function() { -      return Object.toJSON(this.toObject()); -    }, +  function toQueryString() { +    return this.inject([], function(results, pair) { +      var key = encodeURIComponent(pair.key), values = pair.value; -    clone: function() { -      return new Hash(this); -    } +      if (values && typeof values == 'object') { +        if (Object.isArray(values)) +          return results.concat(values.map(toQueryPair.curry(key))); +      } else results.push(toQueryPair(key, values)); +      return results; +    }).join('&'); +  } + +  function inspect() { +    return '#<Hash:{' + this.map(function(pair) { +      return pair.map(Object.inspect).join(': '); +    }).join(', ') + '}>'; +  } + +  function clone() { +    return new Hash(this);    } + +  return { +    initialize:             initialize, +    _each:                  _each, +    set:                    set, +    get:                    get, +    unset:                  unset, +    toObject:               toObject, +    toTemplateReplacements: toObject, +    keys:                   keys, +    values:                 values, +    index:                  index, +    merge:                  merge, +    update:                 update, +    toQueryString:          toQueryString, +    inspect:                inspect, +    toJSON:                 toObject, +    clone:                  clone +  };  })()); -Hash.prototype.toTemplateReplacements = Hash.prototype.toObject;  Hash.from = $H; -var ObjectRange = Class.create(Enumerable, { -  initialize: function(start, end, exclusive) { +Object.extend(Number.prototype, (function() { +  function toColorPart() { +    return this.toPaddedString(2, 16); +  } + +  function succ() { +    return this + 1; +  } + +  function times(iterator, context) { +    $R(0, this, true).each(iterator, context); +    return this; +  } + +  function toPaddedString(length, radix) { +    var string = this.toString(radix || 10); +    return '0'.times(length - string.length) + string; +  } + +  function abs() { +    return Math.abs(this); +  } + +  function round() { +    return Math.round(this); +  } + +  function ceil() { +    return Math.ceil(this); +  } + +  function floor() { +    return Math.floor(this); +  } + +  return { +    toColorPart:    toColorPart, +    succ:           succ, +    times:          times, +    toPaddedString: toPaddedString, +    abs:            abs, +    round:          round, +    ceil:           ceil, +    floor:          floor +  }; +})()); + +function $R(start, end, exclusive) { +  return new ObjectRange(start, end, exclusive); +} + +var ObjectRange = Class.create(Enumerable, (function() { +  function initialize(start, end, exclusive) {      this.start = start;      this.end = end;      this.exclusive = exclusive; -  }, +  } -  _each: function(iterator) { +  function _each(iterator) {      var value = this.start;      while (this.include(value)) {        iterator(value);        value = value.succ();      } -  }, +  } -  include: function(value) { +  function include(value) {      if (value < this.start)        return false;      if (this.exclusive)        return value < this.end;      return value <= this.end;    } -}); -var $R = function(start, end, exclusive) { -  return new ObjectRange(start, end, exclusive); -}; +  return { +    initialize: initialize, +    _each:      _each, +    include:    include +  }; +})()); + +  var Ajax = {    getTransport: function() { @@ -1152,7 +1453,6 @@ Ajax.Responders.register({    onCreate:   function() { Ajax.activeRequestCount++ },    onComplete: function() { Ajax.activeRequestCount-- }  }); -  Ajax.Base = Class.create({    initialize: function(options) {      this.options = { @@ -1174,7 +1474,6 @@ Ajax.Base = Class.create({        this.options.parameters = this.options.parameters.toObject();    }  }); -  Ajax.Request = Class.create(Ajax.Base, {    _complete: false, @@ -1190,7 +1489,6 @@ Ajax.Request = Class.create(Ajax.Base, {      var params = Object.clone(this.options.parameters);      if (!['get', 'post'].include(this.method)) { -      // simulate other verbs over post        params['_method'] = this.method;        this.method = 'post';      } @@ -1198,7 +1496,6 @@ Ajax.Request = Class.create(Ajax.Base, {      this.parameters = params;      if (params = Object.toQueryString(params)) { -      // when GET, append parameters to URL        if (this.method == 'get')          this.url += (this.url.include('?') ? '&' : '?') + params;        else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) @@ -1257,7 +1554,6 @@ Ajax.Request = Class.create(Ajax.Base, {              headers['Connection'] = 'close';      } -    // user-defined headers      if (typeof this.options.requestHeaders == 'object') {        var extras = this.options.requestHeaders; @@ -1298,7 +1594,7 @@ Ajax.Request = Class.create(Ajax.Base, {        var contentType = response.getHeader('Content-type');        if (this.options.evalJS == 'force' -          || (this.options.evalJS && contentType +          || (this.options.evalJS && this.isSameOrigin() && contentType            && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))          this.evalResponse();      } @@ -1311,15 +1607,23 @@ Ajax.Request = Class.create(Ajax.Base, {      }      if (state == 'Complete') { -      // avoid memory leak in MSIE: clean up        this.transport.onreadystatechange = Prototype.emptyFunction;      }    }, +  isSameOrigin: function() { +    var m = this.url.match(/^\s*https?:\/\/[^\/]*/); +    return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({ +      protocol: location.protocol, +      domain: document.domain, +      port: location.port ? ':' + location.port : '' +    })); +  }, +    getHeader: function(name) {      try { -      return this.transport.getResponseHeader(name); -    } catch (e) { return null } +      return this.transport.getResponseHeader(name) || null; +    } catch (e) { return null; }    },    evalResponse: function() { @@ -1339,20 +1643,27 @@ Ajax.Request = Class.create(Ajax.Base, {  Ajax.Request.Events =    ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; + + + + + + +  Ajax.Response = Class.create({    initialize: function(request){      this.request = request;      var transport  = this.transport  = request.transport,          readyState = this.readyState = transport.readyState; -    if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) { +    if ((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {        this.status       = this.getStatus();        this.statusText   = this.getStatusText();        this.responseText = String.interpret(transport.responseText);        this.headerJSON   = this._getHeaderJSON();      } -    if(readyState == 4) { +    if (readyState == 4) {        var xml = transport.responseXML;        this.responseXML  = Object.isUndefined(xml) ? null : xml;        this.responseJSON = this._getResponseJSON(); @@ -1360,6 +1671,7 @@ Ajax.Response = Class.create({    },    status:      0, +    statusText: '',    getStatus: Ajax.Request.prototype.getStatus, @@ -1391,7 +1703,8 @@ Ajax.Response = Class.create({      if (!json) return null;      json = decodeURIComponent(escape(json));      try { -      return json.evalJSON(this.request.options.sanitizeJSON); +      return json.evalJSON(this.request.options.sanitizeJSON || +        !this.request.isSameOrigin());      } catch (e) {        this.request.dispatchException(e);      } @@ -1404,7 +1717,8 @@ Ajax.Response = Class.create({          this.responseText.blank())            return null;      try { -      return this.responseText.evalJSON(options.sanitizeJSON); +      return this.responseText.evalJSON(options.sanitizeJSON || +        !this.request.isSameOrigin());      } catch (e) {        this.request.dispatchException(e);      } @@ -1487,6 +1801,8 @@ Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {      this.updater = new Ajax.Updater(this.container, this.url, this.options);    }  }); + +  function $(element) {    if (arguments.length > 1) {      for (var i = 0, elements = [], length = arguments.length; i < length; i++) @@ -1511,10 +1827,9 @@ if (Prototype.BrowserFeatures.XPath) {  /*--------------------------------------------------------------------------*/ -if (!window.Node) var Node = { }; +if (!Node) var Node = { };  if (!Node.ELEMENT_NODE) { -  // DOM level 2 ECMAScript Language Binding    Object.extend(Node, {      ELEMENT_NODE: 1,      ATTRIBUTE_NODE: 2, @@ -1531,13 +1846,27 @@ if (!Node.ELEMENT_NODE) {    });  } -(function() { -  var element = this.Element; -  this.Element = function(tagName, attributes) { + + +(function(global) { + +  var HAS_EXTENDED_CREATE_ELEMENT_SYNTAX = (function(){ +    try { +      var el = document.createElement('<input name="x">'); +      return el.tagName.toLowerCase() === 'input' && el.name === 'x'; +    } +    catch(err) { +      return false; +    } +  })(); + +  var element = global.Element; + +  global.Element = function(tagName, attributes) {      attributes = attributes || { };      tagName = tagName.toLowerCase();      var cache = Element.cache; -    if (Prototype.Browser.IE && attributes.name) { +    if (HAS_EXTENDED_CREATE_ELEMENT_SYNTAX && attributes.name) {        tagName = '<' + tagName + ' name="' + attributes.name + '">';        delete attributes.name;        return Element.writeAttribute(document.createElement(tagName), attributes); @@ -1545,11 +1874,24 @@ if (!Node.ELEMENT_NODE) {      if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));      return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);    }; -  Object.extend(this.Element, element || { }); -}).call(window); +  Object.extend(global.Element, element || { }); +  if (element) global.Element.prototype = element.prototype; + +})(this); + +Element.idCounter = 1;  Element.cache = { }; +function purgeElement(element) { +  var uid = element._prototypeUID; +  if (uid) { +    Element.stopObserving(element); +    element._prototypeUID = void 0; +    delete Element.Storage[uid]; +  } +} +  Element.Methods = {    visible: function(element) {      return $(element).style.display != 'none'; @@ -1562,12 +1904,14 @@ Element.Methods = {    },    hide: function(element) { -    $(element).style.display = 'none'; +    element = $(element); +    element.style.display = 'none';      return element;    },    show: function(element) { -    $(element).style.display = ''; +    element = $(element); +    element.style.display = '';      return element;    }, @@ -1577,15 +1921,93 @@ Element.Methods = {      return element;    }, -  update: function(element, content) { -    element = $(element); -    if (content && content.toElement) content = content.toElement(); -    if (Object.isElement(content)) return element.update().insert(content); -    content = Object.toHTML(content); -    element.innerHTML = content.stripScripts(); -    content.evalScripts.bind(content).defer(); -    return element; -  }, +  update: (function(){ + +    var SELECT_ELEMENT_INNERHTML_BUGGY = (function(){ +      var el = document.createElement("select"), +          isBuggy = true; +      el.innerHTML = "<option value=\"test\">test</option>"; +      if (el.options && el.options[0]) { +        isBuggy = el.options[0].nodeName.toUpperCase() !== "OPTION"; +      } +      el = null; +      return isBuggy; +    })(); + +    var TABLE_ELEMENT_INNERHTML_BUGGY = (function(){ +      try { +        var el = document.createElement("table"); +        if (el && el.tBodies) { +          el.innerHTML = "<tbody><tr><td>test</td></tr></tbody>"; +          var isBuggy = typeof el.tBodies[0] == "undefined"; +          el = null; +          return isBuggy; +        } +      } catch (e) { +        return true; +      } +    })(); + +    var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () { +      var s = document.createElement("script"), +          isBuggy = false; +      try { +        s.appendChild(document.createTextNode("")); +        isBuggy = !s.firstChild || +          s.firstChild && s.firstChild.nodeType !== 3; +      } catch (e) { +        isBuggy = true; +      } +      s = null; +      return isBuggy; +    })(); + +    function update(element, content) { +      element = $(element); + +      var descendants = element.getElementsByTagName('*'), +       i = descendants.length; +      while (i--) purgeElement(descendants[i]); + +      if (content && content.toElement) +        content = content.toElement(); + +      if (Object.isElement(content)) +        return element.update().insert(content); + +      content = Object.toHTML(content); + +      var tagName = element.tagName.toUpperCase(); + +      if (tagName === 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) { +        element.text = content; +        return element; +      } + +      if (SELECT_ELEMENT_INNERHTML_BUGGY || TABLE_ELEMENT_INNERHTML_BUGGY) { +        if (tagName in Element._insertionTranslations.tags) { +          while (element.firstChild) { +            element.removeChild(element.firstChild); +          } +          Element._getContentFromAnonymousElement(tagName, content.stripScripts()) +            .each(function(node) { +              element.appendChild(node) +            }); +        } +        else { +          element.innerHTML = content.stripScripts(); +        } +      } +      else { +        element.innerHTML = content.stripScripts(); +      } + +      content.evalScripts.bind(content).defer(); +      return element; +    } + +    return update; +  })(),    replace: function(element, content) {      element = $(element); @@ -1608,24 +2030,28 @@ Element.Methods = {          Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))            insertions = {bottom:insertions}; -    var content, t, range; +    var content, insert, tagName, childNodes; -    for (position in insertions) { +    for (var position in insertions) {        content  = insertions[position];        position = position.toLowerCase(); -      t = Element._insertionTranslations[position]; +      insert = Element._insertionTranslations[position];        if (content && content.toElement) content = content.toElement();        if (Object.isElement(content)) { -        t.insert(element, content); +        insert(element, content);          continue;        }        content = Object.toHTML(content); -      range = element.ownerDocument.createRange(); -      t.initializeRange(element, range); -      t.insert(element, range.createContextualFragment(content.stripScripts())); +      tagName = ((position == 'before' || position == 'after') +        ? element.parentNode : element).tagName.toUpperCase(); + +      childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); + +      if (position == 'top' || position == 'after') childNodes.reverse(); +      childNodes.each(insert.curry(element));        content.evalScripts.bind(content).defer();      } @@ -1649,28 +2075,35 @@ Element.Methods = {      element = $(element);      var result = '<' + element.tagName.toLowerCase();      $H({'id': 'id', 'className': 'class'}).each(function(pair) { -      var property = pair.first(), attribute = pair.last(); -      var value = (element[property] || '').toString(); +      var property = pair.first(), +          attribute = pair.last(), +          value = (element[property] || '').toString();        if (value) result += ' ' + attribute + '=' + value.inspect(true);      });      return result + '>';    }, -  recursivelyCollect: function(element, property) { +  recursivelyCollect: function(element, property, maximumLength) {      element = $(element); +    maximumLength = maximumLength || -1;      var elements = []; -    while (element = element[property]) + +    while (element = element[property]) {        if (element.nodeType == 1)          elements.push(Element.extend(element)); +      if (elements.length == maximumLength) +        break; +    } +      return elements;    },    ancestors: function(element) { -    return $(element).recursivelyCollect('parentNode'); +    return Element.recursivelyCollect(element, 'parentNode');    },    descendants: function(element) { -    return $(element).getElementsBySelector("*"); +    return Element.select(element, "*");    },    firstDescendant: function(element) { @@ -1680,79 +2113,96 @@ Element.Methods = {    },    immediateDescendants: function(element) { -    if (!(element = $(element).firstChild)) return []; -    while (element && element.nodeType != 1) element = element.nextSibling; -    if (element) return [element].concat($(element).nextSiblings()); -    return []; +    var results = [], child = $(element).firstChild; +    while (child) { +      if (child.nodeType === 1) { +        results.push(Element.extend(child)); +      } +      child = child.nextSibling; +    } +    return results;    }, -  previousSiblings: function(element) { -    return $(element).recursivelyCollect('previousSibling'); +  previousSiblings: function(element, maximumLength) { +    return Element.recursivelyCollect(element, 'previousSibling');    },    nextSiblings: function(element) { -    return $(element).recursivelyCollect('nextSibling'); +    return Element.recursivelyCollect(element, 'nextSibling');    },    siblings: function(element) {      element = $(element); -    return element.previousSiblings().reverse().concat(element.nextSiblings()); +    return Element.previousSiblings(element).reverse() +      .concat(Element.nextSiblings(element));    },    match: function(element, selector) { +    element = $(element);      if (Object.isString(selector)) -      selector = new Selector(selector); -    return selector.match($(element)); +      return Prototype.Selector.match(element, selector); +    return selector.match(element);    },    up: function(element, expression, index) {      element = $(element);      if (arguments.length == 1) return $(element.parentNode); -    var ancestors = element.ancestors(); -    return expression ? Selector.findElement(ancestors, expression, index) : -      ancestors[index || 0]; +    var ancestors = Element.ancestors(element); +    return Object.isNumber(expression) ? ancestors[expression] : +      Prototype.Selector.find(ancestors, expression, index);    },    down: function(element, expression, index) {      element = $(element); -    if (arguments.length == 1) return element.firstDescendant(); -    var descendants = element.descendants(); -    return expression ? Selector.findElement(descendants, expression, index) : -      descendants[index || 0]; +    if (arguments.length == 1) return Element.firstDescendant(element); +    return Object.isNumber(expression) ? Element.descendants(element)[expression] : +      Element.select(element, expression)[index || 0];    },    previous: function(element, expression, index) {      element = $(element); -    if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element)); -    var previousSiblings = element.previousSiblings(); -    return expression ? Selector.findElement(previousSiblings, expression, index) : -      previousSiblings[index || 0]; +    if (Object.isNumber(expression)) index = expression, expression = false; +    if (!Object.isNumber(index)) index = 0; + +    if (expression) { +      return Prototype.Selector.find(element.previousSiblings(), expression, index); +    } else { +      return element.recursivelyCollect("previousSibling", index + 1)[index]; +    }    },    next: function(element, expression, index) {      element = $(element); -    if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element)); -    var nextSiblings = element.nextSiblings(); -    return expression ? Selector.findElement(nextSiblings, expression, index) : -      nextSiblings[index || 0]; +    if (Object.isNumber(expression)) index = expression, expression = false; +    if (!Object.isNumber(index)) index = 0; + +    if (expression) { +      return Prototype.Selector.find(element.nextSiblings(), expression, index); +    } else { +      var maximumLength = Object.isNumber(index) ? index + 1 : 1; +      return element.recursivelyCollect("nextSibling", index + 1)[index]; +    }    }, -  select: function() { -    var args = $A(arguments), element = $(args.shift()); -    return Selector.findChildElements(element, args); + +  select: function(element) { +    element = $(element); +    var expressions = Array.prototype.slice.call(arguments, 1).join(', '); +    return Prototype.Selector.select(expressions, element);    }, -  adjacent: function() { -    var args = $A(arguments), element = $(args.shift()); -    return Selector.findChildElements(element.parentNode, args).without(element); +  adjacent: function(element) { +    element = $(element); +    var expressions = Array.prototype.slice.call(arguments, 1).join(', '); +    return Prototype.Selector.select(expressions, element.parentNode).without(element);    },    identify: function(element) {      element = $(element); -    var id = element.readAttribute('id'), self = arguments.callee; +    var id = Element.readAttribute(element, 'id');      if (id) return id; -    do { id = 'anonymous_element_' + self.counter++ } while ($(id)); -    element.writeAttribute('id', id); +    do { id = 'anonymous_element_' + Element.idCounter++ } while ($(id)); +    Element.writeAttribute(element, 'id', id);      return id;    }, @@ -1791,11 +2241,11 @@ Element.Methods = {    },    getHeight: function(element) { -    return $(element).getDimensions().height; +    return Element.getDimensions(element).height;    },    getWidth: function(element) { -    return $(element).getDimensions().width; +    return Element.getDimensions(element).width;    },    classNames: function(element) { @@ -1811,7 +2261,7 @@ Element.Methods = {    addClassName: function(element, className) {      if (!(element = $(element))) return; -    if (!element.hasClassName(className)) +    if (!Element.hasClassName(element, className))        element.className += (element.className ? ' ' : '') + className;      return element;    }, @@ -1825,11 +2275,10 @@ Element.Methods = {    toggleClassName: function(element, className) {      if (!(element = $(element))) return; -    return element[element.hasClassName(className) ? -      'removeClassName' : 'addClassName'](className); +    return Element[Element.hasClassName(element, className) ? +      'removeClassName' : 'addClassName'](element, className);    }, -  // removes whitespace-only text node children    cleanWhitespace: function(element) {      element = $(element);      var node = element.firstChild; @@ -1848,29 +2297,22 @@ Element.Methods = {    descendantOf: function(element, ancestor) {      element = $(element), ancestor = $(ancestor); -    var originalAncestor = ancestor;      if (element.compareDocumentPosition)        return (element.compareDocumentPosition(ancestor) & 8) === 8; -    if (element.sourceIndex && !Prototype.Browser.Opera) { -      var e = element.sourceIndex, a = ancestor.sourceIndex, -       nextAncestor = ancestor.nextSibling; -      if (!nextAncestor) { -        do { ancestor = ancestor.parentNode; } -        while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode); -      } -      if (nextAncestor) return (e > a && e < nextAncestor.sourceIndex); -    } +    if (ancestor.contains) +      return ancestor.contains(element) && ancestor !== element;      while (element = element.parentNode) -      if (element == originalAncestor) return true; +      if (element == ancestor) return true; +      return false;    },    scrollTo: function(element) {      element = $(element); -    var pos = element.cumulativeOffset(); +    var pos = Element.cumulativeOffset(element);      window.scrollTo(pos[0], pos[1]);      return element;    }, @@ -1879,7 +2321,7 @@ Element.Methods = {      element = $(element);      style = style == 'float' ? 'cssFloat' : style.camelize();      var value = element.style[style]; -    if (!value) { +    if (!value || value == 'auto') {        var css = document.defaultView.getComputedStyle(element, null);        value = css ? css[style] : null;      } @@ -1916,38 +2358,13 @@ Element.Methods = {      return element;    }, -  getDimensions: function(element) { -    element = $(element); -    var display = $(element).getStyle('display'); -    if (display != 'none' && display != null) // Safari bug -      return {width: element.offsetWidth, height: element.offsetHeight}; - -    // All *Width and *Height properties give 0 on elements with display none, -    // so enable the element temporarily -    var els = element.style; -    var originalVisibility = els.visibility; -    var originalPosition = els.position; -    var originalDisplay = els.display; -    els.visibility = 'hidden'; -    els.position = 'absolute'; -    els.display = 'block'; -    var originalWidth = element.clientWidth; -    var originalHeight = element.clientHeight; -    els.display = originalDisplay; -    els.position = originalPosition; -    els.visibility = originalVisibility; -    return {width: originalWidth, height: originalHeight}; -  }, -    makePositioned: function(element) {      element = $(element);      var pos = Element.getStyle(element, 'position');      if (pos == 'static' || !pos) {        element._madePositioned = true;        element.style.position = 'relative'; -      // Opera returns the offset relative to the positioning context, when an -      // element is position relative but top and left have not been defined -      if (window.opera) { +      if (Prototype.Browser.Opera) {          element.style.top = 0;          element.style.left = 0;        } @@ -1987,11 +2404,13 @@ Element.Methods = {    cumulativeOffset: function(element) {      var valueT = 0, valueL = 0; -    do { -      valueT += element.offsetTop  || 0; -      valueL += element.offsetLeft || 0; -      element = element.offsetParent; -    } while (element); +    if (element.parentNode) { +      do { +        valueT += element.offsetTop  || 0; +        valueL += element.offsetLeft || 0; +        element = element.offsetParent; +      } while (element); +    }      return Element._returnOffset(valueL, valueT);    }, @@ -2002,9 +2421,9 @@ Element.Methods = {        valueL += element.offsetLeft || 0;        element = element.offsetParent;        if (element) { -        if (element.tagName == 'BODY') break; +        if (element.tagName.toUpperCase() == 'BODY') break;          var p = Element.getStyle(element, 'position'); -        if (p == 'relative' || p == 'absolute') break; +        if (p !== 'static') break;        }      } while (element);      return Element._returnOffset(valueL, valueT); @@ -2012,14 +2431,13 @@ Element.Methods = {    absolutize: function(element) {      element = $(element); -    if (element.getStyle('position') == 'absolute') return; -    // Position.prepare(); // To be done manually by Scripty when it needs it. +    if (Element.getStyle(element, 'position') == 'absolute') return element; -    var offsets = element.positionedOffset(); -    var top     = offsets[1]; -    var left    = offsets[0]; -    var width   = element.clientWidth; -    var height  = element.clientHeight; +    var offsets = Element.positionedOffset(element), +        top     = offsets[1], +        left    = offsets[0], +        width   = element.clientWidth, +        height  = element.clientHeight;      element._originalLeft   = left - parseFloat(element.style.left  || 0);      element._originalTop    = top  - parseFloat(element.style.top || 0); @@ -2036,12 +2454,11 @@ Element.Methods = {    relativize: function(element) {      element = $(element); -    if (element.getStyle('position') == 'relative') return; -    // Position.prepare(); // To be done manually by Scripty when it needs it. +    if (Element.getStyle(element, 'position') == 'relative') return element;      element.style.position = 'relative'; -    var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0); -    var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); +    var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0), +        left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);      element.style.top    = top + 'px';      element.style.left   = left + 'px'; @@ -2072,14 +2489,14 @@ Element.Methods = {    },    viewportOffset: function(forElement) { -    var valueT = 0, valueL = 0; +    var valueT = 0, +        valueL = 0, +        element = forElement; -    var element = forElement;      do {        valueT += element.offsetTop  || 0;        valueL += element.offsetLeft || 0; -      // Safari fix        if (element.offsetParent == document.body &&          Element.getStyle(element, 'position') == 'absolute') break; @@ -2087,7 +2504,7 @@ Element.Methods = {      element = forElement;      do { -      if (!Prototype.Browser.Opera || element.tagName == 'BODY') { +      if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) {          valueT -= element.scrollTop  || 0;          valueL -= element.scrollLeft || 0;        } @@ -2106,28 +2523,21 @@ Element.Methods = {        offsetLeft: 0      }, arguments[2] || { }); -    // find page position of source      source = $(source); -    var p = source.viewportOffset(); +    var p = Element.viewportOffset(source), delta = [0, 0], parent = null; -    // find coordinate system to use      element = $(element); -    var delta = [0, 0]; -    var parent = null; -    // delta [0,0] will do fine with position: fixed elements, -    // position:absolute needs offsetParent deltas +      if (Element.getStyle(element, 'position') == 'absolute') { -      parent = element.getOffsetParent(); -      delta = parent.viewportOffset(); +      parent = Element.getOffsetParent(element); +      delta = Element.viewportOffset(parent);      } -    // correct by body offsets (fixes Safari)      if (parent == document.body) {        delta[0] -= document.body.offsetLeft;        delta[1] -= document.body.offsetTop;      } -    // set position      if (options.setLeft)   element.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';      if (options.setTop)    element.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';      if (options.setWidth)  element.style.width = source.offsetWidth + 'px'; @@ -2136,10 +2546,9 @@ Element.Methods = {    }  }; -Element.Methods.identify.counter = 1; -  Object.extend(Element.Methods, {    getElementsBySelector: Element.Methods.select, +    childElements: Element.Methods.immediateDescendants  }); @@ -2153,46 +2562,6 @@ Element._attributeTranslations = {    }  }; - -if (!document.createRange || Prototype.Browser.Opera) { -  Element.Methods.insert = function(element, insertions) { -    element = $(element); - -    if (Object.isString(insertions) || Object.isNumber(insertions) || -        Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML))) -          insertions = { bottom: insertions }; - -    var t = Element._insertionTranslations, content, position, pos, tagName; - -    for (position in insertions) { -      content  = insertions[position]; -      position = position.toLowerCase(); -      pos      = t[position]; - -      if (content && content.toElement) content = content.toElement(); -      if (Object.isElement(content)) { -        pos.insert(element, content); -        continue; -      } - -      content = Object.toHTML(content); -      tagName = ((position == 'before' || position == 'after') -        ? element.parentNode : element).tagName.toUpperCase(); - -      if (t.tags[tagName]) { -        var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); -        if (position == 'top' || position == 'after') fragments.reverse(); -        fragments.each(pos.insert.curry(element)); -      } -      else element.insertAdjacentHTML(pos.adjacency, content.stripScripts()); - -      content.evalScripts.bind(content).defer(); -    } - -    return element; -  }; -} -  if (Prototype.Browser.Opera) {    Element.Methods.getStyle = Element.Methods.getStyle.wrap(      function(proceed, element, style) { @@ -2200,11 +2569,8 @@ if (Prototype.Browser.Opera) {          case 'left': case 'top': case 'right': case 'bottom':            if (proceed(element, 'position') === 'static') return null;          case 'height': case 'width': -          // returns '0px' for hidden elements; we want it to return null            if (!Element.visible(element)) return null; -          // returns the border-box dimensions rather than the content-box -          // dimensions, so we subtract padding and borders from the value            var dim = parseInt(proceed(element, style), 10);            if (dim !== element['offset' + style.capitalize()]) @@ -2237,12 +2603,29 @@ if (Prototype.Browser.Opera) {  }  else if (Prototype.Browser.IE) { -  $w('positionedOffset getOffsetParent viewportOffset').each(function(method) { +  Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap( +    function(proceed, element) { +      element = $(element); +      if (!element.parentNode) return $(document.body); +      var position = element.getStyle('position'); +      if (position !== 'static') return proceed(element); +      element.setStyle({ position: 'relative' }); +      var value = proceed(element); +      element.setStyle({ position: position }); +      return value; +    } +  ); + +  $w('positionedOffset viewportOffset').each(function(method) {      Element.Methods[method] = Element.Methods[method].wrap(        function(proceed, element) {          element = $(element); +        if (!element.parentNode) return Element._returnOffset(0, 0);          var position = element.getStyle('position'); -        if (position != 'static') return proceed(element); +        if (position !== 'static') return proceed(element); +        var offsetParent = element.getOffsetParent(); +        if (offsetParent && offsetParent.getStyle('position') === 'fixed') +          offsetParent.setStyle({ zoom: 1 });          element.setStyle({ position: 'relative' });          var value = proceed(element);          element.setStyle({ position: position }); @@ -2292,39 +2675,96 @@ else if (Prototype.Browser.IE) {      return element;    }; -  Element._attributeTranslations = { -    read: { -      names: { -        'class': 'className', -        'for':   'htmlFor' -      }, -      values: { -        _getAttr: function(element, attribute) { -          return element.getAttribute(attribute, 2); -        }, -        _getAttrNode: function(element, attribute) { -          var node = element.getAttributeNode(attribute); -          return node ? node.value : ""; -        }, -        _getEv: function(element, attribute) { -          attribute = element.getAttribute(attribute); -          return attribute ? attribute.toString().slice(23, -2) : null; -        }, -        _flag: function(element, attribute) { -          return $(element).hasAttribute(attribute) ? attribute : null; -        }, -        style: function(element) { -          return element.style.cssText.toLowerCase(); +  Element._attributeTranslations = (function(){ + +    var classProp = 'className', +        forProp = 'for', +        el = document.createElement('div'); + +    el.setAttribute(classProp, 'x'); + +    if (el.className !== 'x') { +      el.setAttribute('class', 'x'); +      if (el.className === 'x') { +        classProp = 'class'; +      } +    } +    el = null; + +    el = document.createElement('label'); +    el.setAttribute(forProp, 'x'); +    if (el.htmlFor !== 'x') { +      el.setAttribute('htmlFor', 'x'); +      if (el.htmlFor === 'x') { +        forProp = 'htmlFor'; +      } +    } +    el = null; + +    return { +      read: { +        names: { +          'class':      classProp, +          'className':  classProp, +          'for':        forProp, +          'htmlFor':    forProp          }, -        title: function(element) { -          return element.title; +        values: { +          _getAttr: function(element, attribute) { +            return element.getAttribute(attribute); +          }, +          _getAttr2: function(element, attribute) { +            return element.getAttribute(attribute, 2); +          }, +          _getAttrNode: function(element, attribute) { +            var node = element.getAttributeNode(attribute); +            return node ? node.value : ""; +          }, +          _getEv: (function(){ + +            var el = document.createElement('div'), f; +            el.onclick = Prototype.emptyFunction; +            var value = el.getAttribute('onclick'); + +            if (String(value).indexOf('{') > -1) { +              f = function(element, attribute) { +                attribute = element.getAttribute(attribute); +                if (!attribute) return null; +                attribute = attribute.toString(); +                attribute = attribute.split('{')[1]; +                attribute = attribute.split('}')[0]; +                return attribute.strip(); +              }; +            } +            else if (value === '') { +              f = function(element, attribute) { +                attribute = element.getAttribute(attribute); +                if (!attribute) return null; +                return attribute.strip(); +              }; +            } +            el = null; +            return f; +          })(), +          _flag: function(element, attribute) { +            return $(element).hasAttribute(attribute) ? attribute : null; +          }, +          style: function(element) { +            return element.style.cssText.toLowerCase(); +          }, +          title: function(element) { +            return element.title; +          }          }        }      } -  }; +  })();    Element._attributeTranslations.write = { -    names: Object.clone(Element._attributeTranslations.read.names), +    names: Object.extend({ +      cellpadding: 'cellPadding', +      cellspacing: 'cellSpacing' +    }, Element._attributeTranslations.read.names),      values: {        checked: function(element, value) {          element.checked = !!value; @@ -2339,15 +2779,15 @@ else if (Prototype.Browser.IE) {    Element._attributeTranslations.has = {};    $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' + -      'encType maxLength readOnly longDesc').each(function(attr) { +      'encType maxLength readOnly longDesc frameBorder').each(function(attr) {      Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;      Element._attributeTranslations.has[attr.toLowerCase()] = attr;    });    (function(v) {      Object.extend(v, { -      href:        v._getAttr, -      src:         v._getAttr, +      href:        v._getAttr2, +      src:         v._getAttr2,        type:        v._getAttr,        action:      v._getAttrNode,        disabled:    v._flag, @@ -2374,6 +2814,26 @@ else if (Prototype.Browser.IE) {        onchange:    v._getEv      });    })(Element._attributeTranslations.read.values); + +  if (Prototype.BrowserFeatures.ElementExtensions) { +    (function() { +      function _descendants(element) { +        var nodes = element.getElementsByTagName('*'), results = []; +        for (var i = 0, node; node = nodes[i]; i++) +          if (node.tagName !== "!") // Filter out comment nodes. +            results.push(node); +        return results; +      } + +      Element.Methods.down = function(element, expression, index) { +        element = $(element); +        if (arguments.length == 1) return element.firstDescendant(); +        return Object.isNumber(expression) ? _descendants(element)[expression] : +          Element.select(element, expression)[index || 0]; +      } +    })(); +  } +  }  else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) { @@ -2392,7 +2852,7 @@ else if (Prototype.Browser.WebKit) {        (value < 0.00001) ? 0 : value;      if (value == 1) -      if(element.tagName == 'IMG' && element.width) { +      if (element.tagName.toUpperCase() == 'IMG' && element.width) {          element.width++; element.width--;        } else try {          var n = document.createTextNode(' '); @@ -2403,9 +2863,6 @@ else if (Prototype.Browser.WebKit) {      return element;    }; -  // Safari returns margins on body which is incorrect if the child is absolutely -  // positioned.  For performance reasons, redefine Element#cumulativeOffset for -  // KHTML/WebKit only.    Element.Methods.cumulativeOffset = function(element) {      var valueT = 0, valueL = 0;      do { @@ -2421,30 +2878,7 @@ else if (Prototype.Browser.WebKit) {    };  } -if (Prototype.Browser.IE || Prototype.Browser.Opera) { -  // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements -  Element.Methods.update = function(element, content) { -    element = $(element); - -    if (content && content.toElement) content = content.toElement(); -    if (Object.isElement(content)) return element.update().insert(content); - -    content = Object.toHTML(content); -    var tagName = element.tagName.toUpperCase(); - -    if (tagName in Element._insertionTranslations.tags) { -      $A(element.childNodes).each(function(node) { element.removeChild(node) }); -      Element._getContentFromAnonymousElement(tagName, content.stripScripts()) -        .each(function(node) { element.appendChild(node) }); -    } -    else element.innerHTML = content.stripScripts(); - -    content.evalScripts.bind(content).defer(); -    return element; -  }; -} - -if (document.createElement('div').outerHTML) { +if ('outerHTML' in document.documentElement) {    Element.Methods.replace = function(element, content) {      element = $(element); @@ -2458,8 +2892,8 @@ if (document.createElement('div').outerHTML) {      var parent = element.parentNode, tagName = parent.tagName.toUpperCase();      if (Element._insertionTranslations.tags[tagName]) { -      var nextSibling = element.next(); -      var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); +      var nextSibling = element.next(), +          fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());        parent.removeChild(element);        if (nextSibling)          fragments.each(function(node) { parent.insertBefore(node, nextSibling) }); @@ -2481,46 +2915,32 @@ Element._returnOffset = function(l, t) {  };  Element._getContentFromAnonymousElement = function(tagName, html) { -  var div = new Element('div'), t = Element._insertionTranslations.tags[tagName]; -  div.innerHTML = t[0] + html + t[1]; -  t[2].times(function() { div = div.firstChild }); +  var div = new Element('div'), +      t = Element._insertionTranslations.tags[tagName]; +  if (t) { +    div.innerHTML = t[0] + html + t[1]; +    for (var i = t[2]; i--; ) { +      div = div.firstChild; +    } +  } +  else { +    div.innerHTML = html; +  }    return $A(div.childNodes);  };  Element._insertionTranslations = { -  before: { -    adjacency: 'beforeBegin', -    insert: function(element, node) { -      element.parentNode.insertBefore(node, element); -    }, -    initializeRange: function(element, range) { -      range.setStartBefore(element); -    } +  before: function(element, node) { +    element.parentNode.insertBefore(node, element);    }, -  top: { -    adjacency: 'afterBegin', -    insert: function(element, node) { -      element.insertBefore(node, element.firstChild); -    }, -    initializeRange: function(element, range) { -      range.selectNodeContents(element); -      range.collapse(true); -    } +  top: function(element, node) { +    element.insertBefore(node, element.firstChild);    }, -  bottom: { -    adjacency: 'beforeEnd', -    insert: function(element, node) { -      element.appendChild(node); -    } +  bottom: function(element, node) { +    element.appendChild(node);    }, -  after: { -    adjacency: 'afterEnd', -    insert: function(element, node) { -      element.parentNode.insertBefore(node, element.nextSibling); -    }, -    initializeRange: function(element, range) { -      range.setStartAfter(element); -    } +  after: function(element, node) { +    element.parentNode.insertBefore(node, element.nextSibling);    },    tags: {      TABLE:  ['<table>',                '</table>',                   1], @@ -2532,19 +2952,19 @@ Element._insertionTranslations = {  };  (function() { -  this.bottom.initializeRange = this.top.initializeRange; -  Object.extend(this.tags, { -    THEAD: this.tags.TBODY, -    TFOOT: this.tags.TBODY, -    TH:    this.tags.TD +  var tags = Element._insertionTranslations.tags; +  Object.extend(tags, { +    THEAD: tags.TBODY, +    TFOOT: tags.TBODY, +    TH:    tags.TD    }); -}).call(Element._insertionTranslations); +})();  Element.Methods.Simulated = {    hasAttribute: function(element, attribute) {      attribute = Element._attributeTranslations.has[attribute] || attribute;      var node = $(element).getAttributeNode(attribute); -    return node && node.specified; +    return !!(node && node.specified);    }  }; @@ -2552,41 +2972,81 @@ Element.Methods.ByTag = { };  Object.extend(Element, Element.Methods); -if (!Prototype.BrowserFeatures.ElementExtensions && -    document.createElement('div').__proto__) { -  window.HTMLElement = { }; -  window.HTMLElement.prototype = document.createElement('div').__proto__; -  Prototype.BrowserFeatures.ElementExtensions = true; -} +(function(div) { + +  if (!Prototype.BrowserFeatures.ElementExtensions && div['__proto__']) { +    window.HTMLElement = { }; +    window.HTMLElement.prototype = div['__proto__']; +    Prototype.BrowserFeatures.ElementExtensions = true; +  } + +  div = null; + +})(document.createElement('div'));  Element.extend = (function() { -  if (Prototype.BrowserFeatures.SpecificElementExtensions) + +  function checkDeficiency(tagName) { +    if (typeof window.Element != 'undefined') { +      var proto = window.Element.prototype; +      if (proto) { +        var id = '_' + (Math.random()+'').slice(2), +            el = document.createElement(tagName); +        proto[id] = 'x'; +        var isBuggy = (el[id] !== 'x'); +        delete proto[id]; +        el = null; +        return isBuggy; +      } +    } +    return false; +  } + +  function extendElementWith(element, methods) { +    for (var property in methods) { +      var value = methods[property]; +      if (Object.isFunction(value) && !(property in element)) +        element[property] = value.methodize(); +    } +  } + +  var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY = checkDeficiency('object'); + +  if (Prototype.BrowserFeatures.SpecificElementExtensions) { +    if (HTMLOBJECTELEMENT_PROTOTYPE_BUGGY) { +      return function(element) { +        if (element && typeof element._extendedByPrototype == 'undefined') { +          var t = element.tagName; +          if (t && (/^(?:object|applet|embed)$/i.test(t))) { +            extendElementWith(element, Element.Methods); +            extendElementWith(element, Element.Methods.Simulated); +            extendElementWith(element, Element.Methods.ByTag[t.toUpperCase()]); +          } +        } +        return element; +      } +    }      return Prototype.K; +  }    var Methods = { }, ByTag = Element.Methods.ByTag;    var extend = Object.extend(function(element) { -    if (!element || element._extendedByPrototype || +    if (!element || typeof element._extendedByPrototype != 'undefined' ||          element.nodeType != 1 || element == window) return element;      var methods = Object.clone(Methods), -      tagName = element.tagName, property, value; +        tagName = element.tagName.toUpperCase(); -    // extend methods for specific tags      if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]); -    for (property in methods) { -      value = methods[property]; -      if (Object.isFunction(value) && !(property in element)) -        element[property] = value.methodize(); -    } +    extendElementWith(element, methods);      element._extendedByPrototype = Prototype.emptyFunction;      return element;    }, {      refresh: function() { -      // extend methods for all tags (Safari doesn't need this)        if (!Prototype.BrowserFeatures.ElementExtensions) {          Object.extend(Methods, Element.Methods);          Object.extend(Methods, Element.Methods.Simulated); @@ -2598,10 +3058,14 @@ Element.extend = (function() {    return extend;  })(); -Element.hasAttribute = function(element, attribute) { -  if (element.hasAttribute) return element.hasAttribute(attribute); -  return Element.Methods.Simulated.hasAttribute(element, attribute); -}; +if (document.documentElement.hasAttribute) { +  Element.hasAttribute = function(element, attribute) { +    return element.hasAttribute(attribute); +  }; +} +else { +  Element.hasAttribute = Element.Methods.Simulated.hasAttribute; +}  Element.addMethods = function(methods) {    var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; @@ -2665,14 +3129,19 @@ Element.addMethods = function(methods) {      klass = 'HTML' + tagName.capitalize() + 'Element';      if (window[klass]) return window[klass]; -    window[klass] = { }; -    window[klass].prototype = document.createElement(tagName).__proto__; -    return window[klass]; +    var element = document.createElement(tagName), +        proto = element['__proto__'] || element.constructor.prototype; + +    element = null; +    return proto;    } +  var elementPrototype = window.HTMLElement ? HTMLElement.prototype : +   Element.prototype; +    if (F.ElementExtensions) { -    copy(Element.Methods, HTMLElement.prototype); -    copy(Element.Methods.Simulated, HTMLElement.prototype, true); +    copy(Element.Methods, elementPrototype); +    copy(Element.Methods.Simulated, elementPrototype, true);    }    if (F.SpecificElementExtensions) { @@ -2690,697 +3159,1803 @@ Element.addMethods = function(methods) {    Element.cache = { };  }; -document.viewport = { -  getDimensions: function() { -    var dimensions = { }; -    var B = Prototype.Browser; -    $w('width height').each(function(d) { -      var D = d.capitalize(); -      dimensions[d] = (B.WebKit && !document.evaluate) ? self['inner' + D] : -        (B.Opera) ? document.body['client' + D] : document.documentElement['client' + D]; -    }); -    return dimensions; -  }, -  getWidth: function() { -    return this.getDimensions().width; -  }, +document.viewport = { -  getHeight: function() { -    return this.getDimensions().height; +  getDimensions: function() { +    return { width: this.getWidth(), height: this.getHeight() };    },    getScrollOffsets: function() {      return Element._returnOffset(        window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft, -      window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); +      window.pageYOffset || document.documentElement.scrollTop  || document.body.scrollTop);    }  }; -/* Portions of the Selector class are derived from Jack Slocum’s DomQuery, - * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style - * license.  Please see http://www.yui-ext.com/ for more information. */ -var Selector = Class.create({ -  initialize: function(expression) { -    this.expression = expression.strip(); -    this.compileMatcher(); -  }, +(function(viewport) { +  var B = Prototype.Browser, doc = document, element, property = {}; -  shouldUseXPath: function() { -    if (!Prototype.BrowserFeatures.XPath) return false; +  function getRootElement() { +    if (B.WebKit && !doc.evaluate) +      return document; -    var e = this.expression; +    if (B.Opera && window.parseFloat(window.opera.version()) < 9.5) +      return document.body; -    // Safari 3 chokes on :*-of-type and :empty -    if (Prototype.Browser.WebKit && -     (e.include("-of-type") || e.include(":empty"))) -      return false; +    return document.documentElement; +  } -    // XPath can't do namespaced attributes, nor can it read -    // the "checked" property from DOM nodes -    if ((/(\[[\w-]*?:|:checked)/).test(this.expression)) -      return false; +  function define(D) { +    if (!element) element = getRootElement(); -    return true; -  }, +    property[D] = 'client' + D; -  compileMatcher: function() { -    if (this.shouldUseXPath()) -      return this.compileXPathMatcher(); +    viewport['get' + D] = function() { return element[property[D]] }; +    return viewport['get' + D](); +  } -    var e = this.expression, ps = Selector.patterns, h = Selector.handlers, -        c = Selector.criteria, le, p, m; +  viewport.getWidth  = define.curry('Width'); -    if (Selector._cache[e]) { -      this.matcher = Selector._cache[e]; -      return; -    } +  viewport.getHeight = define.curry('Height'); +})(document.viewport); -    this.matcher = ["this.matcher = function(root) {", -                    "var r = root, h = Selector.handlers, c = false, n;"]; -    while (e && le != e && (/\S/).test(e)) { -      le = e; -      for (var i in ps) { -        p = ps[i]; -        if (m = e.match(p)) { -          this.matcher.push(Object.isFunction(c[i]) ? c[i](m) : -    	      new Template(c[i]).evaluate(m)); -          e = e.replace(m[0], ''); -          break; -        } -      } +Element.Storage = { +  UID: 1 +}; + +Element.addMethods({ +  getStorage: function(element) { +    if (!(element = $(element))) return; + +    var uid; +    if (element === window) { +      uid = 0; +    } else { +      if (typeof element._prototypeUID === "undefined") +        element._prototypeUID = Element.Storage.UID++; +      uid = element._prototypeUID;      } -    this.matcher.push("return h.unique(n);\n}"); -    eval(this.matcher.join('\n')); -    Selector._cache[this.expression] = this.matcher; +    if (!Element.Storage[uid]) +      Element.Storage[uid] = $H(); + +    return Element.Storage[uid];    }, -  compileXPathMatcher: function() { -    var e = this.expression, ps = Selector.patterns, -        x = Selector.xpath, le, m; +  store: function(element, key, value) { +    if (!(element = $(element))) return; -    if (Selector._cache[e]) { -      this.xpath = Selector._cache[e]; return; +    if (arguments.length === 2) { +      Element.getStorage(element).update(key); +    } else { +      Element.getStorage(element).set(key, value);      } -    this.matcher = ['.//*']; -    while (e && le != e && (/\S/).test(e)) { -      le = e; -      for (var i in ps) { -        if (m = e.match(ps[i])) { -          this.matcher.push(Object.isFunction(x[i]) ? x[i](m) : -            new Template(x[i]).evaluate(m)); -          e = e.replace(m[0], ''); -          break; -        } -      } +    return element; +  }, + +  retrieve: function(element, key, defaultValue) { +    if (!(element = $(element))) return; +    var hash = Element.getStorage(element), value = hash.get(key); + +    if (Object.isUndefined(value)) { +      hash.set(key, defaultValue); +      value = defaultValue;      } -    this.xpath = this.matcher.join(''); -    Selector._cache[this.expression] = this.xpath; +    return value;    }, -  findElements: function(root) { -    root = root || document; -    if (this.xpath) return document._getElementsByXPath(this.xpath, root); -    return this.matcher(root); +  clone: function(element, deep) { +    if (!(element = $(element))) return; +    var clone = element.cloneNode(deep); +    clone._prototypeUID = void 0; +    if (deep) { +      var descendants = Element.select(clone, '*'), +          i = descendants.length; +      while (i--) { +        descendants[i]._prototypeUID = void 0; +      } +    } +    return Element.extend(clone);    }, -  match: function(element) { -    this.tokens = []; +  purge: function(element) { +    if (!(element = $(element))) return; +    purgeElement(element); -    var e = this.expression, ps = Selector.patterns, as = Selector.assertions; -    var le, p, m; +    var descendants = element.getElementsByTagName('*'), +     i = descendants.length; -    while (e && le !== e && (/\S/).test(e)) { -      le = e; -      for (var i in ps) { -        p = ps[i]; -        if (m = e.match(p)) { -          // use the Selector.assertions methods unless the selector -          // is too complex. -          if (as[i]) { -            this.tokens.push([i, Object.clone(m)]); -            e = e.replace(m[0], ''); -          } else { -            // reluctantly do a document-wide search -            // and look for a match in the array -            return this.findElements(document).include(element); -          } -        } -      } +    while (i--) purgeElement(descendants[i]); + +    return null; +  } +}); + +(function() { + +  function toDecimal(pctString) { +    var match = pctString.match(/^(\d+)%?$/i); +    if (!match) return null; +    return (Number(match[1]) / 100); +  } + +  function getPixelValue(value, property) { +    if (Object.isElement(value)) { +      element = value; +      value = element.getStyle(property); +    } +    if (value === null) { +      return null; +    } + +    if ((/^(?:-)?\d+(\.\d+)?(px)?$/i).test(value)) { +      return window.parseFloat(value);      } -    var match = true, name, matches; -    for (var i = 0, token; token = this.tokens[i]; i++) { -      name = token[0], matches = token[1]; -      if (!Selector.assertions[name](element, matches)) { -        match = false; break; +    if (/\d/.test(value) && element.runtimeStyle) { +      var style = element.style.left, rStyle = element.runtimeStyle.left; +      element.runtimeStyle.left = element.currentStyle.left; +      element.style.left = value || 0; +      value = element.style.pixelLeft; +      element.style.left = style; +      element.runtimeStyle.left = rStyle; + +      return value; +    } + +    if (value.include('%')) { +      var decimal = toDecimal(value); +      var whole; +      if (property.include('left') || property.include('right') || +       property.include('width')) { +        whole = $(element.parentNode).measure('width'); +      } else if (property.include('top') || property.include('bottom') || +       property.include('height')) { +        whole = $(element.parentNode).measure('height');        } + +      return whole * decimal;      } -    return match; -  }, +    return 0; +  } -  toString: function() { -    return this.expression; -  }, +  function toCSSPixels(number) { +    if (Object.isString(number) && number.endsWith('px')) { +      return number; +    } +    return number + 'px'; +  } -  inspect: function() { -    return "#<Selector:" + this.expression.inspect() + ">"; +  function isDisplayed(element) { +    var originalElement = element; +    while (element && element.parentNode) { +      var display = element.getStyle('display'); +      if (display === 'none') { +        return false; +      } +      element = $(element.parentNode); +    } +    return true;    } -}); -Object.extend(Selector, { -  _cache: { }, - -  xpath: { -    descendant:   "//*", -    child:        "/*", -    adjacent:     "/following-sibling::*[1]", -    laterSibling: '/following-sibling::*', -    tagName:      function(m) { -      if (m[1] == '*') return ''; -      return "[local-name()='" + m[1].toLowerCase() + -             "' or local-name()='" + m[1].toUpperCase() + "']"; +  var hasLayout = Prototype.K; +  if ('currentStyle' in document.documentElement) { +    hasLayout = function(element) { +      if (!element.currentStyle.hasLayout) { +        element.style.zoom = 1; +      } +      return element; +    }; +  } + +  function cssNameFor(key) { +    if (key.include('border')) key = key + '-width'; +    return key.camelize(); +  } + +  Element.Layout = Class.create(Hash, { +    initialize: function($super, element, preCompute) { +      $super(); +      this.element = $(element); + +      Element.Layout.PROPERTIES.each( function(property) { +        this._set(property, null); +      }, this); + +      if (preCompute) { +        this._preComputing = true; +        this._begin(); +        Element.Layout.PROPERTIES.each( this._compute, this ); +        this._end(); +        this._preComputing = false; +      } +    }, + +    _set: function(property, value) { +      return Hash.prototype.set.call(this, property, value); +    }, + +    set: function(property, value) { +      throw "Properties of Element.Layout are read-only."; +    }, + +    get: function($super, property) { +      var value = $super(property); +      return value === null ? this._compute(property) : value; +    }, + +    _begin: function() { +      if (this._prepared) return; + +      var element = this.element; +      if (isDisplayed(element)) { +        this._prepared = true; +        return; +      } + +      var originalStyles = { +        position:   element.style.position   || '', +        width:      element.style.width      || '', +        visibility: element.style.visibility || '', +        display:    element.style.display    || '' +      }; + +      element.store('prototype_original_styles', originalStyles); + +      var position = element.getStyle('position'), +       width = element.getStyle('width'); + +      element.setStyle({ +        position:   'absolute', +        visibility: 'hidden', +        display:    'block' +      }); + +      var positionedWidth = element.getStyle('width'); + +      var newWidth; +      if (width && (positionedWidth === width)) { +        newWidth = getPixelValue(width); +      } else if (width && (position === 'absolute' || position === 'fixed')) { +        newWidth = getPixelValue(width); +      } else { +        var parent = element.parentNode, pLayout = $(parent).getLayout(); + +        newWidth = pLayout.get('width') - +         this.get('margin-left') - +         this.get('border-left') - +         this.get('padding-left') - +         this.get('padding-right') - +         this.get('border-right') - +         this.get('margin-right'); +      } + +      element.setStyle({ width: newWidth + 'px' }); + +      this._prepared = true;      }, -    className:    "[contains(concat(' ', @class, ' '), ' #{1} ')]", -    id:           "[@id='#{1}']", -    attrPresence: function(m) { -      m[1] = m[1].toLowerCase(); -      return new Template("[@#{1}]").evaluate(m); + +    _end: function() { +      var element = this.element; +      var originalStyles = element.retrieve('prototype_original_styles'); +      element.store('prototype_original_styles', null); +      element.setStyle(originalStyles); +      this._prepared = false;      }, -    attr: function(m) { -      m[1] = m[1].toLowerCase(); -      m[3] = m[5] || m[6]; -      return new Template(Selector.xpath.operators[m[2]]).evaluate(m); + +    _compute: function(property) { +      var COMPUTATIONS = Element.Layout.COMPUTATIONS; +      if (!(property in COMPUTATIONS)) { +        throw "Property not found."; +      } +      return this._set(property, COMPUTATIONS[property].call(this, this.element));      }, -    pseudo: function(m) { -      var h = Selector.xpath.pseudos[m[1]]; -      if (!h) return ''; -      if (Object.isFunction(h)) return h(m); -      return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m); + +    toObject: function() { +      var args = $A(arguments); +      var keys = (args.length === 0) ? Element.Layout.PROPERTIES : +       args.join(' ').split(' '); +      var obj = {}; +      keys.each( function(key) { +        if (!Element.Layout.PROPERTIES.include(key)) return; +        var value = this.get(key); +        if (value != null) obj[key] = value; +      }, this); +      return obj;      }, -    operators: { -      '=':  "[@#{1}='#{3}']", -      '!=': "[@#{1}!='#{3}']", -      '^=': "[starts-with(@#{1}, '#{3}')]", -      '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']", -      '*=': "[contains(@#{1}, '#{3}')]", -      '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]", -      '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]" + +    toHash: function() { +      var obj = this.toObject.apply(this, arguments); +      return new Hash(obj);      }, -    pseudos: { -      'first-child': '[not(preceding-sibling::*)]', -      'last-child':  '[not(following-sibling::*)]', -      'only-child':  '[not(preceding-sibling::* or following-sibling::*)]', -      'empty':       "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]", -      'checked':     "[@checked]", -      'disabled':    "[@disabled]", -      'enabled':     "[not(@disabled)]", -      'not': function(m) { -        var e = m[6], p = Selector.patterns, -            x = Selector.xpath, le, v; - -        var exclusion = []; -        while (e && le != e && (/\S/).test(e)) { -          le = e; -          for (var i in p) { -            if (m = e.match(p[i])) { -              v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m); -              exclusion.push("(" + v.substring(1, v.length - 1) + ")"); -              e = e.replace(m[0], ''); -              break; -            } -          } -        } -        return "[not(" + exclusion.join(" and ") + ")]"; + +    toCSS: function() { +      var args = $A(arguments); +      var keys = (args.length === 0) ? Element.Layout.PROPERTIES : +       args.join(' ').split(' '); +      var css = {}; + +      keys.each( function(key) { +        if (!Element.Layout.PROPERTIES.include(key)) return; +        if (Element.Layout.COMPOSITE_PROPERTIES.include(key)) return; + +        var value = this.get(key); +        if (value != null) css[cssNameFor(key)] = value + 'px'; +      }, this); +      return css; +    }, + +    inspect: function() { +      return "#<Element.Layout>"; +    } +  }); + +  Object.extend(Element.Layout, { +    PROPERTIES: $w('height width top left right bottom border-left border-right border-top border-bottom padding-left padding-right padding-top padding-bottom margin-top margin-bottom margin-left margin-right padding-box-width padding-box-height border-box-width border-box-height margin-box-width margin-box-height'), + +    COMPOSITE_PROPERTIES: $w('padding-box-width padding-box-height margin-box-width margin-box-height border-box-width border-box-height'), + +    COMPUTATIONS: { +      'height': function(element) { +        if (!this._preComputing) this._begin(); + +        var bHeight = this.get('border-box-height'); +        if (bHeight <= 0) return 0; + +        var bTop = this.get('border-top'), +         bBottom = this.get('border-bottom'); + +        var pTop = this.get('padding-top'), +         pBottom = this.get('padding-bottom'); + +        if (!this._preComputing) this._end(); + +        return bHeight - bTop - bBottom - pTop - pBottom;        }, -      'nth-child':      function(m) { -        return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m); + +      'width': function(element) { +        if (!this._preComputing) this._begin(); + +        var bWidth = this.get('border-box-width'); +        if (bWidth <= 0) return 0; + +        var bLeft = this.get('border-left'), +         bRight = this.get('border-right'); + +        var pLeft = this.get('padding-left'), +         pRight = this.get('padding-right'); + +        if (!this._preComputing) this._end(); + +        return bWidth - bLeft - bRight - pLeft - pRight;        }, -      'nth-last-child': function(m) { -        return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m); + +      'padding-box-height': function(element) { +        var height = this.get('height'), +         pTop = this.get('padding-top'), +         pBottom = this.get('padding-bottom'); + +        return height + pTop + pBottom;        }, -      'nth-of-type':    function(m) { -        return Selector.xpath.pseudos.nth("position() ", m); + +      'padding-box-width': function(element) { +        var width = this.get('width'), +         pLeft = this.get('padding-left'), +         pRight = this.get('padding-right'); + +        return width + pLeft + pRight;        }, -      'nth-last-of-type': function(m) { -        return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m); + +      'border-box-height': function(element) { +        return element.offsetHeight;        }, -      'first-of-type':  function(m) { -        m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m); + +      'border-box-width': function(element) { +        return element.offsetWidth;        }, -      'last-of-type':   function(m) { -        m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m); + +      'margin-box-height': function(element) { +        var bHeight = this.get('border-box-height'), +         mTop = this.get('margin-top'), +         mBottom = this.get('margin-bottom'); + +        if (bHeight <= 0) return 0; + +        return bHeight + mTop + mBottom;        }, -      'only-of-type':   function(m) { -        var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m); + +      'margin-box-width': function(element) { +        var bWidth = this.get('border-box-width'), +         mLeft = this.get('margin-left'), +         mRight = this.get('margin-right'); + +        if (bWidth <= 0) return 0; + +        return bWidth + mLeft + mRight;        }, -      nth: function(fragment, m) { -        var mm, formula = m[6], predicate; -        if (formula == 'even') formula = '2n+0'; -        if (formula == 'odd')  formula = '2n+1'; -        if (mm = formula.match(/^(\d+)$/)) // digit only -          return '[' + fragment + "= " + mm[1] + ']'; -        if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b -          if (mm[1] == "-") mm[1] = -1; -          var a = mm[1] ? Number(mm[1]) : 1; -          var b = mm[2] ? Number(mm[2]) : 0; -          predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " + -          "((#{fragment} - #{b}) div #{a} >= 0)]"; -          return new Template(predicate).evaluate({ -            fragment: fragment, a: a, b: b }); -        } + +      'top': function(element) { +        var offset = element.positionedOffset(); +        return offset.top; +      }, + +      'bottom': function(element) { +        var offset = element.positionedOffset(), +         parent = element.getOffsetParent(), +         pHeight = parent.measure('height'); + +        var mHeight = this.get('border-box-height'); + +        return pHeight - mHeight - offset.top; +      }, + +      'left': function(element) { +        var offset = element.positionedOffset(); +        return offset.left; +      }, + +      'right': function(element) { +        var offset = element.positionedOffset(), +         parent = element.getOffsetParent(), +         pWidth = parent.measure('width'); + +        var mWidth = this.get('border-box-width'); + +        return pWidth - mWidth - offset.left; +      }, + +      'padding-top': function(element) { +        return getPixelValue(element, 'paddingTop'); +      }, + +      'padding-bottom': function(element) { +        return getPixelValue(element, 'paddingBottom'); +      }, + +      'padding-left': function(element) { +        return getPixelValue(element, 'paddingLeft'); +      }, + +      'padding-right': function(element) { +        return getPixelValue(element, 'paddingRight'); +      }, + +      'border-top': function(element) { +        return Object.isNumber(element.clientTop) ? element.clientTop : +         getPixelValue(element, 'borderTopWidth'); +      }, + +      'border-bottom': function(element) { +        return Object.isNumber(element.clientBottom) ? element.clientBottom : +         getPixelValue(element, 'borderBottomWidth'); +      }, + +      'border-left': function(element) { +        return Object.isNumber(element.clientLeft) ? element.clientLeft : +         getPixelValue(element, 'borderLeftWidth'); +      }, + +      'border-right': function(element) { +        return Object.isNumber(element.clientRight) ? element.clientRight : +         getPixelValue(element, 'borderRightWidth'); +      }, + +      'margin-top': function(element) { +        return getPixelValue(element, 'marginTop'); +      }, + +      'margin-bottom': function(element) { +        return getPixelValue(element, 'marginBottom'); +      }, + +      'margin-left': function(element) { +        return getPixelValue(element, 'marginLeft'); +      }, + +      'margin-right': function(element) { +        return getPixelValue(element, 'marginRight');        }      } -  }, +  }); -  criteria: { -    tagName:      'n = h.tagName(n, r, "#{1}", c);   c = false;', -    className:    'n = h.className(n, r, "#{1}", c); c = false;', -    id:           'n = h.id(n, r, "#{1}", c);        c = false;', -    attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;', -    attr: function(m) { -      m[3] = (m[5] || m[6]); -      return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m); -    }, -    pseudo: function(m) { -      if (m[6]) m[6] = m[6].replace(/"/g, '\\"'); -      return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m); -    }, -    descendant:   'c = "descendant";', -    child:        'c = "child";', -    adjacent:     'c = "adjacent";', -    laterSibling: 'c = "laterSibling";' -  }, - -  patterns: { -    // combinators must be listed first -    // (and descendant needs to be last combinator) -    laterSibling: /^\s*~\s*/, -    child:        /^\s*>\s*/, -    adjacent:     /^\s*\+\s*/, -    descendant:   /^\s/, - -    // selectors follow -    tagName:      /^\s*(\*|[\w\-]+)(\b|$)?/, -    id:           /^#([\w\-\*]+)(\b|$)/, -    className:    /^\.([\w\-\*]+)(\b|$)/, -    pseudo:       /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s)|(?=:))/, -    attrPresence: /^\[([\w]+)\]/, -    attr:         /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/ -  }, - -  // for Selector.match and Element#match -  assertions: { -    tagName: function(element, matches) { -      return matches[1].toUpperCase() == element.tagName.toUpperCase(); +  if ('getBoundingClientRect' in document.documentElement) { +    Object.extend(Element.Layout.COMPUTATIONS, { +      'right': function(element) { +        var parent = hasLayout(element.getOffsetParent()); +        var rect = element.getBoundingClientRect(), +         pRect = parent.getBoundingClientRect(); + +        return (pRect.right - rect.right).round(); +      }, + +      'bottom': function(element) { +        var parent = hasLayout(element.getOffsetParent()); +        var rect = element.getBoundingClientRect(), +         pRect = parent.getBoundingClientRect(); + +        return (pRect.bottom - rect.bottom).round(); +      } +    }); +  } + +  Element.Offset = Class.create({ +    initialize: function(left, top) { +      this.left = left.round(); +      this.top  = top.round(); + +      this[0] = this.left; +      this[1] = this.top;      }, -    className: function(element, matches) { -      return Element.hasClassName(element, matches[1]); +    relativeTo: function(offset) { +      return new Element.Offset( +        this.left - offset.left, +        this.top  - offset.top +      );      }, -    id: function(element, matches) { -      return element.id === matches[1]; +    inspect: function() { +      return "#<Element.Offset left: #{left} top: #{top}>".interpolate(this);      }, -    attrPresence: function(element, matches) { -      return Element.hasAttribute(element, matches[1]); +    toString: function() { +      return "[#{left}, #{top}]".interpolate(this);      }, -    attr: function(element, matches) { -      var nodeValue = Element.readAttribute(element, matches[1]); -      return Selector.operators[matches[2]](nodeValue, matches[3]); +    toArray: function() { +      return [this.left, this.top];      } -  }, +  }); -  handlers: { -    // UTILITY FUNCTIONS -    // joins two collections -    concat: function(a, b) { -      for (var i = 0, node; node = b[i]; i++) -        a.push(node); -      return a; -    }, +  function getLayout(element, preCompute) { +    return new Element.Layout(element, preCompute); +  } -    // marks an array of nodes for counting -    mark: function(nodes) { -      for (var i = 0, node; node = nodes[i]; i++) -        node._counted = true; -      return nodes; -    }, +  function measure(element, property) { +    return $(element).getLayout().get(property); +  } -    unmark: function(nodes) { -      for (var i = 0, node; node = nodes[i]; i++) -        node._counted = undefined; -      return nodes; -    }, +  function getDimensions(element) { +    var layout = $(element).getLayout(); +    return { +      width:  layout.get('width'), +      height: layout.get('height') +    }; +  } -    // mark each child node with its position (for nth calls) -    // "ofType" flag indicates whether we're indexing for nth-of-type -    // rather than nth-child -    index: function(parentNode, reverse, ofType) { -      parentNode._counted = true; -      if (reverse) { -        for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) { -          var node = nodes[i]; -          if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++; -        } -      } else { -        for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++) -          if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++; +  function getOffsetParent(element) { +    if (isDetached(element)) return $(document.body); + +    var isInline = (Element.getStyle(element, 'display') === 'inline'); +    if (!isInline && element.offsetParent) return $(element.offsetParent); +    if (element === document.body) return $(element); + +    while ((element = element.parentNode) && element !== document.body) { +      if (Element.getStyle(element, 'position') !== 'static') { +        return (element.nodeName === 'HTML') ? $(document.body) : $(element);        } -    }, +    } -    // filters out duplicates and extends all nodes -    unique: function(nodes) { -      if (nodes.length == 0) return nodes; -      var results = [], n; -      for (var i = 0, l = nodes.length; i < l; i++) -        if (!(n = nodes[i])._counted) { -          n._counted = true; -          results.push(Element.extend(n)); -        } -      return Selector.handlers.unmark(results); -    }, +    return $(document.body); +  } -    // COMBINATOR FUNCTIONS -    descendant: function(nodes) { -      var h = Selector.handlers; -      for (var i = 0, results = [], node; node = nodes[i]; i++) -        h.concat(results, node.getElementsByTagName('*')); -      return results; -    }, -    child: function(nodes) { -      var h = Selector.handlers; -      for (var i = 0, results = [], node; node = nodes[i]; i++) { -        for (var j = 0, child; child = node.childNodes[j]; j++) -          if (child.nodeType == 1 && child.tagName != '!') results.push(child); -      } -      return results; -    }, +  function cumulativeOffset(element) { +    var valueT = 0, valueL = 0; +    do { +      valueT += element.offsetTop  || 0; +      valueL += element.offsetLeft || 0; +      element = element.offsetParent; +    } while (element); +    return new Element.Offset(valueL, valueT); +  } + +  function positionedOffset(element) { +    var layout = element.getLayout(); -    adjacent: function(nodes) { -      for (var i = 0, results = [], node; node = nodes[i]; i++) { -        var next = this.nextElementSibling(node); -        if (next) results.push(next); +    var valueT = 0, valueL = 0; +    do { +      valueT += element.offsetTop  || 0; +      valueL += element.offsetLeft || 0; +      element = element.offsetParent; +      if (element) { +        if (isBody(element)) break; +        var p = Element.getStyle(element, 'position'); +        if (p !== 'static') break;        } -      return results; -    }, +    } while (element); -    laterSibling: function(nodes) { -      var h = Selector.handlers; -      for (var i = 0, results = [], node; node = nodes[i]; i++) -        h.concat(results, Element.nextSiblings(node)); -      return results; -    }, +    valueL -= layout.get('margin-top'); +    valueT -= layout.get('margin-left'); -    nextElementSibling: function(node) { -      while (node = node.nextSibling) -	      if (node.nodeType == 1) return node; -      return null; -    }, +    return new Element.Offset(valueL, valueT); +  } -    previousElementSibling: function(node) { -      while (node = node.previousSibling) -        if (node.nodeType == 1) return node; -      return null; -    }, +  function cumulativeScrollOffset(element) { +    var valueT = 0, valueL = 0; +    do { +      valueT += element.scrollTop  || 0; +      valueL += element.scrollLeft || 0; +      element = element.parentNode; +    } while (element); +    return new Element.Offset(valueL, valueT); +  } -    // TOKEN FUNCTIONS -    tagName: function(nodes, root, tagName, combinator) { -      tagName = tagName.toUpperCase(); -      var results = [], h = Selector.handlers; -      if (nodes) { -        if (combinator) { -          // fastlane for ordinary descendant combinators -          if (combinator == "descendant") { -            for (var i = 0, node; node = nodes[i]; i++) -              h.concat(results, node.getElementsByTagName(tagName)); -            return results; -          } else nodes = this[combinator](nodes); -          if (tagName == "*") return nodes; -        } -        for (var i = 0, node; node = nodes[i]; i++) -          if (node.tagName.toUpperCase() == tagName) results.push(node); -        return results; -      } else return root.getElementsByTagName(tagName); -    }, +  function viewportOffset(forElement) { +    var valueT = 0, valueL = 0, docBody = document.body; -    id: function(nodes, root, id, combinator) { -      var targetNode = $(id), h = Selector.handlers; -      if (!targetNode) return []; -      if (!nodes && root == document) return [targetNode]; -      if (nodes) { -        if (combinator) { -          if (combinator == 'child') { -            for (var i = 0, node; node = nodes[i]; i++) -              if (targetNode.parentNode == node) return [targetNode]; -          } else if (combinator == 'descendant') { -            for (var i = 0, node; node = nodes[i]; i++) -              if (Element.descendantOf(targetNode, node)) return [targetNode]; -          } else if (combinator == 'adjacent') { -            for (var i = 0, node; node = nodes[i]; i++) -              if (Selector.handlers.previousElementSibling(targetNode) == node) -                return [targetNode]; -          } else nodes = h[combinator](nodes); -        } -        for (var i = 0, node; node = nodes[i]; i++) -          if (node == targetNode) return [targetNode]; -        return []; +    var element = forElement; +    do { +      valueT += element.offsetTop  || 0; +      valueL += element.offsetLeft || 0; +      if (element.offsetParent == docBody && +        Element.getStyle(element, 'position') == 'absolute') break; +    } while (element = element.offsetParent); + +    element = forElement; +    do { +      if (element != docBody) { +        valueT -= element.scrollTop  || 0; +        valueL -= element.scrollLeft || 0;        } -      return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : []; -    }, +    } while (element = element.parentNode); +    return new Element.Offset(valueL, valueT); +  } -    className: function(nodes, root, className, combinator) { -      if (nodes && combinator) nodes = this[combinator](nodes); -      return Selector.handlers.byClassName(nodes, root, className); -    }, +  function absolutize(element) { +    element = $(element); -    byClassName: function(nodes, root, className) { -      if (!nodes) nodes = Selector.handlers.descendant([root]); -      var needle = ' ' + className + ' '; -      for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) { -        nodeClassName = node.className; -        if (nodeClassName.length == 0) continue; -        if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle)) -          results.push(node); -      } -      return results; -    }, +    if (Element.getStyle(element, 'position') === 'absolute') { +      return element; +    } -    attrPresence: function(nodes, root, attr) { -      if (!nodes) nodes = root.getElementsByTagName("*"); -      var results = []; -      for (var i = 0, node; node = nodes[i]; i++) -        if (Element.hasAttribute(node, attr)) results.push(node); -      return results; -    }, +    var offsetParent = getOffsetParent(element); +    var eOffset = element.viewportOffset(), +     pOffset = offsetParent.viewportOffset(); -    attr: function(nodes, root, attr, value, operator) { -      if (!nodes) nodes = root.getElementsByTagName("*"); -      var handler = Selector.operators[operator], results = []; -      for (var i = 0, node; node = nodes[i]; i++) { -        var nodeValue = Element.readAttribute(node, attr); -        if (nodeValue === null) continue; -        if (handler(nodeValue, value)) results.push(node); -      } -      return results; -    }, +    var offset = eOffset.relativeTo(pOffset); +    var layout = element.getLayout(); -    pseudo: function(nodes, name, value, root, combinator) { -      if (nodes && combinator) nodes = this[combinator](nodes); -      if (!nodes) nodes = root.getElementsByTagName("*"); -      return Selector.pseudos[name](nodes, value, root); +    element.store('prototype_absolutize_original_styles', { +      left:   element.getStyle('left'), +      top:    element.getStyle('top'), +      width:  element.getStyle('width'), +      height: element.getStyle('height') +    }); + +    element.setStyle({ +      position: 'absolute', +      top:    offset.top + 'px', +      left:   offset.left + 'px', +      width:  layout.get('width') + 'px', +      height: layout.get('height') + 'px' +    }); + +    return element; +  } + +  function relativize(element) { +    element = $(element); +    if (Element.getStyle(element, 'position') === 'relative') { +      return element;      } -  }, -  pseudos: { -    'first-child': function(nodes, value, root) { -      for (var i = 0, results = [], node; node = nodes[i]; i++) { -        if (Selector.handlers.previousElementSibling(node)) continue; -          results.push(node); -      } -      return results; -    }, -    'last-child': function(nodes, value, root) { -      for (var i = 0, results = [], node; node = nodes[i]; i++) { -        if (Selector.handlers.nextElementSibling(node)) continue; -          results.push(node); -      } -      return results; -    }, -    'only-child': function(nodes, value, root) { -      var h = Selector.handlers; -      for (var i = 0, results = [], node; node = nodes[i]; i++) -        if (!h.previousElementSibling(node) && !h.nextElementSibling(node)) -          results.push(node); -      return results; -    }, -    'nth-child':        function(nodes, formula, root) { -      return Selector.pseudos.nth(nodes, formula, root); -    }, -    'nth-last-child':   function(nodes, formula, root) { -      return Selector.pseudos.nth(nodes, formula, root, true); -    }, -    'nth-of-type':      function(nodes, formula, root) { -      return Selector.pseudos.nth(nodes, formula, root, false, true); -    }, -    'nth-last-of-type': function(nodes, formula, root) { -      return Selector.pseudos.nth(nodes, formula, root, true, true); -    }, -    'first-of-type':    function(nodes, formula, root) { -      return Selector.pseudos.nth(nodes, "1", root, false, true); -    }, -    'last-of-type':     function(nodes, formula, root) { -      return Selector.pseudos.nth(nodes, "1", root, true, true); -    }, -    'only-of-type':     function(nodes, formula, root) { -      var p = Selector.pseudos; -      return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root); -    }, +    var originalStyles = +     element.retrieve('prototype_absolutize_original_styles'); -    // handles the an+b logic -    getIndices: function(a, b, total) { -      if (a == 0) return b > 0 ? [b] : []; -      return $R(1, total).inject([], function(memo, i) { -        if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i); -        return memo; -      }); -    }, +    if (originalStyles) element.setStyle(originalStyles); +    return element; +  } -    // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type -    nth: function(nodes, formula, root, reverse, ofType) { -      if (nodes.length == 0) return []; -      if (formula == 'even') formula = '2n+0'; -      if (formula == 'odd')  formula = '2n+1'; -      var h = Selector.handlers, results = [], indexed = [], m; -      h.mark(nodes); -      for (var i = 0, node; node = nodes[i]; i++) { -        if (!node.parentNode._counted) { -          h.index(node.parentNode, reverse, ofType); -          indexed.push(node.parentNode); -        } -      } -      if (formula.match(/^\d+$/)) { // just a number -        formula = Number(formula); -        for (var i = 0, node; node = nodes[i]; i++) -          if (node.nodeIndex == formula) results.push(node); -      } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b -        if (m[1] == "-") m[1] = -1; -        var a = m[1] ? Number(m[1]) : 1; -        var b = m[2] ? Number(m[2]) : 0; -        var indices = Selector.pseudos.getIndices(a, b, nodes.length); -        for (var i = 0, node, l = indices.length; node = nodes[i]; i++) { -          for (var j = 0; j < l; j++) -            if (node.nodeIndex == indices[j]) results.push(node); +  Element.addMethods({ +    getLayout:              getLayout, +    measure:                measure, +    getDimensions:          getDimensions, +    getOffsetParent:        getOffsetParent, +    cumulativeOffset:       cumulativeOffset, +    positionedOffset:       positionedOffset, +    cumulativeScrollOffset: cumulativeScrollOffset, +    viewportOffset:         viewportOffset, +    absolutize:             absolutize, +    relativize:             relativize +  }); + +  function isBody(element) { +    return element.nodeName.toUpperCase() === 'BODY'; +  } + +  function isDetached(element) { +    return element !== document.body && +     !Element.descendantOf(element, document.body); +  } + +  if ('getBoundingClientRect' in document.documentElement) { +    Element.addMethods({ +      viewportOffset: function(element) { +        element = $(element); +        if (isDetached(element)) return new Element.Offset(0, 0); + +        var rect  = element.getBoundingClientRect(), +         docEl = document.documentElement; +        return new Element.Offset(rect.left - docEl.clientLeft, +         rect.top - docEl.clientTop); +      }, + +      positionedOffset: function(element) { +        element = $(element); +        var parent = element.getOffsetParent(); +        if (isDetached(element)) return new Element.Offset(0, 0); + +        if (element.offsetParent && +         element.offsetParent.nodeName.toUpperCase() === 'HTML') { +          return positionedOffset(element);          } -      } -      h.unmark(nodes); -      h.unmark(indexed); -      return results; -    }, -    'empty': function(nodes, value, root) { -      for (var i = 0, results = [], node; node = nodes[i]; i++) { -        // IE treats comments as element nodes -        if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue; -        results.push(node); -      } -      return results; -    }, +        var eOffset = element.viewportOffset(), +         pOffset = isBody(parent) ? viewportOffset(parent) : +          parent.viewportOffset(); +        var retOffset = eOffset.relativeTo(pOffset); -    'not': function(nodes, selector, root) { -      var h = Selector.handlers, selectorType, m; -      var exclusions = new Selector(selector).findElements(root); -      h.mark(exclusions); -      for (var i = 0, results = [], node; node = nodes[i]; i++) -        if (!node._counted) results.push(node); -      h.unmark(exclusions); -      return results; -    }, +        var layout = element.getLayout(); +        var top  = retOffset.top  - layout.get('margin-top'); +        var left = retOffset.left - layout.get('margin-left'); -    'enabled': function(nodes, value, root) { -      for (var i = 0, results = [], node; node = nodes[i]; i++) -        if (!node.disabled) results.push(node); -      return results; -    }, +        return new Element.Offset(left, top); +      } +    }); +  } +})(); +window.$$ = function() { +  var expression = $A(arguments).join(', '); +  return Prototype.Selector.select(expression, document); +}; -    'disabled': function(nodes, value, root) { -      for (var i = 0, results = [], node; node = nodes[i]; i++) -        if (node.disabled) results.push(node); -      return results; -    }, +Prototype.Selector = (function() { -    'checked': function(nodes, value, root) { -      for (var i = 0, results = [], node; node = nodes[i]; i++) -        if (node.checked) results.push(node); -      return results; -    } -  }, +  function select() { +    throw new Error('Method "Prototype.Selector.select" must be defined.'); +  } -  operators: { -    '=':  function(nv, v) { return nv == v; }, -    '!=': function(nv, v) { return nv != v; }, -    '^=': function(nv, v) { return nv.startsWith(v); }, -    '$=': function(nv, v) { return nv.endsWith(v); }, -    '*=': function(nv, v) { return nv.include(v); }, -    '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); }, -    '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); } -  }, +  function match() { +    throw new Error('Method "Prototype.Selector.match" must be defined.'); +  } -  matchElements: function(elements, expression) { -    var matches = new Selector(expression).findElements(), h = Selector.handlers; -    h.mark(matches); -    for (var i = 0, results = [], element; element = elements[i]; i++) -      if (element._counted) results.push(element); -    h.unmark(matches); -    return results; -  }, +  function find(elements, expression, index) { +    index = index || 0; +    var match = Prototype.Selector.match, length = elements.length, matchIndex = 0, i; -  findElement: function(elements, expression, index) { -    if (Object.isNumber(expression)) { -      index = expression; expression = false; +    for (i = 0; i < length; i++) { +      if (match(elements[i], expression) && index == matchIndex++) { +        return Element.extend(elements[i]); +      }      } -    return Selector.matchElements(elements, expression || '*')[index || 0]; -  }, +  } -  findChildElements: function(element, expressions) { -    var exprs = expressions.join(','); -    expressions = []; -    exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) { -      expressions.push(m[1].strip()); -    }); -    var results = [], h = Selector.handlers; -    for (var i = 0, l = expressions.length, selector; i < l; i++) { -      selector = new Selector(expressions[i].strip()); -      h.concat(results, selector.findElements(element)); +  function extendElements(elements) { +    for (var i = 0, length = elements.length; i < length; i++) { +      Element.extend(elements[i]);      } -    return (l > 1) ? h.unique(results) : results; +    return elements;    } -}); -if (Prototype.Browser.IE) { -  // IE returns comment nodes on getElementsByTagName("*"). -  // Filter them out. -  Selector.handlers.concat = function(a, b) { -    for (var i = 0, node; node = b[i]; i++) -      if (node.tagName !== "!") a.push(node); -    return a; + +  var K = Prototype.K; + +  return { +    select: select, +    match: match, +    find: find, +    extendElements: (Element.extend === K) ? K : extendElements, +    extendElement: Element.extend    }; +})(); +Prototype._original_property = window.Sizzle; +/*! + * Sizzle CSS Selector Engine - v1.0 + *  Copyright 2009, The Dojo Foundation + *  Released under the MIT, BSD, and GPL Licenses. + *  More information: http://sizzlejs.com/ + */ +(function(){ + +var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, +	done = 0, +	toString = Object.prototype.toString, +	hasDuplicate = false, +	baseHasDuplicate = true; + +[0, 0].sort(function(){ +	baseHasDuplicate = false; +	return 0; +}); + +var Sizzle = function(selector, context, results, seed) { +	results = results || []; +	var origContext = context = context || document; + +	if ( context.nodeType !== 1 && context.nodeType !== 9 ) { +		return []; +	} + +	if ( !selector || typeof selector !== "string" ) { +		return results; +	} + +	var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context), +		soFar = selector; + +	while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) { +		soFar = m[3]; + +		parts.push( m[1] ); + +		if ( m[2] ) { +			extra = m[3]; +			break; +		} +	} + +	if ( parts.length > 1 && origPOS.exec( selector ) ) { +		if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { +			set = posProcess( parts[0] + parts[1], context ); +		} else { +			set = Expr.relative[ parts[0] ] ? +				[ context ] : +				Sizzle( parts.shift(), context ); + +			while ( parts.length ) { +				selector = parts.shift(); + +				if ( Expr.relative[ selector ] ) +					selector += parts.shift(); + +				set = posProcess( selector, set ); +			} +		} +	} else { +		if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && +				Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { +			var ret = Sizzle.find( parts.shift(), context, contextXML ); +			context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; +		} + +		if ( context ) { +			var ret = seed ? +				{ expr: parts.pop(), set: makeArray(seed) } : +				Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); +			set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; + +			if ( parts.length > 0 ) { +				checkSet = makeArray(set); +			} else { +				prune = false; +			} + +			while ( parts.length ) { +				var cur = parts.pop(), pop = cur; + +				if ( !Expr.relative[ cur ] ) { +					cur = ""; +				} else { +					pop = parts.pop(); +				} + +				if ( pop == null ) { +					pop = context; +				} + +				Expr.relative[ cur ]( checkSet, pop, contextXML ); +			} +		} else { +			checkSet = parts = []; +		} +	} + +	if ( !checkSet ) { +		checkSet = set; +	} + +	if ( !checkSet ) { +		throw "Syntax error, unrecognized expression: " + (cur || selector); +	} + +	if ( toString.call(checkSet) === "[object Array]" ) { +		if ( !prune ) { +			results.push.apply( results, checkSet ); +		} else if ( context && context.nodeType === 1 ) { +			for ( var i = 0; checkSet[i] != null; i++ ) { +				if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) { +					results.push( set[i] ); +				} +			} +		} else { +			for ( var i = 0; checkSet[i] != null; i++ ) { +				if ( checkSet[i] && checkSet[i].nodeType === 1 ) { +					results.push( set[i] ); +				} +			} +		} +	} else { +		makeArray( checkSet, results ); +	} + +	if ( extra ) { +		Sizzle( extra, origContext, results, seed ); +		Sizzle.uniqueSort( results ); +	} + +	return results; +}; + +Sizzle.uniqueSort = function(results){ +	if ( sortOrder ) { +		hasDuplicate = baseHasDuplicate; +		results.sort(sortOrder); + +		if ( hasDuplicate ) { +			for ( var i = 1; i < results.length; i++ ) { +				if ( results[i] === results[i-1] ) { +					results.splice(i--, 1); +				} +			} +		} +	} + +	return results; +}; + +Sizzle.matches = function(expr, set){ +	return Sizzle(expr, null, null, set); +}; + +Sizzle.find = function(expr, context, isXML){ +	var set, match; + +	if ( !expr ) { +		return []; +	} + +	for ( var i = 0, l = Expr.order.length; i < l; i++ ) { +		var type = Expr.order[i], match; + +		if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { +			var left = match[1]; +			match.splice(1,1); + +			if ( left.substr( left.length - 1 ) !== "\\" ) { +				match[1] = (match[1] || "").replace(/\\/g, ""); +				set = Expr.find[ type ]( match, context, isXML ); +				if ( set != null ) { +					expr = expr.replace( Expr.match[ type ], "" ); +					break; +				} +			} +		} +	} + +	if ( !set ) { +		set = context.getElementsByTagName("*"); +	} + +	return {set: set, expr: expr}; +}; + +Sizzle.filter = function(expr, set, inplace, not){ +	var old = expr, result = [], curLoop = set, match, anyFound, +		isXMLFilter = set && set[0] && isXML(set[0]); + +	while ( expr && set.length ) { +		for ( var type in Expr.filter ) { +			if ( (match = Expr.match[ type ].exec( expr )) != null ) { +				var filter = Expr.filter[ type ], found, item; +				anyFound = false; + +				if ( curLoop == result ) { +					result = []; +				} + +				if ( Expr.preFilter[ type ] ) { +					match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); + +					if ( !match ) { +						anyFound = found = true; +					} else if ( match === true ) { +						continue; +					} +				} + +				if ( match ) { +					for ( var i = 0; (item = curLoop[i]) != null; i++ ) { +						if ( item ) { +							found = filter( item, match, i, curLoop ); +							var pass = not ^ !!found; + +							if ( inplace && found != null ) { +								if ( pass ) { +									anyFound = true; +								} else { +									curLoop[i] = false; +								} +							} else if ( pass ) { +								result.push( item ); +								anyFound = true; +							} +						} +					} +				} + +				if ( found !== undefined ) { +					if ( !inplace ) { +						curLoop = result; +					} + +					expr = expr.replace( Expr.match[ type ], "" ); + +					if ( !anyFound ) { +						return []; +					} + +					break; +				} +			} +		} + +		if ( expr == old ) { +			if ( anyFound == null ) { +				throw "Syntax error, unrecognized expression: " + expr; +			} else { +				break; +			} +		} + +		old = expr; +	} + +	return curLoop; +}; + +var Expr = Sizzle.selectors = { +	order: [ "ID", "NAME", "TAG" ], +	match: { +		ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/, +		CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/, +		NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/, +		ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/, +		TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/, +		CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/, +		POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/, +		PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/ +	}, +	leftMatch: {}, +	attrMap: { +		"class": "className", +		"for": "htmlFor" +	}, +	attrHandle: { +		href: function(elem){ +			return elem.getAttribute("href"); +		} +	}, +	relative: { +		"+": function(checkSet, part, isXML){ +			var isPartStr = typeof part === "string", +				isTag = isPartStr && !/\W/.test(part), +				isPartStrNotTag = isPartStr && !isTag; + +			if ( isTag && !isXML ) { +				part = part.toUpperCase(); +			} + +			for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { +				if ( (elem = checkSet[i]) ) { +					while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + +					checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ? +						elem || false : +						elem === part; +				} +			} + +			if ( isPartStrNotTag ) { +				Sizzle.filter( part, checkSet, true ); +			} +		}, +		">": function(checkSet, part, isXML){ +			var isPartStr = typeof part === "string"; + +			if ( isPartStr && !/\W/.test(part) ) { +				part = isXML ? part : part.toUpperCase(); + +				for ( var i = 0, l = checkSet.length; i < l; i++ ) { +					var elem = checkSet[i]; +					if ( elem ) { +						var parent = elem.parentNode; +						checkSet[i] = parent.nodeName === part ? parent : false; +					} +				} +			} else { +				for ( var i = 0, l = checkSet.length; i < l; i++ ) { +					var elem = checkSet[i]; +					if ( elem ) { +						checkSet[i] = isPartStr ? +							elem.parentNode : +							elem.parentNode === part; +					} +				} + +				if ( isPartStr ) { +					Sizzle.filter( part, checkSet, true ); +				} +			} +		}, +		"": function(checkSet, part, isXML){ +			var doneName = done++, checkFn = dirCheck; + +			if ( !/\W/.test(part) ) { +				var nodeCheck = part = isXML ? part : part.toUpperCase(); +				checkFn = dirNodeCheck; +			} + +			checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML); +		}, +		"~": function(checkSet, part, isXML){ +			var doneName = done++, checkFn = dirCheck; + +			if ( typeof part === "string" && !/\W/.test(part) ) { +				var nodeCheck = part = isXML ? part : part.toUpperCase(); +				checkFn = dirNodeCheck; +			} + +			checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); +		} +	}, +	find: { +		ID: function(match, context, isXML){ +			if ( typeof context.getElementById !== "undefined" && !isXML ) { +				var m = context.getElementById(match[1]); +				return m ? [m] : []; +			} +		}, +		NAME: function(match, context, isXML){ +			if ( typeof context.getElementsByName !== "undefined" ) { +				var ret = [], results = context.getElementsByName(match[1]); + +				for ( var i = 0, l = results.length; i < l; i++ ) { +					if ( results[i].getAttribute("name") === match[1] ) { +						ret.push( results[i] ); +					} +				} + +				return ret.length === 0 ? null : ret; +			} +		}, +		TAG: function(match, context){ +			return context.getElementsByTagName(match[1]); +		} +	}, +	preFilter: { +		CLASS: function(match, curLoop, inplace, result, not, isXML){ +			match = " " + match[1].replace(/\\/g, "") + " "; + +			if ( isXML ) { +				return match; +			} + +			for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { +				if ( elem ) { +					if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) { +						if ( !inplace ) +							result.push( elem ); +					} else if ( inplace ) { +						curLoop[i] = false; +					} +				} +			} + +			return false; +		}, +		ID: function(match){ +			return match[1].replace(/\\/g, ""); +		}, +		TAG: function(match, curLoop){ +			for ( var i = 0; curLoop[i] === false; i++ ){} +			return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase(); +		}, +		CHILD: function(match){ +			if ( match[1] == "nth" ) { +				var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( +					match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" || +					!/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + +				match[2] = (test[1] + (test[2] || 1)) - 0; +				match[3] = test[3] - 0; +			} + +			match[0] = done++; + +			return match; +		}, +		ATTR: function(match, curLoop, inplace, result, not, isXML){ +			var name = match[1].replace(/\\/g, ""); + +			if ( !isXML && Expr.attrMap[name] ) { +				match[1] = Expr.attrMap[name]; +			} + +			if ( match[2] === "~=" ) { +				match[4] = " " + match[4] + " "; +			} + +			return match; +		}, +		PSEUDO: function(match, curLoop, inplace, result, not){ +			if ( match[1] === "not" ) { +				if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { +					match[3] = Sizzle(match[3], null, null, curLoop); +				} else { +					var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); +					if ( !inplace ) { +						result.push.apply( result, ret ); +					} +					return false; +				} +			} else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { +				return true; +			} + +			return match; +		}, +		POS: function(match){ +			match.unshift( true ); +			return match; +		} +	}, +	filters: { +		enabled: function(elem){ +			return elem.disabled === false && elem.type !== "hidden"; +		}, +		disabled: function(elem){ +			return elem.disabled === true; +		}, +		checked: function(elem){ +			return elem.checked === true; +		}, +		selected: function(elem){ +			elem.parentNode.selectedIndex; +			return elem.selected === true; +		}, +		parent: function(elem){ +			return !!elem.firstChild; +		}, +		empty: function(elem){ +			return !elem.firstChild; +		}, +		has: function(elem, i, match){ +			return !!Sizzle( match[3], elem ).length; +		}, +		header: function(elem){ +			return /h\d/i.test( elem.nodeName ); +		}, +		text: function(elem){ +			return "text" === elem.type; +		}, +		radio: function(elem){ +			return "radio" === elem.type; +		}, +		checkbox: function(elem){ +			return "checkbox" === elem.type; +		}, +		file: function(elem){ +			return "file" === elem.type; +		}, +		password: function(elem){ +			return "password" === elem.type; +		}, +		submit: function(elem){ +			return "submit" === elem.type; +		}, +		image: function(elem){ +			return "image" === elem.type; +		}, +		reset: function(elem){ +			return "reset" === elem.type; +		}, +		button: function(elem){ +			return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON"; +		}, +		input: function(elem){ +			return /input|select|textarea|button/i.test(elem.nodeName); +		} +	}, +	setFilters: { +		first: function(elem, i){ +			return i === 0; +		}, +		last: function(elem, i, match, array){ +			return i === array.length - 1; +		}, +		even: function(elem, i){ +			return i % 2 === 0; +		}, +		odd: function(elem, i){ +			return i % 2 === 1; +		}, +		lt: function(elem, i, match){ +			return i < match[3] - 0; +		}, +		gt: function(elem, i, match){ +			return i > match[3] - 0; +		}, +		nth: function(elem, i, match){ +			return match[3] - 0 == i; +		}, +		eq: function(elem, i, match){ +			return match[3] - 0 == i; +		} +	}, +	filter: { +		PSEUDO: function(elem, match, i, array){ +			var name = match[1], filter = Expr.filters[ name ]; + +			if ( filter ) { +				return filter( elem, i, match, array ); +			} else if ( name === "contains" ) { +				return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0; +			} else if ( name === "not" ) { +				var not = match[3]; + +				for ( var i = 0, l = not.length; i < l; i++ ) { +					if ( not[i] === elem ) { +						return false; +					} +				} + +				return true; +			} +		}, +		CHILD: function(elem, match){ +			var type = match[1], node = elem; +			switch (type) { +				case 'only': +				case 'first': +					while ( (node = node.previousSibling) )  { +						if ( node.nodeType === 1 ) return false; +					} +					if ( type == 'first') return true; +					node = elem; +				case 'last': +					while ( (node = node.nextSibling) )  { +						if ( node.nodeType === 1 ) return false; +					} +					return true; +				case 'nth': +					var first = match[2], last = match[3]; + +					if ( first == 1 && last == 0 ) { +						return true; +					} + +					var doneName = match[0], +						parent = elem.parentNode; + +					if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { +						var count = 0; +						for ( node = parent.firstChild; node; node = node.nextSibling ) { +							if ( node.nodeType === 1 ) { +								node.nodeIndex = ++count; +							} +						} +						parent.sizcache = doneName; +					} + +					var diff = elem.nodeIndex - last; +					if ( first == 0 ) { +						return diff == 0; +					} else { +						return ( diff % first == 0 && diff / first >= 0 ); +					} +			} +		}, +		ID: function(elem, match){ +			return elem.nodeType === 1 && elem.getAttribute("id") === match; +		}, +		TAG: function(elem, match){ +			return (match === "*" && elem.nodeType === 1) || elem.nodeName === match; +		}, +		CLASS: function(elem, match){ +			return (" " + (elem.className || elem.getAttribute("class")) + " ") +				.indexOf( match ) > -1; +		}, +		ATTR: function(elem, match){ +			var name = match[1], +				result = Expr.attrHandle[ name ] ? +					Expr.attrHandle[ name ]( elem ) : +					elem[ name ] != null ? +						elem[ name ] : +						elem.getAttribute( name ), +				value = result + "", +				type = match[2], +				check = match[4]; + +			return result == null ? +				type === "!=" : +				type === "=" ? +				value === check : +				type === "*=" ? +				value.indexOf(check) >= 0 : +				type === "~=" ? +				(" " + value + " ").indexOf(check) >= 0 : +				!check ? +				value && result !== false : +				type === "!=" ? +				value != check : +				type === "^=" ? +				value.indexOf(check) === 0 : +				type === "$=" ? +				value.substr(value.length - check.length) === check : +				type === "|=" ? +				value === check || value.substr(0, check.length + 1) === check + "-" : +				false; +		}, +		POS: function(elem, match, i, array){ +			var name = match[2], filter = Expr.setFilters[ name ]; + +			if ( filter ) { +				return filter( elem, i, match, array ); +			} +		} +	} +}; + +var origPOS = Expr.match.POS; + +for ( var type in Expr.match ) { +	Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source ); +	Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source ); +} + +var makeArray = function(array, results) { +	array = Array.prototype.slice.call( array, 0 ); + +	if ( results ) { +		results.push.apply( results, array ); +		return results; +	} + +	return array; +}; + +try { +	Array.prototype.slice.call( document.documentElement.childNodes, 0 ); + +} catch(e){ +	makeArray = function(array, results) { +		var ret = results || []; + +		if ( toString.call(array) === "[object Array]" ) { +			Array.prototype.push.apply( ret, array ); +		} else { +			if ( typeof array.length === "number" ) { +				for ( var i = 0, l = array.length; i < l; i++ ) { +					ret.push( array[i] ); +				} +			} else { +				for ( var i = 0; array[i]; i++ ) { +					ret.push( array[i] ); +				} +			} +		} + +		return ret; +	}; +} + +var sortOrder; + +if ( document.documentElement.compareDocumentPosition ) { +	sortOrder = function( a, b ) { +		if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { +			if ( a == b ) { +				hasDuplicate = true; +			} +			return 0; +		} + +		var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; +		if ( ret === 0 ) { +			hasDuplicate = true; +		} +		return ret; +	}; +} else if ( "sourceIndex" in document.documentElement ) { +	sortOrder = function( a, b ) { +		if ( !a.sourceIndex || !b.sourceIndex ) { +			if ( a == b ) { +				hasDuplicate = true; +			} +			return 0; +		} + +		var ret = a.sourceIndex - b.sourceIndex; +		if ( ret === 0 ) { +			hasDuplicate = true; +		} +		return ret; +	}; +} else if ( document.createRange ) { +	sortOrder = function( a, b ) { +		if ( !a.ownerDocument || !b.ownerDocument ) { +			if ( a == b ) { +				hasDuplicate = true; +			} +			return 0; +		} + +		var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); +		aRange.setStart(a, 0); +		aRange.setEnd(a, 0); +		bRange.setStart(b, 0); +		bRange.setEnd(b, 0); +		var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange); +		if ( ret === 0 ) { +			hasDuplicate = true; +		} +		return ret; +	}; +} + +(function(){ +	var form = document.createElement("div"), +		id = "script" + (new Date).getTime(); +	form.innerHTML = "<a name='" + id + "'/>"; + +	var root = document.documentElement; +	root.insertBefore( form, root.firstChild ); + +	if ( !!document.getElementById( id ) ) { +		Expr.find.ID = function(match, context, isXML){ +			if ( typeof context.getElementById !== "undefined" && !isXML ) { +				var m = context.getElementById(match[1]); +				return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; +			} +		}; + +		Expr.filter.ID = function(elem, match){ +			var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); +			return elem.nodeType === 1 && node && node.nodeValue === match; +		}; +	} + +	root.removeChild( form ); +	root = form = null; // release memory in IE +})(); + +(function(){ + +	var div = document.createElement("div"); +	div.appendChild( document.createComment("") ); + +	if ( div.getElementsByTagName("*").length > 0 ) { +		Expr.find.TAG = function(match, context){ +			var results = context.getElementsByTagName(match[1]); + +			if ( match[1] === "*" ) { +				var tmp = []; + +				for ( var i = 0; results[i]; i++ ) { +					if ( results[i].nodeType === 1 ) { +						tmp.push( results[i] ); +					} +				} + +				results = tmp; +			} + +			return results; +		}; +	} + +	div.innerHTML = "<a href='#'></a>"; +	if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && +			div.firstChild.getAttribute("href") !== "#" ) { +		Expr.attrHandle.href = function(elem){ +			return elem.getAttribute("href", 2); +		}; +	} + +	div = null; // release memory in IE +})(); + +if ( document.querySelectorAll ) (function(){ +	var oldSizzle = Sizzle, div = document.createElement("div"); +	div.innerHTML = "<p class='TEST'></p>"; + +	if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { +		return; +	} + +	Sizzle = function(query, context, extra, seed){ +		context = context || document; + +		if ( !seed && context.nodeType === 9 && !isXML(context) ) { +			try { +				return makeArray( context.querySelectorAll(query), extra ); +			} catch(e){} +		} + +		return oldSizzle(query, context, extra, seed); +	}; + +	for ( var prop in oldSizzle ) { +		Sizzle[ prop ] = oldSizzle[ prop ]; +	} + +	div = null; // release memory in IE +})(); + +if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){ +	var div = document.createElement("div"); +	div.innerHTML = "<div class='test e'></div><div class='test'></div>"; + +	if ( div.getElementsByClassName("e").length === 0 ) +		return; + +	div.lastChild.className = "e"; + +	if ( div.getElementsByClassName("e").length === 1 ) +		return; + +	Expr.order.splice(1, 0, "CLASS"); +	Expr.find.CLASS = function(match, context, isXML) { +		if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { +			return context.getElementsByClassName(match[1]); +		} +	}; + +	div = null; // release memory in IE +})(); + +function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { +	var sibDir = dir == "previousSibling" && !isXML; +	for ( var i = 0, l = checkSet.length; i < l; i++ ) { +		var elem = checkSet[i]; +		if ( elem ) { +			if ( sibDir && elem.nodeType === 1 ){ +				elem.sizcache = doneName; +				elem.sizset = i; +			} +			elem = elem[dir]; +			var match = false; + +			while ( elem ) { +				if ( elem.sizcache === doneName ) { +					match = checkSet[elem.sizset]; +					break; +				} + +				if ( elem.nodeType === 1 && !isXML ){ +					elem.sizcache = doneName; +					elem.sizset = i; +				} + +				if ( elem.nodeName === cur ) { +					match = elem; +					break; +				} + +				elem = elem[dir]; +			} + +			checkSet[i] = match; +		} +	}  } -function $$() { -  return Selector.findChildElements(document, $A(arguments)); +function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { +	var sibDir = dir == "previousSibling" && !isXML; +	for ( var i = 0, l = checkSet.length; i < l; i++ ) { +		var elem = checkSet[i]; +		if ( elem ) { +			if ( sibDir && elem.nodeType === 1 ) { +				elem.sizcache = doneName; +				elem.sizset = i; +			} +			elem = elem[dir]; +			var match = false; + +			while ( elem ) { +				if ( elem.sizcache === doneName ) { +					match = checkSet[elem.sizset]; +					break; +				} + +				if ( elem.nodeType === 1 ) { +					if ( !isXML ) { +						elem.sizcache = doneName; +						elem.sizset = i; +					} +					if ( typeof cur !== "string" ) { +						if ( elem === cur ) { +							match = true; +							break; +						} + +					} else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { +						match = elem; +						break; +					} +				} + +				elem = elem[dir]; +			} + +			checkSet[i] = match; +		} +	}  } + +var contains = document.compareDocumentPosition ?  function(a, b){ +	return a.compareDocumentPosition(b) & 16; +} : function(a, b){ +	return a !== b && (a.contains ? a.contains(b) : true); +}; + +var isXML = function(elem){ +	return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" || +		!!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML"; +}; + +var posProcess = function(selector, context){ +	var tmpSet = [], later = "", match, +		root = context.nodeType ? [context] : context; + +	while ( (match = Expr.match.PSEUDO.exec( selector )) ) { +		later += match[0]; +		selector = selector.replace( Expr.match.PSEUDO, "" ); +	} + +	selector = Expr.relative[selector] ? selector + "*" : selector; + +	for ( var i = 0, l = root.length; i < l; i++ ) { +		Sizzle( selector, root[i], tmpSet ); +	} + +	return Sizzle.filter( later, tmpSet ); +}; + + +window.Sizzle = Sizzle; + +})(); + +;(function(engine) { +  var extendElements = Prototype.Selector.extendElements; + +  function select(selector, scope) { +    return extendElements(engine(selector, scope || document)); +  } + +  function match(element, selector) { +    return engine.matches(selector, [element]).length == 1; +  } + +  Prototype.Selector.engine = engine; +  Prototype.Selector.select = select; +  Prototype.Selector.match = match; +})(Sizzle); + +window.Sizzle = Prototype._original_property; +delete Prototype._original_property; +  var Form = {    reset: function(form) { -    $(form).reset(); +    form = $(form); +    form.reset();      return form;    }, @@ -3392,10 +4967,9 @@ var Form = {      var data = elements.inject({ }, function(result, element) {        if (!element.disabled && element.name) {          key = element.name; value = $(element).getValue(); -        if (value != null && (element.type != 'submit' || (!submitted && +        if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted &&              submit !== false && (!submit || key == submit) && (submitted = true)))) {            if (key in result) { -            // a key is already present; construct an array of values              if (!Object.isArray(result[key])) result[key] = [result[key]];              result[key].push(value);            } @@ -3415,13 +4989,18 @@ Form.Methods = {    },    getElements: function(form) { -    return $A($(form).getElementsByTagName('*')).inject([], -      function(elements, child) { -        if (Form.Element.Serializers[child.tagName.toLowerCase()]) -          elements.push(Element.extend(child)); -        return elements; -      } -    ); +    var elements = $(form).getElementsByTagName('*'), +        element, +        arr = [ ], +        serializers = Form.Element.Serializers; +    for (var i = 0; element = elements[i]; i++) { +      arr.push(element); +    } +    return arr.inject([], function(elements, child) { +      if (serializers[child.tagName.toLowerCase()]) +        elements.push(Element.extend(child)); +      return elements; +    })    },    getInputs: function(form, typeName, name) { @@ -3461,7 +5040,7 @@ Form.Methods = {      }).sortBy(function(element) { return element.tabIndex }).first();      return firstByIndex ? firstByIndex : elements.find(function(element) { -      return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); +      return /^(?:input|select|textarea)$/i.test(element.tagName);      });    }, @@ -3492,6 +5071,7 @@ Form.Methods = {  /*--------------------------------------------------------------------------*/ +  Form.Element = {    focus: function(element) {      $(element).focus(); @@ -3505,6 +5085,7 @@ Form.Element = {  };  Form.Element.Methods = { +    serialize: function(element) {      element = $(element);      if (!element.disabled && element.name) { @@ -3545,7 +5126,7 @@ Form.Element.Methods = {      try {        element.focus();        if (element.select && (element.tagName.toLowerCase() != 'input' || -          !['button', 'reset', 'submit'].include(element.type))) +          !(/^(?:button|reset|submit)$/i.test(element.type))))          element.select();      } catch (e) { }      return element; @@ -3553,7 +5134,6 @@ Form.Element.Methods = {    disable: function(element) {      element = $(element); -    element.blur();      element.disabled = true;      return element;    }, @@ -3568,6 +5148,7 @@ Form.Element.Methods = {  /*--------------------------------------------------------------------------*/  var Field = Form.Element; +  var $F = Form.Element.Methods.getValue;  /*--------------------------------------------------------------------------*/ @@ -3593,22 +5174,22 @@ Form.Element.Serializers = {      else element.value = value;    }, -  select: function(element, index) { -    if (Object.isUndefined(index)) +  select: function(element, value) { +    if (Object.isUndefined(value))        return this[element.type == 'select-one' ?          'selectOne' : 'selectMany'](element);      else { -      var opt, value, single = !Object.isArray(index); +      var opt, currentValue, single = !Object.isArray(value);        for (var i = 0, length = element.length; i < length; i++) {          opt = element.options[i]; -        value = this.optionValue(opt); +        currentValue = this.optionValue(opt);          if (single) { -          if (value == index) { +          if (currentValue == value) {              opt.selected = true;              return;            }          } -        else opt.selected = index.include(value); +        else opt.selected = value.include(currentValue);        }      }    }, @@ -3630,13 +5211,13 @@ Form.Element.Serializers = {    },    optionValue: function(opt) { -    // extend element because hasAttribute may not be native      return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;    }  };  /*--------------------------------------------------------------------------*/ +  Abstract.TimedObserver = Class.create(PeriodicalExecuter, {    initialize: function($super, element, frequency, callback) {      $super(callback, frequency); @@ -3718,323 +5299,475 @@ Form.EventObserver = Class.create(Abstract.EventObserver, {      return Form.serialize(this.element);    }  }); -if (!window.Event) var Event = { }; - -Object.extend(Event, { -  KEY_BACKSPACE: 8, -  KEY_TAB:       9, -  KEY_RETURN:   13, -  KEY_ESC:      27, -  KEY_LEFT:     37, -  KEY_UP:       38, -  KEY_RIGHT:    39, -  KEY_DOWN:     40, -  KEY_DELETE:   46, -  KEY_HOME:     36, -  KEY_END:      35, -  KEY_PAGEUP:   33, -  KEY_PAGEDOWN: 34, -  KEY_INSERT:   45, - -  cache: { }, - -  relatedTarget: function(event) { -    var element; -    switch(event.type) { -      case 'mouseover': element = event.fromElement; break; -      case 'mouseout':  element = event.toElement;   break; -      default: return null; -    } -    return Element.extend(element); -  } -}); +(function() { -Event.Methods = (function() { -  var isButton; +  var Event = { +    KEY_BACKSPACE: 8, +    KEY_TAB:       9, +    KEY_RETURN:   13, +    KEY_ESC:      27, +    KEY_LEFT:     37, +    KEY_UP:       38, +    KEY_RIGHT:    39, +    KEY_DOWN:     40, +    KEY_DELETE:   46, +    KEY_HOME:     36, +    KEY_END:      35, +    KEY_PAGEUP:   33, +    KEY_PAGEDOWN: 34, +    KEY_INSERT:   45, + +    cache: {} +  }; + +  var docEl = document.documentElement; +  var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl +    && 'onmouseleave' in docEl; +  var _isButton;    if (Prototype.Browser.IE) {      var buttonMap = { 0: 1, 1: 4, 2: 2 }; -    isButton = function(event, code) { -      return event.button == buttonMap[code]; +    _isButton = function(event, code) { +      return event.button === buttonMap[code];      }; -    } else if (Prototype.Browser.WebKit) { -    isButton = function(event, code) { +    _isButton = function(event, code) {        switch (code) {          case 0: return event.which == 1 && !event.metaKey;          case 1: return event.which == 1 && event.metaKey;          default: return false;        }      }; -    } else { -    isButton = function(event, code) { +    _isButton = function(event, code) {        return event.which ? (event.which === code + 1) : (event.button === code);      };    } -  return { -    isLeftClick:   function(event) { return isButton(event, 0) }, -    isMiddleClick: function(event) { return isButton(event, 1) }, -    isRightClick:  function(event) { return isButton(event, 2) }, +  function isLeftClick(event)   { return _isButton(event, 0) } -    element: function(event) { -      var node = Event.extend(event).target; -      return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode : node); -    }, +  function isMiddleClick(event) { return _isButton(event, 1) } -    findElement: function(event, expression) { -      var element = Event.element(event); -      if (!expression) return element; -      var elements = [element].concat(element.ancestors()); -      return Selector.findElement(elements, expression, 0); -    }, +  function isRightClick(event)  { return _isButton(event, 2) } -    pointer: function(event) { -      return { -        x: event.pageX || (event.clientX + -          (document.documentElement.scrollLeft || document.body.scrollLeft)), -        y: event.pageY || (event.clientY + -          (document.documentElement.scrollTop || document.body.scrollTop)) -      }; -    }, +  function element(event) { +    event = Event.extend(event); + +    var node = event.target, type = event.type, +     currentTarget = event.currentTarget; + +    if (currentTarget && currentTarget.tagName) { +      if (type === 'load' || type === 'error' || +        (type === 'click' && currentTarget.tagName.toLowerCase() === 'input' +          && currentTarget.type === 'radio')) +            node = currentTarget; +    } -    pointerX: function(event) { return Event.pointer(event).x }, -    pointerY: function(event) { return Event.pointer(event).y }, +    if (node.nodeType == Node.TEXT_NODE) +      node = node.parentNode; -    stop: function(event) { -      Event.extend(event); -      event.preventDefault(); -      event.stopPropagation(); -      event.stopped = true; +    return Element.extend(node); +  } + +  function findElement(event, expression) { +    var element = Event.element(event); +    if (!expression) return element; +    while (element) { +      if (Object.isElement(element) && Prototype.Selector.match(element, expression)) { +        return Element.extend(element); +      } +      element = element.parentNode;      } +  } + +  function pointer(event) { +    return { x: pointerX(event), y: pointerY(event) }; +  } + +  function pointerX(event) { +    var docElement = document.documentElement, +     body = document.body || { scrollLeft: 0 }; + +    return event.pageX || (event.clientX + +      (docElement.scrollLeft || body.scrollLeft) - +      (docElement.clientLeft || 0)); +  } + +  function pointerY(event) { +    var docElement = document.documentElement, +     body = document.body || { scrollTop: 0 }; + +    return  event.pageY || (event.clientY + +       (docElement.scrollTop || body.scrollTop) - +       (docElement.clientTop || 0)); +  } + + +  function stop(event) { +    Event.extend(event); +    event.preventDefault(); +    event.stopPropagation(); + +    event.stopped = true; +  } + +  Event.Methods = { +    isLeftClick: isLeftClick, +    isMiddleClick: isMiddleClick, +    isRightClick: isRightClick, + +    element: element, +    findElement: findElement, + +    pointer: pointer, +    pointerX: pointerX, +    pointerY: pointerY, + +    stop: stop    }; -})(); -Event.extend = (function() { +    var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {      m[name] = Event.Methods[name].methodize();      return m;    });    if (Prototype.Browser.IE) { +    function _relatedTarget(event) { +      var element; +      switch (event.type) { +        case 'mouseover': element = event.fromElement; break; +        case 'mouseout':  element = event.toElement;   break; +        default: return null; +      } +      return Element.extend(element); +    } +      Object.extend(methods, {        stopPropagation: function() { this.cancelBubble = true },        preventDefault:  function() { this.returnValue = false }, -      inspect: function() { return "[object Event]" } +      inspect: function() { return '[object Event]' }      }); -    return function(event) { +    Event.extend = function(event, element) {        if (!event) return false;        if (event._extendedByPrototype) return event;        event._extendedByPrototype = Prototype.emptyFunction;        var pointer = Event.pointer(event); +        Object.extend(event, { -        target: event.srcElement, -        relatedTarget: Event.relatedTarget(event), +        target: event.srcElement || element, +        relatedTarget: _relatedTarget(event),          pageX:  pointer.x,          pageY:  pointer.y        }); +        return Object.extend(event, methods);      }; -    } else { -    Event.prototype = Event.prototype || document.createEvent("HTMLEvents").__proto__; +    Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__;      Object.extend(Event.prototype, methods); -    return Prototype.K; +    Event.extend = Prototype.K;    } -})(); -Object.extend(Event, (function() { -  var cache = Event.cache; +  function _createResponder(element, eventName, handler) { +    var registry = Element.retrieve(element, 'prototype_event_registry'); -  function getEventID(element) { -    if (element._eventID) return element._eventID; -    arguments.callee.id = arguments.callee.id || 1; -    return element._eventID = ++arguments.callee.id; -  } - -  function getDOMEventName(eventName) { -    if (eventName && eventName.include(':')) return "dataavailable"; -    return eventName; -  } +    if (Object.isUndefined(registry)) { +      CACHE.push(element); +      registry = Element.retrieve(element, 'prototype_event_registry', $H()); +    } -  function getCacheForID(id) { -    return cache[id] = cache[id] || { }; -  } +    var respondersForEvent = registry.get(eventName); +    if (Object.isUndefined(respondersForEvent)) { +      respondersForEvent = []; +      registry.set(eventName, respondersForEvent); +    } -  function getWrappersForEventName(id, eventName) { -    var c = getCacheForID(id); -    return c[eventName] = c[eventName] || []; -  } +    if (respondersForEvent.pluck('handler').include(handler)) return false; -  function createWrapper(element, eventName, handler) { -    var id = getEventID(element); -    var c = getWrappersForEventName(id, eventName); -    if (c.pluck("handler").include(handler)) return false; +    var responder; +    if (eventName.include(":")) { +      responder = function(event) { +        if (Object.isUndefined(event.eventName)) +          return false; -    var wrapper = function(event) { -      if (!Event || !Event.extend || -        (event.eventName && event.eventName != eventName)) +        if (event.eventName !== eventName)            return false; -      Event.extend(event); -      handler.call(element, event) -    }; +        Event.extend(event, element); +        handler.call(element, event); +      }; +    } else { +      if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED && +       (eventName === "mouseenter" || eventName === "mouseleave")) { +        if (eventName === "mouseenter" || eventName === "mouseleave") { +          responder = function(event) { +            Event.extend(event, element); + +            var parent = event.relatedTarget; +            while (parent && parent !== element) { +              try { parent = parent.parentNode; } +              catch(e) { parent = element; } +            } -    wrapper.handler = handler; -    c.push(wrapper); -    return wrapper; -  } +            if (parent === element) return; -  function findWrapper(id, eventName, handler) { -    var c = getWrappersForEventName(id, eventName); -    return c.find(function(wrapper) { return wrapper.handler == handler }); -  } +            handler.call(element, event); +          }; +        } +      } else { +        responder = function(event) { +          Event.extend(event, element); +          handler.call(element, event); +        }; +      } +    } -  function destroyWrapper(id, eventName, handler) { -    var c = getCacheForID(id); -    if (!c[eventName]) return false; -    c[eventName] = c[eventName].without(findWrapper(id, eventName, handler)); +    responder.handler = handler; +    respondersForEvent.push(responder); +    return responder;    } -  function destroyCache() { -    for (var id in cache) -      for (var eventName in cache[id]) -        cache[id][eventName] = null; +  function _destroyCache() { +    for (var i = 0, length = CACHE.length; i < length; i++) { +      Event.stopObserving(CACHE[i]); +      CACHE[i] = null; +    }    } -  if (window.attachEvent) { -    window.attachEvent("onunload", destroyCache); +  var CACHE = []; + +  if (Prototype.Browser.IE) +    window.attachEvent('onunload', _destroyCache); + +  if (Prototype.Browser.WebKit) +    window.addEventListener('unload', Prototype.emptyFunction, false); + + +  var _getDOMEventName = Prototype.K, +      translations = { mouseenter: "mouseover", mouseleave: "mouseout" }; + +  if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED) { +    _getDOMEventName = function(eventName) { +      return (translations[eventName] || eventName); +    };    } -  return { -    observe: function(element, eventName, handler) { -      element = $(element); -      var name = getDOMEventName(eventName); +  function observe(element, eventName, handler) { +    element = $(element); -      var wrapper = createWrapper(element, eventName, handler); -      if (!wrapper) return element; +    var responder = _createResponder(element, eventName, handler); -      if (element.addEventListener) { -        element.addEventListener(name, wrapper, false); -      } else { -        element.attachEvent("on" + name, wrapper); +    if (!responder) return element; + +    if (eventName.include(':')) { +      if (element.addEventListener) +        element.addEventListener("dataavailable", responder, false); +      else { +        element.attachEvent("ondataavailable", responder); +        element.attachEvent("onfilterchange", responder);        } +    } else { +      var actualEventName = _getDOMEventName(eventName); + +      if (element.addEventListener) +        element.addEventListener(actualEventName, responder, false); +      else +        element.attachEvent("on" + actualEventName, responder); +    } + +    return element; +  } + +  function stopObserving(element, eventName, handler) { +    element = $(element); + +    var registry = Element.retrieve(element, 'prototype_event_registry'); +    if (!registry) return element; +    if (!eventName) { +      registry.each( function(pair) { +        var eventName = pair.key; +        stopObserving(element, eventName); +      });        return element; -    }, +    } -    stopObserving: function(element, eventName, handler) { -      element = $(element); -      var id = getEventID(element), name = getDOMEventName(eventName); +    var responders = registry.get(eventName); +    if (!responders) return element; -      if (!handler && eventName) { -        getWrappersForEventName(id, eventName).each(function(wrapper) { -          element.stopObserving(eventName, wrapper.handler); -        }); -        return element; +    if (!handler) { +      responders.each(function(r) { +        stopObserving(element, eventName, r.handler); +      }); +      return element; +    } -      } else if (!eventName) { -        Object.keys(getCacheForID(id)).each(function(eventName) { -          element.stopObserving(eventName); -        }); -        return element; +    var responder = responders.find( function(r) { return r.handler === handler; }); +    if (!responder) return element; + +    if (eventName.include(':')) { +      if (element.removeEventListener) +        element.removeEventListener("dataavailable", responder, false); +      else { +        element.detachEvent("ondataavailable", responder); +        element.detachEvent("onfilterchange",  responder);        } +    } else { +      var actualEventName = _getDOMEventName(eventName); +      if (element.removeEventListener) +        element.removeEventListener(actualEventName, responder, false); +      else +        element.detachEvent('on' + actualEventName, responder); +    } -      var wrapper = findWrapper(id, eventName, handler); -      if (!wrapper) return element; +    registry.set(eventName, responders.without(responder)); -      if (element.removeEventListener) { -        element.removeEventListener(name, wrapper, false); -      } else { -        element.detachEvent("on" + name, wrapper); -      } +    return element; +  } -      destroyWrapper(id, eventName, handler); +  function fire(element, eventName, memo, bubble) { +    element = $(element); -      return element; -    }, +    if (Object.isUndefined(bubble)) +      bubble = true; -    fire: function(element, eventName, memo) { -      element = $(element); -      if (element == document && document.createEvent && !element.dispatchEvent) -        element = document.documentElement; +    if (element == document && document.createEvent && !element.dispatchEvent) +      element = document.documentElement; -      if (document.createEvent) { -        var event = document.createEvent("HTMLEvents"); -        event.initEvent("dataavailable", true, true); -      } else { -        var event = document.createEventObject(); -        event.eventType = "ondataavailable"; -      } +    var event; +    if (document.createEvent) { +      event = document.createEvent('HTMLEvents'); +      event.initEvent('dataavailable', true, true); +    } else { +      event = document.createEventObject(); +      event.eventType = bubble ? 'ondataavailable' : 'onfilterchange'; +    } -      event.eventName = eventName; -      event.memo = memo || { }; +    event.eventName = eventName; +    event.memo = memo || { }; -      if (document.createEvent) { -        element.dispatchEvent(event); -      } else { -        element.fireEvent(event.eventType, event); -      } +    if (document.createEvent) +      element.dispatchEvent(event); +    else +      element.fireEvent(event.eventType, event); + +    return Event.extend(event); +  } + +  Event.Handler = Class.create({ +    initialize: function(element, eventName, selector, callback) { +      this.element   = $(element); +      this.eventName = eventName; +      this.selector  = selector; +      this.callback  = callback; +      this.handler   = this.handleEvent.bind(this); +    }, -      return Event.extend(event); +    start: function() { +      Event.observe(this.element, this.eventName, this.handler); +      return this; +    }, + +    stop: function() { +      Event.stopObserving(this.element, this.eventName, this.handler); +      return this; +    }, + +    handleEvent: function(event) { +      var element = event.findElement(this.selector); +      if (element) this.callback.call(this.element, event, element);      } -  }; -})()); +  }); -Object.extend(Event, Event.Methods); +  function on(element, eventName, selector, callback) { +    element = $(element); +    if (Object.isFunction(selector) && Object.isUndefined(callback)) { +      callback = selector, selector = null; +    } -Element.addMethods({ -  fire:          Event.fire, -  observe:       Event.observe, -  stopObserving: Event.stopObserving -}); +    return new Event.Handler(element, eventName, selector, callback).start(); +  } -Object.extend(document, { -  fire:          Element.Methods.fire.methodize(), -  observe:       Element.Methods.observe.methodize(), -  stopObserving: Element.Methods.stopObserving.methodize() -}); +  Object.extend(Event, Event.Methods); + +  Object.extend(Event, { +    fire:          fire, +    observe:       observe, +    stopObserving: stopObserving, +    on:            on +  }); + +  Element.addMethods({ +    fire:          fire, + +    observe:       observe, + +    stopObserving: stopObserving, + +    on:            on +  }); + +  Object.extend(document, { +    fire:          fire.methodize(), + +    observe:       observe.methodize(), + +    stopObserving: stopObserving.methodize(), + +    on:            on.methodize(), + +    loaded:        false +  }); + +  if (window.Event) Object.extend(window.Event, Event); +  else window.Event = Event; +})();  (function() {    /* Support for the DOMContentLoaded event is based on work by Dan Webb, -     Matthias Miller, Dean Edwards and John Resig. */ +     Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */ -  var timer, fired = false; +  var timer;    function fireContentLoadedEvent() { -    if (fired) return; -    if (timer) window.clearInterval(timer); -    document.fire("dom:loaded"); -    fired = true; +    if (document.loaded) return; +    if (timer) window.clearTimeout(timer); +    document.loaded = true; +    document.fire('dom:loaded');    } -  if (document.addEventListener) { -    if (Prototype.Browser.WebKit) { -      timer = window.setInterval(function() { -        if (/loaded|complete/.test(document.readyState)) -          fireContentLoadedEvent(); -      }, 0); - -      Event.observe(window, "load", fireContentLoadedEvent); +  function checkReadyState() { +    if (document.readyState === 'complete') { +      document.stopObserving('readystatechange', checkReadyState); +      fireContentLoadedEvent(); +    } +  } -    } else { -      document.addEventListener("DOMContentLoaded", -        fireContentLoadedEvent, false); +  function pollDoScroll() { +    try { document.documentElement.doScroll('left'); } +    catch(e) { +      timer = pollDoScroll.defer(); +      return;      } +    fireContentLoadedEvent(); +  } +  if (document.addEventListener) { +    document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false);    } else { -    document.write("<script id=__onDOMContentLoaded defer src=//:><\/script>"); -    $("__onDOMContentLoaded").onreadystatechange = function() { -      if (this.readyState == "complete") { -        this.onreadystatechange = null; -        fireContentLoadedEvent(); -      } -    }; +    document.observe('readystatechange', checkReadyState); +    if (window == top) +      timer = pollDoScroll.defer();    } + +  Event.observe(window, 'load', fireContentLoadedEvent);  })(); + +Element.addMethods(); +  /*------------------------------- DEPRECATED -------------------------------*/  Hash.toQueryString = Object.toQueryString; @@ -4063,16 +5796,9 @@ var Insertion = {  var $continue = new Error('"throw $continue" is deprecated, use "return" instead'); -// This should be moved to script.aculo.us; notice the deprecated methods -// further below, that map to the newer Element methods.  var Position = { -  // set to true if needed, warning: firefox performance problems -  // NOT neeeded for page scrolling, only if draggable contained in -  // scrollable elements    includeScrollOffsets: false, -  // must be called before calling withinIncludingScrolloffset, every time the -  // page is scrolled    prepare: function() {      this.deltaX =  window.pageXOffset                  || document.documentElement.scrollLeft @@ -4084,7 +5810,6 @@ var Position = {                  || 0;    }, -  // caches x/y coordinate pair to use with overlap    within: function(element, x, y) {      if (this.includeScrollOffsets)        return this.withinIncludingScrolloffsets(element, x, y); @@ -4111,7 +5836,6 @@ var Position = {              this.xcomp <  this.offset[0] + element.offsetWidth);    }, -  // within must be called directly before    overlap: function(mode, element) {      if (!mode) return 0;      if (mode == 'vertical') @@ -4122,7 +5846,6 @@ var Position = {          element.offsetWidth;    }, -  // Deprecation layer -- use newer Element methods now (1.5.2).    cumulativeOffset: Element.Methods.cumulativeOffset, @@ -4222,4 +5945,57 @@ Object.extend(Element.ClassNames.prototype, Enumerable);  /*--------------------------------------------------------------------------*/ -Element.addMethods();
\ No newline at end of file +(function() { +  window.Selector = Class.create({ +    initialize: function(expression) { +      this.expression = expression.strip(); +    }, + +    findElements: function(rootElement) { +      return Prototype.Selector.select(this.expression, rootElement); +    }, + +    match: function(element) { +      return Prototype.Selector.match(element, this.expression); +    }, + +    toString: function() { +      return this.expression; +    }, + +    inspect: function() { +      return "#<Selector: " + this.expression + ">"; +    } +  }); + +  Object.extend(Selector, { +    matchElements: function(elements, expression) { +      var match = Prototype.Selector.match, +          results = []; + +      for (var i = 0, length = elements.length; i < length; i++) { +        var element = elements[i]; +        if (match(element, expression)) { +          results.push(Element.extend(element)); +        } +      } +      return results; +    }, + +    findElement: function(elements, expression, index) { +      index = index || 0; +      var matchIndex = 0, element; +      for (var i = 0, length = elements.length; i < length; i++) { +        element = elements[i]; +        if (Prototype.Selector.match(element, expression) && index === matchIndex++) { +          return Element.extend(element); +        } +      } +    }, + +    findChildElements: function(element, expressions) { +      var selector = expressions.toArray().join(', '); +      return Prototype.Selector.select(selector, element || document); +    } +  }); +})(); diff --git a/public/javascripts/rails.js b/public/javascripts/rails.js new file mode 100644 index 000000000..5cea13c15 --- /dev/null +++ b/public/javascripts/rails.js @@ -0,0 +1,202 @@ +(function() { +  Ajax.Responders.register({ +    onCreate: function(request) { +      var token = $$('meta[name=csrf-token]')[0]; +      if (token) { +        if (!request.options.requestHeaders) request.options.requestHeaders = {}; +        request.options.requestHeaders['X-CSRF-Token'] = token.readAttribute('content'); +      } +    } +  }); + +  // Technique from Juriy Zaytsev +  // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ +  function isEventSupported(eventName) { +    var el = document.createElement('div'); +    eventName = 'on' + eventName; +    var isSupported = (eventName in el); +    if (!isSupported) { +      el.setAttribute(eventName, 'return;'); +      isSupported = typeof el[eventName] == 'function'; +    } +    el = null; +    return isSupported; +  } + +  function isForm(element) { +    return Object.isElement(element) && element.nodeName.toUpperCase() == 'FORM'; +  } + +  function isInput(element) { +    if (Object.isElement(element)) { +      var name = element.nodeName.toUpperCase(); +      return name == 'INPUT' || name == 'SELECT' || name == 'TEXTAREA'; +    } +    else return false; +  } + +  var submitBubbles = isEventSupported('submit'), +      changeBubbles = isEventSupported('change'); + +  if (!submitBubbles || !changeBubbles) { +    // augment the Event.Handler class to observe custom events when needed +    Event.Handler.prototype.initialize = Event.Handler.prototype.initialize.wrap( +      function(init, element, eventName, selector, callback) { +        init(element, eventName, selector, callback); +        // is the handler being attached to an element that doesn't support this event? +        if ( (!submitBubbles && this.eventName == 'submit' && !isForm(this.element)) || +             (!changeBubbles && this.eventName == 'change' && !isInput(this.element)) ) { +          // "submit" => "emulated:submit" +          this.eventName = 'emulated:' + this.eventName; +        } +      } +    ); +  } + +  if (!submitBubbles) { +    // discover forms on the page by observing focus events which always bubble +    document.on('focusin', 'form', function(focusEvent, form) { +      // special handler for the real "submit" event (one-time operation) +      if (!form.retrieve('emulated:submit')) { +        form.on('submit', function(submitEvent) { +          var emulated = form.fire('emulated:submit', submitEvent, true); +          // if custom event received preventDefault, cancel the real one too +          if (emulated.returnValue === false) submitEvent.preventDefault(); +        }); +        form.store('emulated:submit', true); +      } +    }); +  } + +  if (!changeBubbles) { +    // discover form inputs on the page +    document.on('focusin', 'input, select, textarea', function(focusEvent, input) { +      // special handler for real "change" events +      if (!input.retrieve('emulated:change')) { +        input.on('change', function(changeEvent) { +          input.fire('emulated:change', changeEvent, true); +        }); +        input.store('emulated:change', true); +      } +    }); +  } + +  function handleRemote(element) { +    var method, url, params; + +    var event = element.fire("ajax:before"); +    if (event.stopped) return false; + +    if (element.tagName.toLowerCase() === 'form') { +      method = element.readAttribute('method') || 'post'; +      url    = element.readAttribute('action'); +      // serialize the form with respect to the submit button that was pressed +      params = element.serialize({ submit: element.retrieve('rails:submit-button') }); +      // clear the pressed submit button information +      element.store('rails:submit-button', null); +    } else { +      method = element.readAttribute('data-method') || 'get'; +      url    = element.readAttribute('href'); +      params = {}; +    } + +    new Ajax.Request(url, { +      method: method, +      parameters: params, +      evalScripts: true, + +      onCreate:   function(response) { element.fire("ajax:create",   response); }, +      onComplete: function(response) { element.fire("ajax:complete", response); }, +      onSuccess:  function(response) { element.fire("ajax:success",  response); }, +      onFailure:  function(response) { element.fire("ajax:failure",  response); } +    }); + +    element.fire("ajax:after"); +  } + +  function insertHiddenField(form, name, value) { +    form.insert(new Element('input', { type: 'hidden', name: name, value: value })); +  } + +  function handleMethod(element) { +    var method = element.readAttribute('data-method'), +        url = element.readAttribute('href'), +        csrf_param = $$('meta[name=csrf-param]')[0], +        csrf_token = $$('meta[name=csrf-token]')[0]; + +    var form = new Element('form', { method: "POST", action: url, style: "display: none;" }); +    $(element.parentNode).insert(form); + +    if (method !== 'post') { +      insertHiddenField(form, '_method', method); +    } + +    if (csrf_param) { +      insertHiddenField(form, csrf_param.readAttribute('content'), csrf_token.readAttribute('content')); +    } + +    form.submit(); +  } + +  function disableFormElements(form) { +    form.select('input[type=submit][data-disable-with]').each(function(input) { +      input.store('rails:original-value', input.getValue()); +      input.setValue(input.readAttribute('data-disable-with')).disable(); +    }); +  } + +  function enableFormElements(form) { +    form.select('input[type=submit][data-disable-with]').each(function(input) { +      input.setValue(input.retrieve('rails:original-value')).enable(); +    }); +  } + +  function allowAction(element) { +    var message = element.readAttribute('data-confirm'); +    return !message || confirm(message); +  } + +  document.on('click', 'a[data-confirm], a[data-remote], a[data-method]', function(event, link) { +    if (!allowAction(link)) { +      event.stop(); +      return false; +    } + +    if (link.readAttribute('data-remote')) { +      handleRemote(link); +      event.stop(); +    } else if (link.readAttribute('data-method')) { +      handleMethod(link); +      event.stop(); +    } +  }); + +  document.on("click", "form input[type=submit], form button[type=submit], form button:not([type])", function(event, button) { +    // register the pressed submit button +    event.findElement('form').store('rails:submit-button', button.name || false); +  }); + +  document.on("submit", function(event) { +    var form = event.findElement(); + +    if (!allowAction(form)) { +      event.stop(); +      return false; +    } + +    if (form.readAttribute('data-remote')) { +      handleRemote(form); +      event.stop(); +    } else { +      disableFormElements(form); +    } +  }); + +  document.on('ajax:create', 'form', function(event, form) { +    if (form == event.findElement()) disableFormElements(form); +  }); + +  document.on('ajax:complete', 'form', function(event, form) { +    if (form == event.findElement()) enableFormElements(form); +  }); +})(); diff --git a/script/cache-incoming-emails b/script/cache-incoming-emails index 0b3069bd7..0b3069bd7 100644..100755 --- a/script/cache-incoming-emails +++ b/script/cache-incoming-emails diff --git a/script/rails b/script/rails new file mode 100755 index 000000000..f8da2cffd --- /dev/null +++ b/script/rails @@ -0,0 +1,6 @@ +#!/usr/bin/env ruby +# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. + +APP_PATH = File.expand_path('../../config/application',  __FILE__) +require File.expand_path('../../config/boot',  __FILE__) +require 'rails/commands'  | 
