I spent a bit of time yesterday/today going through the Deltacloud Aggregator, updating the necessary components to work with Rails 3. Obviously I won't push for this patch to be included until Rails 3 is in Fedora, but the good news is that most everything seems to be working in the aggregator against it.
Some more work needs to be done to get the feature suite fully functional again and some additional fixes are needed for various things (mostly to not rely on rails functionality which is there but deprecated), but currently the webapp itself works as it does w/ Rails 2.3.x and the spec suite is 100% functional.
Here are some specific points of interest about this patch:
- I tested it on Fedora 14, shipping with Ruby 1.8.7, and with Rails 3 installed via 'sudo gem install rails -v 3.0.1'
- Rails 3 has many various configuration changes: * gem dependencies are now managed via Bundler and listed in the Gemfile. Install them with 'bundle install' (as opposed to 'rake gems:install' as instructed in the install docs). We actually may be able to use this to our advantage by parsing this file in our build system and using it to generate the Requires in the rpm spec
* routes.rb has been overhauled, and I had to make some changes in the app to bring things in line
* all the scripts/ have been replaced with scripts/rails
- All the gems and plugins we depend on seem to have been updated to work against Rails 3. The upstream communities seem to be on the ball regarding this matter
- I updated the spec suite to fully work against rails 3 and the updated dependencies. I also did alot to fix the cucumber feature suite, but this is not fully finished. I didn't touch the test suite at all as this is deprecated, and should be removed at somepoint soon
- Some things have been deprecated / changed in the Rails API which affect us: - overriding the 'validate' method in the models is deprected and we need to update those classes to register our own validation method (eg validate :foo_validation_method)
- authlogic doesn't work 100% with rails 3, and I had to add a small hack to app/models/user_session.rb to get things working again (see relevant comment in that file)
- error_messages for forms is not directly supported in rails 3 as it was in 2, rather its a plugin that needs to be seperately installed (and thus we need to package)
- log_error doesn't seem to be present in rails anymore, so I had to substitute it in the application controller with what the method used to do (simply log the error to the rails logger)
I'll continue to fix the app to bring it in line with the new way of doing things and we might need to change a few things here and there, but for the most part everything looks pretty good concerning supporting Deltacloud on Rails 3.
-Mo
From: Mo Morsi mmorsi@redhat.com
--- src/.gitignore | 5 +- src/.project | 12 - src/.rspec | 1 + src/Gemfile | 56 + src/Gemfile.lock | 156 + src/Rakefile | 8 +- src/app/controllers/application_controller.rb | 10 +- src/app/controllers/users_controller.rb | 8 +- src/app/helpers/templates_helper.rb | 2 +- src/app/models/instance.rb | 2 +- src/app/models/search_filter.rb | 2 +- src/app/models/user_session.rb | 5 + src/app/views/user_sessions/new.haml | 2 +- src/autotest/discover.rb | 2 + src/config.ru | 9 +- src/config/application.rb | 58 + src/config/boot.rb | 123 +- src/config/environment.rb | 102 +- src/config/environments/cucumber.rb | 29 - src/config/environments/development.rb | 53 +- src/config/environments/production.rb | 87 +- src/config/environments/test.rb | 77 +- src/config/initializers/backtrace_silencers.rb | 4 +- src/config/initializers/new_rails_defaults.rb | 19 - src/config/initializers/secret_token.rb | 7 + src/config/initializers/session_store.rb | 4 +- src/config/routes.rb | 106 +- src/db/seeds.rb | 7 + src/features/step_definitions/web_steps.rb | 16 +- src/features/support/env.rb | 18 +- src/features/support/paths.rb | 7 +- src/lib/tasks/cucumber.rake | 33 +- src/lib/tasks/rspec.rake | 157 - src/public/401.html | 40 - src/public/404.html | 34 +- src/public/422.html | 26 + src/public/500.html | 36 +- src/public/dispatch.cgi | 10 - src/public/dispatch.fcgi | 24 - src/public/dispatch.rb | 29 - src/public/images/rails.png | Bin 0 -> 6646 bytes src/public/javascripts/controls.js | 8 +- src/public/javascripts/dragdrop.js | 13 +- src/public/javascripts/effects.js | 21 +- src/public/javascripts/prototype.js | 5081 +++++++++++++------- src/public/javascripts/rails.js | 175 + src/public/robots.txt | 6 +- src/script/about | 3 - src/script/autospec | 6 - src/script/breakpointer | 3 - src/script/console | 3 - src/script/dbconsole | 3 - src/script/destroy | 3 - src/script/generate | 3 - src/script/performance/benchmarker | 3 - src/script/performance/profiler | 3 - src/script/performance/request | 3 - src/script/plugin | 3 - src/script/process/inspector | 3 - src/script/process/reaper | 3 - src/script/process/spawner | 3 - src/script/rails | 6 + src/script/runner | 3 - src/script/server | 9 - src/script/spec | 10 - .../controllers/cloud_accounts_controller_spec.rb | 1 + src/spec/controllers/dashboard_controller_spec.rb | 1 + .../hardware_profiles_controller_spec.rb | 1 + src/spec/controllers/instance_controller_spec.rb | 2 + src/spec/controllers/pools_controller_spec.rb | 12 +- src/spec/controllers/provider_controller_spec.rb | 1 + src/spec/controllers/templates_controller_spec.rb | 1 + .../controllers/user_sessions_controller_spec.rb | 4 +- src/spec/controllers/users_controller_spec.rb | 27 +- src/spec/models/provider_spec.rb | 3 +- src/spec/models/registration_service_spec.rb | 2 +- src/spec/services/registration_service_spec.rb | 4 +- src/spec/spec.opts | 2 - src/spec/spec_helper.rb | 69 +- src/test/performance/browsing_test.rb | 9 + 80 files changed, 4233 insertions(+), 2669 deletions(-) delete mode 100644 src/.project create mode 100644 src/.rspec create mode 100644 src/Gemfile create mode 100644 src/Gemfile.lock create mode 100644 src/autotest/discover.rb create mode 100644 src/config/application.rb delete mode 100644 src/config/environments/cucumber.rb delete mode 100644 src/config/initializers/new_rails_defaults.rb create mode 100644 src/config/initializers/secret_token.rb create mode 100644 src/db/seeds.rb create mode 100644 src/lib/tasks/.gitkeep delete mode 100644 src/lib/tasks/rspec.rake delete mode 100644 src/public/401.html create mode 100644 src/public/422.html delete mode 100755 src/public/dispatch.cgi delete mode 100755 src/public/dispatch.fcgi delete mode 100755 src/public/dispatch.rb create mode 100644 src/public/images/rails.png create mode 100644 src/public/javascripts/rails.js create mode 100644 src/public/stylesheets/.gitkeep delete mode 100755 src/script/about delete mode 100755 src/script/autospec delete mode 100755 src/script/breakpointer delete mode 100755 src/script/console delete mode 100755 src/script/dbconsole delete mode 100755 src/script/destroy delete mode 100755 src/script/generate delete mode 100755 src/script/performance/benchmarker delete mode 100755 src/script/performance/profiler delete mode 100755 src/script/performance/request delete mode 100755 src/script/plugin delete mode 100755 src/script/process/inspector delete mode 100755 src/script/process/reaper delete mode 100755 src/script/process/spawner create mode 100755 src/script/rails delete mode 100755 src/script/runner delete mode 100755 src/script/server delete mode 100755 src/script/spec create mode 100644 src/test/performance/browsing_test.rb
diff --git a/src/.gitignore b/src/.gitignore index 6cddb31..af64fae 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1 +1,4 @@ -po +.bundle +db/*.sqlite3 +log/*.log +tmp/**/* diff --git a/src/.project b/src/.project deleted file mode 100644 index 244f341..0000000 --- a/src/.project +++ /dev/null @@ -1,12 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<projectDescription> - <name>oVirt Server</name> - <comment></comment> - <projects> - </projects> - <buildSpec> - </buildSpec> - <natures> - <nature>com.aptana.ide.project.nature.web</nature> - </natures> -</projectDescription> diff --git a/src/.rspec b/src/.rspec new file mode 100644 index 0000000..53607ea --- /dev/null +++ b/src/.rspec @@ -0,0 +1 @@ +--colour diff --git a/src/Gemfile b/src/Gemfile new file mode 100644 index 0000000..a5c4fc9 --- /dev/null +++ b/src/Gemfile @@ -0,0 +1,56 @@ +source 'http://rubygems.org' + +gem 'rails', '3.0.1' + +# Bundle edge Rails instead: +# gem 'rails', :git => 'git://github.com/rails/rails.git' + +gem 'sqlite3-ruby', :require => 'sqlite3' + +# Use unicorn as the web server +# gem 'unicorn' + +# Deploy with Capistrano +# gem 'capistrano' + +# To use debugger +# gem 'ruby-debug' + +# Bundle the extra gems: +# gem 'bj' +# gem 'nokogiri' +# gem 'sqlite3-ruby', :require => 'sqlite3' +# gem 'aws-s3', :require => 'aws/s3' + +# Bundle gems for the local environment. Make sure to +# put test-only gems in this group so their generators +# and rake tasks are available in development mode: +# group :development, :test do +# gem 'webrat' +# end + +gem 'authlogic' +gem 'deltacloud-client', '>= 0.0.9.8', :require => 'deltacloud' +gem 'haml' +gem 'will_paginate', '>= 3.0.pre2' +gem 'nokogiri', '>= 1.4.0' +gem 'gnuplot' +gem 'scruffy' +gem 'compass', '>= 0.10.2' +gem 'compass-960-plugin', :require => 'ninesixty' +gem 'simple-navigation' +gem 'typhoeus' +gem 'rb-inotify' +gem 'json' + +group :development, :test do + gem 'rspec-rails', '~> 2.0.1' + gem 'autotest' + gem 'factory_girl_rails' + gem 'timecop' + + gem 'cucumber' + gem 'cucumber-rails' + gem 'database_cleaner', '>=0.5.0' + gem 'webrat', '>=0.7.2' +end diff --git a/src/Gemfile.lock b/src/Gemfile.lock new file mode 100644 index 0000000..94a344f --- /dev/null +++ b/src/Gemfile.lock @@ -0,0 +1,156 @@ +GEM + remote: http://rubygems.org/ + specs: + abstract (1.0.0) + actionmailer (3.0.1) + actionpack (= 3.0.1) + mail (~> 2.2.5) + actionpack (3.0.1) + activemodel (= 3.0.1) + activesupport (= 3.0.1) + builder (~> 2.1.2) + erubis (~> 2.6.6) + i18n (~> 0.4.1) + rack (~> 1.2.1) + rack-mount (~> 0.6.12) + rack-test (~> 0.5.4) + tzinfo (~> 0.3.23) + activemodel (3.0.1) + activesupport (= 3.0.1) + builder (~> 2.1.2) + i18n (~> 0.4.1) + activerecord (3.0.1) + activemodel (= 3.0.1) + activesupport (= 3.0.1) + arel (~> 1.0.0) + tzinfo (~> 0.3.23) + activeresource (3.0.1) + activemodel (= 3.0.1) + activesupport (= 3.0.1) + activesupport (3.0.1) + arel (1.0.1) + activesupport (~> 3.0.0) + authlogic (2.1.6) + activesupport + autotest (4.4.2) + builder (2.1.2) + compass (0.10.6) + haml (>= 3.0.4) + compass-960-plugin (0.10.0) + compass (>= 0.10.0) + cucumber (0.9.3) + builder (~> 2.1.2) + diff-lcs (~> 1.1.2) + gherkin (~> 2.2.9) + json (~> 1.4.6) + term-ansicolor (~> 1.0.5) + cucumber-rails (0.3.2) + cucumber (>= 0.8.0) + database_cleaner (0.6.0) + deltacloud-client (0.1.0) + nokogiri (>= 1.4.3) + rest-client (>= 1.6.1) + diff-lcs (1.1.2) + erubis (2.6.6) + abstract (>= 1.0.0) + factory_girl (1.3.2) + factory_girl_rails (1.0) + factory_girl (~> 1.3) + rails (>= 3.0.0.beta4) + ffi (0.6.3) + rake (>= 0.8.7) + gherkin (2.2.9) + json (~> 1.4.6) + term-ansicolor (~> 1.0.5) + gnuplot (2.3.4) + haml (3.0.23) + i18n (0.4.2) + json (1.4.6) + mail (2.2.9) + activesupport (>= 2.3.6) + i18n (~> 0.4.1) + mime-types (~> 1.16) + treetop (~> 1.4.8) + mime-types (1.16) + nokogiri (1.4.3.1) + polyglot (0.3.1) + rack (1.2.1) + rack-mount (0.6.13) + rack (>= 1.0.0) + rack-test (0.5.6) + rack (>= 1.0) + rails (3.0.1) + actionmailer (= 3.0.1) + actionpack (= 3.0.1) + activerecord (= 3.0.1) + activeresource (= 3.0.1) + activesupport (= 3.0.1) + bundler (~> 1.0.0) + railties (= 3.0.1) + railties (3.0.1) + actionpack (= 3.0.1) + activesupport (= 3.0.1) + rake (>= 0.8.4) + thor (~> 0.14.0) + rake (0.8.7) + rb-inotify (0.8.1) + ffi (>= 0.5.0) + rest-client (1.6.1) + mime-types (>= 1.16) + rspec (2.0.1) + rspec-core (~> 2.0.1) + rspec-expectations (~> 2.0.1) + rspec-mocks (~> 2.0.1) + rspec-core (2.0.1) + rspec-expectations (2.0.1) + diff-lcs (>= 1.1.2) + rspec-mocks (2.0.1) + rspec-core (~> 2.0.1) + rspec-expectations (~> 2.0.1) + rspec-rails (2.0.1) + rspec (~> 2.0.0) + scruffy (0.2.6) + simple-navigation (3.0.2) + activesupport (>= 2.3.2) + sqlite3-ruby (1.3.2) + term-ansicolor (1.0.5) + thor (0.14.3) + timecop (0.3.5) + treetop (1.4.8) + polyglot (>= 0.3.1) + typhoeus (0.1.31) + rack + tzinfo (0.3.23) + webrat (0.7.2) + nokogiri (>= 1.2.0) + rack (>= 1.0) + rack-test (>= 0.5.3) + will_paginate (3.0.pre2) + +PLATFORMS + ruby + +DEPENDENCIES + authlogic + autotest + compass (>= 0.10.2) + compass-960-plugin + cucumber + cucumber-rails + database_cleaner (>= 0.5.0) + deltacloud-client (>= 0.0.9.8) + factory_girl_rails + gnuplot + haml + json + nokogiri (>= 1.4.0) + rails (= 3.0.1) + rb-inotify + rspec-rails (~> 2.0.1) + scruffy + simple-navigation + sqlite3-ruby + timecop + typhoeus + webrat (>= 0.7.2) + will_paginate (>= 3.0.pre2) diff --git a/src/Rakefile b/src/Rakefile index 37c683b..03d16cb 100644 --- a/src/Rakefile +++ b/src/Rakefile @@ -1,11 +1,7 @@ -# -*- ruby -*- # 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 'rake/rdoctask'
-require 'tasks/rails' +Aggregator::Application.load_tasks diff --git a/src/app/controllers/application_controller.rb b/src/app/controllers/application_controller.rb index 0b8a015..076379d 100644 --- a/src/app/controllers/application_controller.rb +++ b/src/app/controllers/application_controller.rb @@ -24,7 +24,6 @@ class ApplicationController < ActionController::Base # FIXME: not sure what we're doing aobut service layer w/ deltacloud include ApplicationService - filter_parameter_logging :password, :password_confirmation helper_method :current_user_session, :current_user
layout :choose_layout @@ -49,12 +48,11 @@ class ApplicationController < ActionController::Base 'generic' end
- perm_helper_string = "" Privilege::FULL_PRIVILEGE_LIST.each do |privilege| - perm_helper_string += "def has_#{privilege}?(obj=@perm_obj); " + - "check_privilege("#{privilege}", obj) end; " + class_eval "def has_#{privilege}?(obj=@perm_obj); " + + "check_privilege("#{privilege}", obj) end; " + helper_method :"has_#{privilege}?" end - master_helper_module.module_eval perm_helper_string
helper_method :check_privilege
@@ -93,7 +91,7 @@ class ApplicationController < ActionController::Base end
def handle_error(hash) - log_error(hash[:error]) if hash[:error] + logger.fatal(hash[:error].to_s) if hash[:error] msg = hash[:message] || hash[:error].message title = hash[:title] || "Internal Server Error" status = hash[:status] || :internal_server_error diff --git a/src/app/controllers/users_controller.rb b/src/app/controllers/users_controller.rb index 9a6c1db..0345874 100644 --- a/src/app/controllers/users_controller.rb +++ b/src/app/controllers/users_controller.rb @@ -44,7 +44,7 @@ class UsersController < ApplicationController redirect_to users_path else flash[:notice] = "You have successfully registered!" - redirect_to :dashboard + redirect_to :controller => :dashboard end else flash[:warning] = "user registration failed: #{@registration.error}" @@ -81,7 +81,7 @@ class UsersController < ApplicationController if @user != @current_user if !has_users_modify flash[:notice] = "Invalid Permission to perform this operation" - redirect_to :dashboard + redirect_to :controller => :dashboard end end if @user.update_attributes(params[:user]) @@ -89,7 +89,7 @@ class UsersController < ApplicationController if has_users_modify redirect_to users_path else - redirect_to :dashboard + redirect_to :controller => :dashboard end else render :action => :edit @@ -115,7 +115,7 @@ class UsersController < ApplicationController end else flash[:notice] = "Invalid Permission to perform this operation" - redirect_to :dashboard + redirect_to :controller => :dashboard end end
diff --git a/src/app/helpers/templates_helper.rb b/src/app/helpers/templates_helper.rb index 1ffcd2f..f85244e 100644 --- a/src/app/helpers/templates_helper.rb +++ b/src/app/helpers/templates_helper.rb @@ -1,5 +1,5 @@ module TemplatesHelper - class ButtonPaginationRenderer < WillPaginate::LinkRenderer + class ButtonPaginationRenderer < WillPaginate::ViewHelpers::LinkRenderer def page_link(page, text, attributes = {}) #submit_tag text, :name => 'page' "<input type=submit value='#{text}' name='page' class='#{attributes[:class]}' />" diff --git a/src/app/models/instance.rb b/src/app/models/instance.rb index 22069e2..cae9ac2 100644 --- a/src/app/models/instance.rb +++ b/src/app/models/instance.rb @@ -154,7 +154,7 @@ class Instance < ActiveRecord::Base return stats end
- named_scope :with_hardware_profile, lambda { + scope :with_hardware_profile, lambda { {:include => :hardware_profile} } end diff --git a/src/app/models/search_filter.rb b/src/app/models/search_filter.rb index 0913933..a56aab8 100644 --- a/src/app/models/search_filter.rb +++ b/src/app/models/search_filter.rb @@ -20,7 +20,7 @@ module SearchFilter def self.included(base) base.class_eval do - named_scope :search_filter, lambda {|str, cols| + scope :search_filter, lambda {|str, cols| if str.to_s.empty? {:conditions => {}} else diff --git a/src/app/models/user_session.rb b/src/app/models/user_session.rb index b9b2224..9655182 100644 --- a/src/app/models/user_session.rb +++ b/src/app/models/user_session.rb @@ -21,4 +21,9 @@
class UserSession < Authlogic::Session::Base
+ # http://railsplugins.org/plugins/56-authlogic + def to_key + new_record? ? nil : [self.send(self.class.primary_key)] + end + end diff --git a/src/app/views/user_sessions/new.haml b/src/app/views/user_sessions/new.haml index c3a60f1..017e787 100644 --- a/src/app/views/user_sessions/new.haml +++ b/src/app/views/user_sessions/new.haml @@ -1,7 +1,7 @@ .modalbox %h2 Log In .dcloud_form - - form_for @user_session, :url => user_session_path do |f| + = form_for @user_session, :url => url_for(:action => :create) do |f| = f.error_messages %fieldset = f.label :login, "Username:" diff --git a/src/autotest/discover.rb b/src/autotest/discover.rb new file mode 100644 index 0000000..f421dc5 --- /dev/null +++ b/src/autotest/discover.rb @@ -0,0 +1,2 @@ +Autotest.add_discovery { "rails" } +Autotest.add_discovery { "rspec2" } diff --git a/src/config.ru b/src/config.ru index acbfe4e..42fc9ce 100644 --- a/src/config.ru +++ b/src/config.ru @@ -1,7 +1,4 @@ -# Rack Dispatcher +# This file is used by Rack-based servers to start the application.
-# Require your environment file to bootstrap Rails -require File.dirname(__FILE__) + '/config/environment' - -# Dispatch the request -run ActionController::Dispatcher.new +require ::File.expand_path('../config/environment', __FILE__) +run Aggregator::Application diff --git a/src/config/application.rb b/src/config/application.rb new file mode 100644 index 0000000..0ca0f53 --- /dev/null +++ b/src/config/application.rb @@ -0,0 +1,58 @@ +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) + +$: << File.join(File.dirname(__FILE__), "../app") +require 'util/condormatic' + +module Aggregator + 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 + config.active_record.observers = :instance_observer, :task_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, :password_confirmation] + + config.after_initialize do + Haml::Template.options[:format] = :html5 + begin + # This pulls all the possible classad matches from the database and puts + # them on condor on startup. Note that this can fail because this is run on startup + # even for rake db:migrate etc. which won't work since the database doesn't exist + # yet. + kick_condor + rescue Exception => ex + end + end + end +end diff --git a/src/config/boot.rb b/src/config/boot.rb index 9759b93..ab6cb37 100644 --- a/src/config/boot.rb +++ b/src/config/boot.rb @@ -1,110 +1,13 @@ -# Don't change this file! -# Configure your app in config/environment.rb and config/environments/*.rb - -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") - 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.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 - $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 - 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.1' - 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! +require 'rubygems' + +# Set up gems listed in the Gemfile. +gemfile = File.expand_path('../../Gemfile', __FILE__) +begin + ENV['BUNDLE_GEMFILE'] = gemfile + require 'bundler' + Bundler.setup +rescue Bundler::GemNotFound => e + STDERR.puts e.message + STDERR.puts "Try running `bundle install`." + exit! +end if File.exist?(gemfile) diff --git a/src/config/environment.rb b/src/config/environment.rb index 423f224..0c6e8c3 100644 --- a/src/config/environment.rb +++ b/src/config/environment.rb @@ -1,99 +1,5 @@ -# -# Copyright (C) 2009 Red Hat, Inc. -# Written by Scott Seago sseago@redhat.com -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; version 2 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -# MA 02110-1301, USA. A copy of the GNU General Public License is -# also available at http://www.gnu.org/copyleft/gpl.html. +# Load the rails application +require File.expand_path('../application', __FILE__)
-# Be sure to restart your web server when you modify this file. - -# Specifies gem version of Rails to use when vendor/rails is not present -RAILS_GEM_VERSION = '>= 2.3.2' unless defined? RAILS_GEM_VERSION - -# Bootstrap the Rails environment, frameworks, and default configuration -require File.join(File.dirname(__FILE__), 'boot') -require 'util/condormatic' - - -Rails::Initializer.run do |config| - # 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. - # See Rails::Configuration for more options. - - # Skip frameworks you're not going to use. To use Rails without a database - # you must remove the Active Record framework. - # config.frameworks -= [ :active_record, :active_resource, :action_mailer ] - - # Specify gems that this application depends on. - # They can then be installed with "rake gems:install" on new installations. - # config.gem "bj" - # config.gem "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net" - # config.gem "aws-s3", :lib => "aws/s3" - config.gem "authlogic" - config.gem "deltacloud-client", :lib => "deltacloud", :version => ">= 0.0.9.8" - config.gem "haml" - config.gem "will_paginate" - config.gem "nokogiri", :version => ">= 1.4.0" - config.gem "gnuplot" - config.gem "scruffy" - config.gem "compass", :version => ">= 0.10.2" - config.gem "compass-960-plugin", :lib => "ninesixty" - config.gem "simple-navigation" - config.gem "typhoeus" - config.gem "rb-inotify" - - config.active_record.observers = :instance_observer, :task_observer - # Only load the plugins named here, in the order given. By default, all plugins - # in vendor/plugins are loaded in alphabetical order. - # :all can be used as a placeholder for all plugins not explicitly named - # config.plugins = [ :exception_notification, :ssl_requirement, :all ] - - # Add additional load paths for your own custom dirs - # config.load_paths += %W( #{RAILS_ROOT}/extras ) - - # Force all environments to use the same logger level - # (by default production uses :info, the others :debug) - # config.log_level = :debug - - # Make Time.zone default to the specified zone, and make Active Record store time values - # in the database in UTC, and return them converted to the specified local zone. - # Run "rake -D time" for a list of tasks for finding time zone names. Uncomment to use default local time. - config.time_zone = 'UTC' - - # Use SQL instead of Active Record's schema dumper when creating the test database. - # This is necessary if your schema can't be completely dumped by the schema dumper, - # like if you have constraints or database-specific column types - # config.active_record.schema_format = :sql - - # Activate observers that should always be running - # config.active_record.observers = :cacher, :garbage_collector - - # 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}')] - # config.i18n.default_locale = :de - - config.after_initialize do - Haml::Template.options[:format] = :html5 - begin - # This pulls all the possible classad matches from the database and puts - # them on condor on startup. Note that this can fail because this is run on startup - # even for rake db:migrate etc. which won't work since the database doesn't exist - # yet. - kick_condor - rescue Exception => ex - end - end -end +# Initialize the rails application +Aggregator::Application.initialize! diff --git a/src/config/environments/cucumber.rb b/src/config/environments/cucumber.rb deleted file mode 100644 index 1e4a75d..0000000 --- a/src/config/environments/cucumber.rb +++ /dev/null @@ -1,29 +0,0 @@ -# Edit at your own peril - it's recommended to regenerate this file -# in the future when you upgrade to a newer version of Cucumber. - -# IMPORTANT: Setting config.cache_classes to false is known to -# break Cucumber's use_transactional_fixtures method. -# For more information see https://rspec.lighthouseapp.com/projects/16211/tickets/165 -config.cache_classes = true - -# Log error messages when you accidentally call methods on nil. -config.whiny_nils = true - -# Show full error reports and disable caching -config.action_controller.consider_all_requests_local = true -config.action_controller.perform_caching = false - -# Disable request forgery protection in test environment -config.action_controller.allow_forgery_protection = false - -# Tell Action Mailer not to deliver emails to the real world. -# The :test delivery method accumulates sent emails in the -# ActionMailer::Base.deliveries array. -config.action_mailer.delivery_method = :test - -config.gem 'cucumber-rails', :lib => false, :version => '>=0.3.2' unless File.directory?(File.join(Rails.root, 'vendor/plugins/cucumber-rails')) -config.gem 'database_cleaner', :lib => false, :version => '>=0.5.0' unless File.directory?(File.join(Rails.root, 'vendor/plugins/database_cleaner')) -config.gem 'webrat', :lib => false, :version => '>=0.7.0' unless File.directory?(File.join(Rails.root, 'vendor/plugins/webrat')) -config.gem 'rspec', :lib => false, :version => '>=1.3.0' unless File.directory?(File.join(Rails.root, 'vendor/plugins/rspec')) -config.gem 'rspec-rails', :lib => false, :version => '>=1.3.2' unless File.directory?(File.join(Rails.root, 'vendor/plugins/rspec-rails')) -config.gem "factory_girl", :lib => "factory_girl", :version => ">=1.3.1" diff --git a/src/config/environments/development.rb b/src/config/environments/development.rb index 9bd4fa6..9be67fd 100644 --- a/src/config/environments/development.rb +++ b/src/config/environments/development.rb @@ -1,39 +1,26 @@ -# -# Copyright (C) 2008 Red Hat, Inc. -# Written by Scott Seago sseago@redhat.com -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; version 2 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -# MA 02110-1301, USA. A copy of the GNU General Public License is -# also available at http://www.gnu.org/copyleft/gpl.html. +Aggregator::Application.configure do + # Settings specified here will take precedence over those in config/environment.rb
-# Settings specified here will take precedence over those in config/environment.rb + # In the development environment your application's code is reloaded on + # every request. This slows down response time but is perfect for development + # since you don't have to restart the webserver when you make code changes. + config.cache_classes = false
-# In the development environment your application's code is reloaded on -# every request. This slows down response time but is perfect for development -# since you don't have to restart the webserver when you make code changes. -config.cache_classes = false + # Log error messages when you accidentally call methods on nil. + config.whiny_nils = true
-# Log error messages when you accidentally call methods on nil. -config.whiny_nils = true + # Show full error reports and disable caching + config.consider_all_requests_local = true + config.action_view.debug_rjs = true + config.action_controller.perform_caching = false
-# Enable the breakpoint server that script/breakpointer connects to -#config.breakpoint_server = true + # Don't care if the mailer can't send + config.action_mailer.raise_delivery_errors = false
-# Show full error reports and disable caching -config.action_controller.consider_all_requests_local = true -config.action_controller.perform_caching = false -config.action_view.debug_rjs = true + # Print deprecation notices to the Rails logger + config.active_support.deprecation = :log + + # Only use best-standards-support built into browsers + config.action_dispatch.best_standards_support = :builtin +end
-# Don't care if the mailer can't send -config.action_mailer.raise_delivery_errors = false diff --git a/src/config/environments/production.rb b/src/config/environments/production.rb index dc093bf..19c8e5c 100644 --- a/src/config/environments/production.rb +++ b/src/config/environments/production.rb @@ -1,38 +1,49 @@ -# -# Copyright (C) 2008 Red Hat, Inc. -# Written by Scott Seago sseago@redhat.com -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; version 2 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -# MA 02110-1301, USA. A copy of the GNU General Public License is -# also available at http://www.gnu.org/copyleft/gpl.html. - -# Settings specified here will take precedence over those in config/environment.rb - -# The production environment is meant for finished, "live" apps. -# Code is not reloaded between requests -config.cache_classes = true - -# Use a different logger for distributed setups -# config.logger = SyslogLogger.new - -# Full error reports are disabled and caching is turned on -config.action_controller.consider_all_requests_local = false -config.action_controller.perform_caching = true - -# Enable serving of images, stylesheets, and javascripts from an asset server -# config.action_controller.asset_host = "http://assets.example.com" - -# Disable delivery errors, bad email addresses will be ignored -# config.action_mailer.raise_delivery_errors = false -config.log_path = "/var/log/deltacloud-aggregator/rails.log" +Aggregator::Application.configure do + # Settings specified here will take precedence over those in config/environment.rb + + # The production environment is meant for finished, "live" apps. + # Code is not reloaded between requests + config.cache_classes = true + + # Full error reports are disabled and caching is turned on + config.consider_all_requests_local = false + config.action_controller.perform_caching = true + + # Specifies the header that your server uses for sending files + config.action_dispatch.x_sendfile_header = "X-Sendfile" + + # For nginx: + # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' + + # If you have no front-end server that supports something like X-Sendfile, + # just comment this out and Rails will serve the files + + # See everything in the log (default is :info) + # config.log_level = :debug + + # Use a different logger for distributed setups + # config.logger = SyslogLogger.new + + # Use a different cache store in production + # config.cache_store = :mem_cache_store + + # Disable Rails's static asset server + # In production, Apache or nginx will already do this + config.serve_static_assets = false + + # Enable serving of images, stylesheets, and javascripts from an asset server + # config.action_controller.asset_host = "http://assets.example.com" + + # Disable delivery errors, bad email addresses will be ignored + # config.action_mailer.raise_delivery_errors = false + + # Enable threaded mode + # config.threadsafe! + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation can not be found) + config.i18n.fallbacks = true + + # Send deprecation notices to registered listeners + config.active_support.deprecation = :notify +end diff --git a/src/config/environments/test.rb b/src/config/environments/test.rb index f7981c4..ba633db 100644 --- a/src/config/environments/test.rb +++ b/src/config/environments/test.rb @@ -1,42 +1,35 @@ -# -# Copyright (C) 2008 Red Hat, Inc. -# Written by Scott Seago sseago@redhat.com -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; version 2 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -# MA 02110-1301, USA. A copy of the GNU General Public License is -# also available at http://www.gnu.org/copyleft/gpl.html. - -# Settings specified here will take precedence over those in config/environment.rb - -# The test environment is used exclusively to run your application's -# test suite. You never need to work with it otherwise. Remember that -# your test database is "scratch space" for the test suite and is wiped -# and recreated between test runs. Don't rely on the data there! -config.cache_classes = true - -# Log error messages when you accidentally call methods on nil. -config.whiny_nils = true - -# Show full error reports and disable caching -config.action_controller.consider_all_requests_local = true -config.action_controller.perform_caching = false - -# Tell ActionMailer not to deliver emails to the real world. -# The :test delivery method accumulates sent emails in the -# ActionMailer::Base.deliveries array. -config.action_mailer.delivery_method = :test - -config.gem 'rspec-rails', :version => '>= 1.3.2', :lib => false unless File.directory?(File.join(Rails.root, 'vendor/plugins/rspec-rails')) -config.gem "factory_girl", :lib => "factory_girl", :version => ">=1.3.1" -config.gem 'timecop', :lib => 'timecop', :version => '>= 0.3.5' +Aggregator::Application.configure do + # Settings specified here will take precedence over those in config/environment.rb + + # The test environment is used exclusively to run your application's + # test suite. You never need to work with it otherwise. Remember that + # your test database is "scratch space" for the test suite and is wiped + # and recreated between test runs. Don't rely on the data there! + config.cache_classes = true + + # Log error messages when you accidentally call methods on nil. + config.whiny_nils = true + + # Show full error reports and disable caching + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + + # Raise exceptions instead of rendering exception templates + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment + config.action_controller.allow_forgery_protection = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Use SQL instead of Active Record's schema dumper when creating the test database. + # This is necessary if your schema can't be completely dumped by the schema dumper, + # like if you have constraints or database-specific column types + # config.active_record.schema_format = :sql + + # Print deprecation notices to the stderr + config.active_support.deprecation = :stderr +end diff --git a/src/config/initializers/backtrace_silencers.rb b/src/config/initializers/backtrace_silencers.rb index c2169ed..59385cd 100644 --- a/src/config/initializers/backtrace_silencers.rb +++ b/src/config/initializers/backtrace_silencers.rb @@ -3,5 +3,5 @@ # 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 do debug a problem that might steem from framework code. -# Rails.backtrace_cleaner.remove_silencers! \ No newline at end of file +# 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/src/config/initializers/new_rails_defaults.rb b/src/config/initializers/new_rails_defaults.rb deleted file mode 100644 index 8ec3186..0000000 --- a/src/config/initializers/new_rails_defaults.rb +++ /dev/null @@ -1,19 +0,0 @@ -# Be sure to restart your server when you modify this file. - -# These settings change the behavior of Rails 2 apps and will be defaults -# for Rails 3. You can remove this initializer when Rails 3 is released. - -if defined?(ActiveRecord) - # Include Active Record class name as root for JSON serialized output. - ActiveRecord::Base.include_root_in_json = true - - # Store the full class name (including module namespace) in STI type column. - ActiveRecord::Base.store_full_sti_class = true -end - -# Use ISO 8601 format for JSON serialized times and dates. -ActiveSupport.use_standard_json_time_format = true - -# Don't escape HTML entities in JSON, leave that for the #json_escape helper. -# if you're including raw json in an HTML page. -ActiveSupport.escape_html_entities_in_json = false \ No newline at end of file diff --git a/src/config/initializers/secret_token.rb b/src/config/initializers/secret_token.rb new file mode 100644 index 0000000..544cb22 --- /dev/null +++ b/src/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. +Aggregator::Application.config.secret_token = '538786e891b468964662eb7385b3b781062b907175875c6b7fc344ffb9eb7de5abd7bca07e7901bf0bfdda57e52a10f2688fae7e86e30e6194d22dc489bd9b54' diff --git a/src/config/initializers/session_store.rb b/src/config/initializers/session_store.rb index 64dbf51..541a4a6 100644 --- a/src/config/initializers/session_store.rb +++ b/src/config/initializers/session_store.rb @@ -4,7 +4,7 @@ # 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 = { +Aggregator::Application.config.session = { :key => '_rails23-app_session', :secret => '41713a6b4a92b5b7af55314d2ef6fc499a177269ea91b9fdaa7d15c42e1234b70b32f52278ae26b774b38dbdfeb7d078585d10f643e81b6615d32410f192f1de' } @@ -12,4 +12,4 @@ ActionController::Base.session = { # Use the database for sessions instead of the cookie-based default, # which shouldn't be used to store highly confidential information # (create the session table with "rake db:sessions:create") -ActionController::Base.session_store = :active_record_store +Aggregator::Application.config.session_store = :active_record_store diff --git a/src/config/routes.rb b/src/config/routes.rb index d736b93..13775ff 100644 --- a/src/config/routes.rb +++ b/src/config/routes.rb @@ -1,64 +1,74 @@ -# -# Copyright (C) 2009 Red Hat, Inc. -# Written by Scott Seago sseago@redhat.com -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; version 2 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -# MA 02110-1301, USA. A copy of the GNU General Public License is -# also available at http://www.gnu.org/copyleft/gpl.html. - -ActionController::Routing::Routes.draw do |map| - - # The priority is based upon order of creation: first created -> highest priority. +Aggregator::Application.routes.draw do + # The priority is based upon order of creation: + # first created -> highest priority.
# Sample of regular route: - # map.connect 'products/:id', :controller => 'catalog', :action => 'view' + # match 'products/:id' => 'catalog#view' # Keep in mind you can assign values other than :controller and :action
# Sample of named route: - # map.purchase 'products/:id/purchase', :controller => 'catalog', :action => 'purchase' + # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase # This route can be invoked with purchase_url(:id => product.id)
- # You can have the root of your site routed by hooking up '' - # -- just remember to delete public/index.html. + # Sample resource route (maps HTTP verbs to controller actions automatically): + # resources :products + + # Sample resource route with options: + # resources :products do + # member do + # get 'short' + # post 'toggle' + # end + # + # collection do + # get 'sold' + # end + # end + + # Sample resource route with sub-resources: + # resources :products do + # resources :comments, :sales + # resource :seller + # end
+ # Sample resource route with more complex sub-resources + # resources :products do + # resources :comments + # resources :sales do + # get 'recent', :on => :collection + # end + # end
- map.resources :pools + # Sample resource route within a namespace: + # namespace :admin do + # # Directs /admin/products/* to Admin::ProductsController + # # (app/controllers/admin/products_controller.rb) + # resources :products + # end
- map.connect '', :controller => 'dashboard' + # You can have the root of your site routed with "root" + # just remember to delete public/index.html. + # root :to => "welcome#index"
- map.login 'login', :controller => "user_sessions", :action => "new" - map.logout 'logout', :controller => "user_sessions", :action => "destroy" - map.resource :user_session - map.register 'register', :controller => 'users', :action => 'new' - map.resource :account, :controller => "users" - map.resources :users + # See how all your routes lay out with "rake routes"
- map.dashboard '/dashboard', :controller => 'dashboard' - map.instance '/instance', :controller => 'instance' - map.templates '/templates', :controller => 'templates' - map.settings '/settings', :controller => 'settings' - map.root :dashboard + # This is a legacy wild controller route that's not recommended for RESTful applications. + # Note: This route will make all actions in every controller accessible via GET requests. + # match ':controller(/:action(/:id(.:format)))'
- # Temporarily disable this route, provider stuff is not restful yet. - # Will be re-enabled in upcoming patch - # map.resources :provider + match 'login', :to => 'user_sessions#new', :as => 'login' + match 'logout', :to => 'user_sessions#destroy', :as => 'logout' + match 'register', :to => 'users#new', :as => 'register'
- # Allow downloading Web Service WSDL as a file with an extension - # instead of a file named 'wsdl' - map.connect ':controller/service.wsdl', :action => 'wsdl' + resource 'account', :to => 'users' + resources :users, :pools, :instance, :templates + resources :settings do + collection do + get :self_service + get :general_settings + end + end + root :to => "dashboard#index"
- # Install the default route as the lowest priority. - map.connect ':controller/:action/:id.:format' - map.connect ':controller/:action/:id' + match '/:controller(/:action(/:id))' end diff --git a/src/db/seeds.rb b/src/db/seeds.rb new file mode 100644 index 0000000..664d8c7 --- /dev/null +++ b/src/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/src/features/step_definitions/web_steps.rb b/src/features/step_definitions/web_steps.rb index f270900..b757096 100644 --- a/src/features/step_definitions/web_steps.rb +++ b/src/features/step_definitions/web_steps.rb @@ -1,6 +1,6 @@ # IMPORTANT: This file is generated by cucumber-rails - edit at your own peril. -# It is recommended to regenerate this file in the future when you upgrade to a -# newer version of cucumber-rails. Consider adding your own code to a new file +# It is recommended to regenerate this file in the future when you upgrade to a +# newer version of cucumber-rails. Consider adding your own code to a new file # instead of editing this one. Cucumber will automatically load all features/**/*.rb # files.
@@ -122,21 +122,21 @@ end
# Adds support for validates_attachment_content_type. Without the mime-type getting # passed to attach_file() you will get a "Photo file is not one of the allowed file types." -# error message +# error message When /^(?:|I )attach the file "([^"]*)" to "([^"]*)"$/ do |path, field| type = path.split(".")[1]
case type when "jpg" - type = "image/jpg" + type = "image/jpg" when "jpeg" - type = "image/jpeg" + type = "image/jpeg" when "png" - type = "image/png" + type = "image/png" when "gif" type = "image/gif" end - + attach_file(field, path, type) end
@@ -267,7 +267,7 @@ Then /^(?:|I )should have the following query string:$/ do |expected_pairs| query = URI.parse(current_url).query actual_params = query ? CGI.parse(query) : {} expected_params = {} - expected_pairs.rows_hash.each_pair{|k,v| expected_params[k] = v.split(',')} + expected_pairs.rows_hash.each_pair{|k,v| expected_params[k] = v.split(',')}
if actual_params.respond_to? :should actual_params.should == expected_params diff --git a/src/features/support/env.rb b/src/features/support/env.rb index b921613..44cd675 100644 --- a/src/features/support/env.rb +++ b/src/features/support/env.rb @@ -1,14 +1,13 @@ # IMPORTANT: This file is generated by cucumber-rails - edit at your own peril. -# It is recommended to regenerate this file in the future when you upgrade to a -# newer version of cucumber-rails. Consider adding your own code to a new file +# It is recommended to regenerate this file in the future when you upgrade to a +# newer version of cucumber-rails. Consider adding your own code to a new file # instead of editing this one. Cucumber will automatically load all features/**/*.rb # files.
-ENV["RAILS_ENV"] ||= "cucumber" +ENV["RAILS_ENV"] ||= "test" require File.expand_path(File.dirname(__FILE__) + '/../../config/environment')
require 'cucumber/formatter/unicode' # Remove this line if you don't want Cucumber Unicode support -require 'cucumber/rails/rspec' require 'cucumber/rails/world' require 'cucumber/rails/active_record' require 'cucumber/web/tableish' @@ -17,12 +16,11 @@ require 'webrat' require 'webrat/core/matchers'
Webrat.configure do |config| - config.mode = :rails + config.mode = :rack config.open_error_files = false # Set to true if you want error pages to pop up in the browser end
- -# If you set this to false, any error raised from within your app will bubble +# If you set this to false, any error raised from within your app will bubble # up to your step definition and out to cucumber unless you catch it somewhere # on the way. You can make Rails rescue errors and render error pages on a # per-scenario basis by tagging a scenario or feature with the @allow-rescue tag. @@ -34,15 +32,15 @@ end ActionController::Base.allow_rescue = false
# If you set this to true, each scenario will run in a database transaction. -# You can still turn off transactions on a per-scenario basis, simply tagging +# You can still turn off transactions on a per-scenario basis, simply tagging # a feature or scenario with the @no-txn tag. If you are using Capybara, # tagging with @culerity or @javascript will also turn transactions off. # # If you set this to false, transactions will be off for all scenarios, # regardless of whether you use @no-txn or not. # -# Beware that turning transactions off will leave data in your database -# after each scenario, which can lead to hard-to-debug failures in +# Beware that turning transactions off will leave data in your database +# after each scenario, which can lead to hard-to-debug failures in # subsequent scenarios. If you do this, we recommend you create a Before # block that will explicitly put your database in a known state. Cucumber::Rails::World.use_transactional_fixtures = true diff --git a/src/features/support/paths.rb b/src/features/support/paths.rb index fdc63f5..6b54a6a 100644 --- a/src/features/support/paths.rb +++ b/src/features/support/paths.rb @@ -24,7 +24,7 @@ module NavigationHelpers account_path
when /the login error page/ - user_session_path + url_for :controller => 'user_sessions', :action => 'new', :only_path => true
when /the providers page/ url_for :controller => 'provider', :action => 'index', :only_path => true @@ -51,10 +51,10 @@ module NavigationHelpers pool_realms_path
when /the dashboard page/ - dashboard_path + url_for :controller => 'dashboard', :only_path => true
when /the instances page/ - instance_path + instance_index_path
when /the pool hardware profiles page/ hardware_profiles_pool_path @@ -80,6 +80,7 @@ module NavigationHelpers when /the settings update page/ url_for :action => 'update', :controller => 'settings', :only_path => true
+ # Add more mappings here. # Here is an example that pulls values out of the Regexp: # diff --git a/src/lib/tasks/.gitkeep b/src/lib/tasks/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/lib/tasks/cucumber.rake b/src/lib/tasks/cucumber.rake index 15034cd..7db1a55 100644 --- a/src/lib/tasks/cucumber.rake +++ b/src/lib/tasks/cucumber.rake @@ -1,6 +1,6 @@ # IMPORTANT: This file is generated by cucumber-rails - edit at your own peril. -# It is recommended to regenerate this file in the future when you upgrade to a -# newer version of cucumber-rails. Consider adding your own code to a new file +# It is recommended to regenerate this file in the future when you upgrade to a +# newer version of cucumber-rails. Consider adding your own code to a new file # instead of editing this one. Cucumber will automatically load all features/**/*.rb # files.
@@ -43,28 +43,11 @@ begin task :features => :cucumber do STDERR.puts "*** The 'features' task is deprecated. See rake -T cucumber ***" end - - namespace :hudson do - def report_path - "hudson/reports/features/" - end - - Cucumber::Rake::Task.new({'cucumber' => [:report_setup]}) do |t| - t.cucumber_opts = %{--profile default --format junit --out #{report_path}} - end - - task :report_setup do - rm_rf report_path - mkdir_p report_path - end - - end - - rescue LoadError - desc 'cucumber rake task not available (cucumber not installed)' - task :cucumber do - abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin' - end +rescue LoadError + desc 'cucumber rake task not available (cucumber not installed)' + task :cucumber do + abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin' end +end
-end \ No newline at end of file +end diff --git a/src/lib/tasks/rspec.rake b/src/lib/tasks/rspec.rake deleted file mode 100644 index 80d000d..0000000 --- a/src/lib/tasks/rspec.rake +++ /dev/null @@ -1,157 +0,0 @@ -gem 'test-unit', '1.2.3' if RUBY_VERSION.to_f >= 1.9 - -rspec_gem_dir = nil -Dir["#{RAILS_ROOT}/vendor/gems/*"].each do |subdir| - rspec_gem_dir = subdir if subdir.gsub("#{RAILS_ROOT}/vendor/gems/","") =~ /^(\w+-)?rspec-(\d+)/ && File.exist?("#{subdir}/lib/spec/rake/spectask.rb") -end -rspec_plugin_dir = File.expand_path(File.dirname(__FILE__) + '/../../vendor/plugins/rspec') - -if rspec_gem_dir && (test ?d, rspec_plugin_dir) - raise "\n#{'*'*50}\nYou have rspec installed in both vendor/gems and vendor/plugins\nPlease pick one and dispose of the other.\n#{'*'*50}\n\n" -end - -if rspec_gem_dir - $LOAD_PATH.unshift("#{rspec_gem_dir}/lib") -elsif File.exist?(rspec_plugin_dir) - $LOAD_PATH.unshift("#{rspec_plugin_dir}/lib") -end - -# Don't load rspec if running "rake gems:*" -unless ARGV.any? {|a| a =~ /^gems/} - -begin - require 'spec/rake/spectask' -rescue MissingSourceFile - module Spec - module Rake - class SpecTask - def initialize(name) - task name do - # if rspec-rails is a configured gem, this will output helpful material and exit ... - require File.expand_path(File.join(File.dirname(__FILE__),"..","..","config","environment")) - - # ... otherwise, do this: - raise <<-MSG - -#{"*" * 80} -* You are trying to run an rspec rake task defined in -* #{__FILE__}, -* but rspec can not be found in vendor/gems, vendor/plugins or system gems. -#{"*" * 80} -MSG - end - end - end - end - end -end - -Rake.application.instance_variable_get('@tasks').delete('default') - -spec_prereq = File.exist?(File.join(RAILS_ROOT, 'config', 'database.yml')) ? "db:test:prepare" : :noop -task :noop do -end - -task :default => :spec -task :stats => "spec:statsetup" - -desc "Run all specs in spec directory (excluding plugin specs)" -Spec::Rake::SpecTask.new(:spec => spec_prereq) do |t| - t.spec_opts = ['--options', ""#{RAILS_ROOT}/spec/spec.opts""] - t.spec_files = FileList['spec/**/*_spec.rb'] -end - -namespace :spec do - desc "Run all specs in spec directory with RCov (excluding plugin specs)" - Spec::Rake::SpecTask.new(:rcov) do |t| - t.spec_opts = ['--options', ""#{RAILS_ROOT}/spec/spec.opts""] - t.spec_files = FileList['spec/**/*_spec.rb'] - t.rcov = true - t.rcov_opts = lambda do - IO.readlines("#{RAILS_ROOT}/spec/rcov.opts").map {|l| l.chomp.split " "}.flatten - end - end - - desc "Prepare JUnit output rspec for Hudson" - task :pre_junit do - gem 'ci_reporter' - require 'ci/reporter/rake/rspec' - ENV["CI_REPORTS"] = 'hudson/reports/spec/' - end - - desc "Run JUnit output filter for spec" - task :junit => [:pre_junit, "ci:setup:rspec", "spec"] - - desc "Print Specdoc for all specs (excluding plugin specs)" - Spec::Rake::SpecTask.new(:doc) do |t| - t.spec_opts = ["--format", "specdoc", "--dry-run"] - t.spec_files = FileList['spec/**/*_spec.rb'] - end - - desc "Print Specdoc for all plugin examples" - Spec::Rake::SpecTask.new(:plugin_doc) do |t| - t.spec_opts = ["--format", "specdoc", "--dry-run"] - t.spec_files = FileList['vendor/plugins/**/spec/**/*_spec.rb'].exclude('vendor/plugins/rspec/*') - end - - [:models, :controllers, :views, :helpers, :lib, :integration].each do |sub| - desc "Run the code examples in spec/#{sub}" - Spec::Rake::SpecTask.new(sub => spec_prereq) do |t| - t.spec_opts = ['--options', ""#{RAILS_ROOT}/spec/spec.opts""] - t.spec_files = FileList["spec/#{sub}/**/*_spec.rb"] - end - end - - desc "Run the code examples in vendor/plugins (except RSpec's own)" - Spec::Rake::SpecTask.new(:plugins => spec_prereq) do |t| - t.spec_opts = ['--options', ""#{RAILS_ROOT}/spec/spec.opts""] - t.spec_files = FileList['vendor/plugins/**/spec/**/*_spec.rb'].exclude('vendor/plugins/rspec/*').exclude("vendor/plugins/rspec-rails/*") - end - - namespace :plugins do - desc "Runs the examples for rspec_on_rails" - Spec::Rake::SpecTask.new(:rspec_on_rails) do |t| - t.spec_opts = ['--options', ""#{RAILS_ROOT}/spec/spec.opts""] - t.spec_files = FileList['vendor/plugins/rspec-rails/spec/**/*_spec.rb'] - end - end - - # Setup specs for stats - task :statsetup do - require 'code_statistics' - ::STATS_DIRECTORIES << %w(Model\ specs spec/models) if File.exist?('spec/models') - ::STATS_DIRECTORIES << %w(View\ specs spec/views) if File.exist?('spec/views') - ::STATS_DIRECTORIES << %w(Controller\ specs spec/controllers) if File.exist?('spec/controllers') - ::STATS_DIRECTORIES << %w(Helper\ specs spec/helpers) if File.exist?('spec/helpers') - ::STATS_DIRECTORIES << %w(Library\ specs spec/lib) if File.exist?('spec/lib') - ::STATS_DIRECTORIES << %w(Routing\ specs spec/routing) if File.exist?('spec/routing') - ::STATS_DIRECTORIES << %w(Integration\ specs spec/integration) if File.exist?('spec/integration') - ::CodeStatistics::TEST_TYPES << "Model specs" if File.exist?('spec/models') - ::CodeStatistics::TEST_TYPES << "View specs" if File.exist?('spec/views') - ::CodeStatistics::TEST_TYPES << "Controller specs" if File.exist?('spec/controllers') - ::CodeStatistics::TEST_TYPES << "Helper specs" if File.exist?('spec/helpers') - ::CodeStatistics::TEST_TYPES << "Library specs" if File.exist?('spec/lib') - ::CodeStatistics::TEST_TYPES << "Routing specs" if File.exist?('spec/routing') - ::CodeStatistics::TEST_TYPES << "Integration specs" if File.exist?('spec/integration') - end - - namespace :db do - namespace :fixtures do - desc "Load fixtures (from spec/fixtures) into the current environment's database. Load specific fixtures using FIXTURES=x,y. Load from subdirectory in test/fixtures using FIXTURES_DIR=z." - task :load => :environment do - ActiveRecord::Base.establish_connection(Rails.env) - base_dir = File.join(Rails.root, 'spec', 'fixtures') - fixtures_dir = ENV['FIXTURES_DIR'] ? File.join(base_dir, ENV['FIXTURES_DIR']) : base_dir - - require 'active_record/fixtures' - (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/).map {|f| File.join(fixtures_dir, f) } : Dir.glob(File.join(fixtures_dir, '*.{yml,csv}'))).each do |fixture_file| - Fixtures.create_fixtures(File.dirname(fixture_file), File.basename(fixture_file, '.*')) - end - end - end - end -end - -end - - diff --git a/src/public/401.html b/src/public/401.html deleted file mode 100644 index ffcfc9b..0000000 --- a/src/public/401.html +++ /dev/null @@ -1,40 +0,0 @@ -<!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"> -<head> - <meta http-equiv="content-type" content="text/html;charset=UTF-8" /> - <title>Authorization Required</title> - <link href="/ovirt/stylesheets/default.css" media="screen" rel="Stylesheet" type="text/css" /> - <script src="/ovirt/javascripts/prototype.js" type="text/javascript"></script> -</head> -<body> - -<div id="top_bar"></div> -<div id="content"> - <div id="header"> -<a href="/"><img alt="Ovirt" class="logo" src="/ovirt/images/ovirt-red-logo133x56.png" /></a> -</div> - - <div class = "alertbox"></div> - <div id="main"> - <div id="left"> - <!-- fill in main page content --> - <h1 class="page-title">Authorization Required</h1> -<p> -This server could not verify that you are authorized to access the -document requested. Either you supplied the wrong credentials (e.g., -bad password), or your browser doesn't understand how to supply the -credentials required. -</p> - </div> - <div id="right"> - </div> - </div> - <br clear="both" /> - <div id="footer"> -ET Group. Copyright Red Hat, Inc. 2007 -</div> -</div> -</body> -</html> diff --git a/src/public/404.html b/src/public/404.html index eff660b..9a48320 100644 --- a/src/public/404.html +++ b/src/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/src/public/422.html b/src/public/422.html new file mode 100644 index 0000000..83660ab --- /dev/null +++ b/src/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/src/public/500.html b/src/public/500.html index f0aee0e..b80307f 100644 --- a/src/public/500.html +++ b/src/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/src/public/dispatch.cgi b/src/public/dispatch.cgi deleted file mode 100755 index 9730473..0000000 --- a/src/public/dispatch.cgi +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/ruby - -require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT) - -# If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like: -# "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired -require "dispatcher" - -ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) } if defined?(Apache::RubyRun) -Dispatcher.dispatch \ No newline at end of file diff --git a/src/public/dispatch.fcgi b/src/public/dispatch.fcgi deleted file mode 100755 index f934b30..0000000 --- a/src/public/dispatch.fcgi +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/ruby -# -# You may specify the path to the FastCGI crash log (a log of unhandled -# exceptions which forced the FastCGI instance to exit, great for debugging) -# and the number of requests to process before running garbage collection. -# -# By default, the FastCGI crash log is RAILS_ROOT/log/fastcgi.crash.log -# and the GC period is nil (turned off). A reasonable number of requests -# could range from 10-100 depending on the memory footprint of your app. -# -# Example: -# # Default log path, normal GC behavior. -# RailsFCGIHandler.process! -# -# # Default log path, 50 requests between GC. -# RailsFCGIHandler.process! nil, 50 -# -# # Custom log path, normal GC behavior. -# RailsFCGIHandler.process! '/var/log/myapp_fcgi_crash.log' -# -require File.dirname(__FILE__) + "/../config/environment" -require 'fcgi_handler' - -RailsFCGIHandler.process! diff --git a/src/public/dispatch.rb b/src/public/dispatch.rb deleted file mode 100755 index a82be08..0000000 --- a/src/public/dispatch.rb +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/ruby -# -# Copyright (C) 2008 Red Hat, Inc. -# Written by Scott Seago sseago@redhat.com -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; version 2 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -# MA 02110-1301, USA. A copy of the GNU General Public License is -# also available at http://www.gnu.org/copyleft/gpl.html. - - -require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT) - -# If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like: -# "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired -require "dispatcher" - -ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) } if defined?(Apache::RubyRun) -Dispatcher.dispatch \ No newline at end of file diff --git a/src/public/images/rails.png b/src/public/images/rails.png new file mode 100644 index 0000000000000000000000000000000000000000..d5edc04e65f555e3ba4dcdaad39dc352e75b575e GIT binary patch literal 6646 zcmV<S842czP)<h;3K|Lk000e1NJLTq001%o002M;1^@s6Sk)wZ0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBV0m`OxIRCwB~TM3k0WtINkQm@vou3oA; zNq1-8!xDmF*T@+_U=+mh$jJf6?dYgy#^am;M`uK5blh=77)EhM@t~py21LYhMiCH! z$QqK6jX=`rPP)_kQdM2ctM}e~_y1olodi*s$9d_h_g?+)-v8e3-tXT3$G9%ti|{al z09OXUUl|5A8-UGg0h$i^V(?}V%)8vU`G*dpHo&Vq7c>pVcQya!6@Dsmj@#jv7C*qh zIhOJ6_K0n?*d`*T7TDuW-}m`9Kz3~>+7`DUkbAraU%yi+R{N~~X<U=TR~Ph0Kd8$Y zxE$51Y7tF~7i8Q(32a16Sn0UBS1nZF%~jzQD?r{wP~dM|A0`JXQjVRuqNfz$`)+QD zn18t};UH$3@I-;YS8`Z<xXLr0O`|>A2B%zt-4=tLimUer9!2M~N{G5bftFij_O&)a zsHnOppFIzebQ`RA0$!<v%G4ys@?khO%!s8GuJU^<3eT}nwW*9{a8CH1DqrkZsfb@Q zqHpt`w>yUM-lg#<l`!D)MZP+rtl;s3&)I43%hD1ys%6g1SOIRKjA%y^W+DcI!uk|U zd{ZkCC@TamXV9d+maS(!s9A?&m&#~8Z6j7+`?nOViX;E~6C8c$9vJZ$f)dB7^4%5A ze6ftc;&f68@dTgV5=1yw*$@HMgoy=Bet3TyXCZEBB}52$pD3Y}p^%C04C3h&h4q!& zLIx~*D39dePR_x!<8aa)h$J(x<7wEjB<yGuotrK|-(_22C*z!Dx=Pf76|;GoycWgm zi_f4mK8#2zgZ545!s$p+C`xA=bS;C{qPtN^jSXJ6g7BWHWYEHdK;h?e)6~)rEukkZ zv<fvb6A`3)vnK%3F!dnS*#dmdZZzA8XnR(@K-{V4;&&pu=|aBCREiBfa-Vu}P_1x6 z=oXO(6-eXAgFm9hh=bw`T`j|L^KfT#P#$TDQ`4%hh4zhSU~1QHxcMoV4i$--%JmwG z01*MU4{Z(QzM(=gOolEMrTcgxxN4@<`WQ-~!1quZ86hA`h%a2E1PaQoQbLZ7jax9a z=Q&hz(};C0Al??Db>*o@_O2wf422iLnM6cU(ktYU8#;*G!QGhIy9+ZfzKjLuZo%@a z-i@9A`X%J{^;2q&ZHY3C(B%gqCPW!8{9C0PMcNZccefK){s|V5-xxtHQc@uf>XqhD z7#N^siWqetgq29aX>G^olMf=bbRF6@Y(}zYxw6o!9WBdG1unP}<(V;zKlcR2p86fq zYjaqB^;Ycq>Wy@5T1xOzG3tucG3e<CrU6d(%=C4^CeS?3fAs{Q;=QRXRGFG$$Sh#+ z=Xav>%nPvajaN{CrFbnzv^9&K3$NrDm*eQe4`BGQ2bI;dFEwyt>hK%X!L6)82aOZp zsrGcJ#7PoX7)s|~t6is?FfX*7vWdREi58tiY4S)t6u*|kv?J)d_$r+CH#eZ?Ef+I_ z(eVlX8dh~4QP?o*E`_MgaNFIKj*rtN(0Raj3ECjSXcW<zSMcJwFykpKy7V$6m-J%# z;5H_*yb{DoFF<19Y9zAD2=@3%1+JEhD2^Ovcqgb0=8#H-Zp+C}wIZ=#slwP9pZGj2 zycjRv`kzdWt`gC%C0@@66v(Tb&9>fd#27NYs&~?t`Q<VaeSKK`_N^HD)xF3Myi9;6 zQJ$Tn*)1%;{B4LY>ZFT}!Zaf=ldZIhi}LhQlqLo+o5(Pvui&{7PD__^53f9j>HW`Q z_V8X5j~$|GP9qXu0C#!@RX2}lXD35@3N5{BkUi%jta<l`Q6e7q-hPjoYU{jc`tMsK zR$N@o6@Zf#bg$~ut{2QFON2AbN>PQ*H6OX2zIz4QPuqmTv3`vG{zc>l3t0B9E75h< z8&twGh%dp7WPNI+tRl%#gf2}Epg8st+~O4GjtwJsXfN;EjAmyr6z5dnaFU(;IV~QK zW62fogF~zA``(Q>_SmD!izc6Y4zq*97|NAPHp1j5X7Op2%;GLYm>^HEMyObo6s7l) zE3n|aOHi5~B84!}b^b*-aL2E)>OEJX_tJ~t<#VJ?bT?lDwyDB&5SZ$_1aUhmAY}#* zs@V1I+c5md9%R-o#_DUfqVtRk>59{+Opd5Yu%dAU#VQW}^m}x-30ftBx#527{^pI4 z6l2C6C7QBG$~NLYb3rVdLD#Z{+SleOp`(Lg5J}`kxdTHe(nV5BdpLrD=l|)e$gEqA zwI6vuX-PFCtcDIH>bGY2dwq&^tf+&R?)nY-@7_j%4CMRAF}C9w%p86W<2!aSY$p+k zrkFtG=cGo38RnrG28;?PNk%7a@faaXq&MS*&?1Z`7Ojw7(#>}ZG4nMAs3VXxfdW>i zY4VX02c5;f7jDPY_7@Oa)CHH}cH<3y#}_!nng^W+h1e-RL*YFYOteC@h?BtJZ+?sE zy)P5^8Mregx{nQaw1NY-|3>{Z)|0`?zc?G2-acYiSU`tj#sSG<K)l&WdQdsgNwEfY z!A53L7RgMD${{ji2BSq#C;@Y25;T6MH3Cv-gF(WMIUF#8kzYTDAm(H9O`k=gr;l`H zR=Jc<VFOQc3f<H9LZ+%+%W%lC4j;zYle@9;lOG~Qc^n7tc!<wB{H+PciYbehj?7|g z*NbRb;=px<*2Gi-w3%cB;?%3=$n6AonmyQ}rA>fm7k86ZQ0SQgPevcklHxM9<~4yW zR796sisf1|!#<W>{Z=e^)0;_8iUhL8g(;j$l=02FTPZ(dZV@s#aQ`DHkLM6=Ysb<n zF2d-eFQ9N}oE*xo*HJcsKeKln<u{S;$4KKzZ^TmsY6dBj#mO-|v836^Bkim$oTC${ zPUboL9u!Y8&9K<f>E4iQ!b#*374l0Jw5;jD%J;vQayq=nD8-kHI~f9Ux|32SJUM`> zGp2UGK*4t?cRKi!2he`zI#j0f${I#f-jeT?u_C7S4WsA0)ryi-1L0(@%pa^&g5x=e z=KW9+Nn(=)1T&S8g_ug%dgk*~l2O-$r9#zEGBdQsweO<oSCXyHDttg*q^zMSjZw3V z{1tcQ7{d=gNvsv=o^cG``xuTr{4BhgiV{3P&>%t*6F4c8JC36JtTizCyy+E4h%G(+ z5>y$%0txMuQ$e~wjFgN(xrAndHQo`Za+K*?gUVDTBV&Ap^}|{w#CIq{DRe}+l@(Ec zCCV6f_?dY_{+f{}6XGn!pL_up?}@>KijT^$w#Lb6iHW&^8RP~g6y=vZBXx~B9nI^i zGexaPjcd(%)zGw!DG_dDwh-7x6+ST#R^${iz_M$uM!da8SxgB_;Z0G%Y*HpvLjKw; zX=ir7i1O$-T|*TBoH$dlW+TLf5j5sep^DlDtkox;Kg{Q%EXWedJq@J@%VAcK)j3y1 zShM!CS#qax;D@RND%2t3W6kv+#Ky0F9<3YKDbV^XJ=^$s(Vtza8V72YY)577nnldI zHMA0PUo!F3j(ubV*CM@PiK<<UFy9zWIk%=zjfh&dh1uOlF*lxv&CG5^BFa*th{tl< z2=iPR@mYsai76p`HB~5NthW<AmtKj*m%kHlyyM3>^|RM2(DuCbG7`W}Rg(xdYC>C~ z;1KJGLN&$cRxSZunjXcntykmpFJ7;dk>shY(DdK&3K_JDJ6R%D`e~6Qv67@Rwu+q9 z*|NG{r}4F8f{Dfzt0+cZMd$fvlX3Q`dzM46@r?ISxr;9gBTG2rmfiGOD*#c*3f)cc zF+PFZo<Yp)-;b`%=c4Pv%`9i#d9HM_-j!}Fn3#ILpA^MKB#~CY_lhp@$>bY$-^}J8 z%n=h4;x2}cP!@SiVd!v;^Ww<Q?nmc2RBqAII(2E_z?$b$S|JU3i%Bp)(2vsLF+Bf? zFJRz-`<OS#(<CWa#&P&)*rs-xbg#L?lPrCQm;}@0YDrY`Wp&fA%=s0faxj|f7_(@n zC6pkEqyPO&jQs9VlEMp^GghN8JcuP%zw5*%qJ&n0JRr`*H6_$aGL%#JnMp+o1H($v z%2*ydK6N9lB&;^7$+55VM@^Z)XxK)DWD%HjWPICxWY1hrIZ0~gDk^#z;Y8StVkuBU z%+kH4XqAO6arg{z?rf1I>o0(N??-ygDr7gG^NKxDjSo{5T{?$|Qo5;8V!~D6O;F*I zuY!gd@+2j_8Rn=UWDa#*4E2auWoGYDddMW7t0=yuC(xLWky?vLimM~!$3fgu!dR>p z?L<Ne*najK6v+Qzi`Ot4E=GJ<j97t7>?!8z>6v$|MsLb&dU?ob)Zd!B)!a*Z2eTE7 zKCzP&e}XO>CT<fAMQY6lgqc+=GAEUT6&Cjl048a7_N?>%=o(v+WUY`Az*`9inbTG& z_9_*oQKw;sc8{ipoBC`S4Tb7a%tUE)1fE+~ib<YPiP~sV#6Z0djU*|_9C?0i#(dKF z<cdDJ*7`rKV-QL!R<cMZHvY>$;|(`|4QbXc2>VzFi%1nX%ti;^s3~NIL0R}!!a{0A zyCRp0F7Y&vcP&3`&Dzv5!&#h}F2R-h&QhIfq*ts&qO13{_CP}1*sLz!hI9VoTSzTu zok5pV0+~jrGymE~{TgbS#nN5+*rF7ij)cnSLQw0Ltc70zmk|O!O(kM<3zw-sUvkx~ z2`y+{xAwKSa-0}n7{$I@Zo<g6hnSldQIQp@<Dx4^)U99pT*HbAv4Q@cTG^&%++_~Y z*3i!e^BZ)GD15qAD2Lo9E@ug@Rz?}a7DZ0S>p7CWy%_xIeN1e-7&OjQ6vZZPbZ^3_ z(~=;ZSP98S2oB#35b1~_x`2gWiPdIVddEf`AD9<@c_s)TM;3J$T_l?pr{<7PTgdiy zBc5IGx)g~n=s+Z$RzYCmv8PlJu%gkh^;%mTGMc)UwRINVD~K;`Rl!5@hhGg;y>5qj zq|u-Yf0q_~Y+Mbivkkfa0nAOzB1acnytogsj_m7FB(-FjihMek#GAU4M!iXCgdK8a zjoKm?*|iz7;dHm4$^hh(`Ufl>yb>$hjIA-;>{>C}G0Di%b<rD<WOOR$OQ<sG4BT@U zjAT0rTk7>GvUsJkfLAV|xq32c<y2?|BSfxNjNe=zPEQIZW%Gq!v38PGGN0GoLg-$# zs3qgJFb+oB(@6I8vIZy;FVvVxr!qc?l9j;gJ)BGi@x@)b8PNn}9d->>RqJqTBJ3Dx zYC;*Dt|S$b6)aCJFnK(Eey$M1DpVV~_M<gS#Q8;XMKs+)-?LbX##n+*qdGi>IhwK> zygo(jWC|_IRw|456`roEyXtkNLWNAt-4N1qyN$I@DvBzt;e|?g<*HK1%~cq|^u*}C zmMrwh>{QAq?Ar~4l^DqT%SQ)w)FA(#7#u+N;>E975rYML>)LgE`2<7nN=C1pC{IkV zVw}_&v6j&S?QVh*)wF3#XmE@0($^BVl1969csLKUBNer{suVd!a~B!0MxWY?=(GD6 zy$G&ERFR#i6G4=2F?R4}Mz3B?3tnpoX3)qFF2sh9-Jn*e%9F>i{WG7$_~XyOO2!+@ z6k+38KyD@-0=uee54D0!Z1@B^ilj~StchdOn(*qvg~s5QJpWGc!6U^Aj!xt-HZn_V zS%|fyQ5YS@EP2lBIodXCLjG_+a)%En+7jzngk@J>6D~^xbxKkvf-R0-c%mX+o{?&j zZZ%RxFeav8Y0gkwtdtrwUb-i0Egd2C=ADu%w5VV-hNJvl)GZ?M;y$!?b=S+wKRK7Q zcOjPT!p<*#8m;TsBih=@Xc&c)?Vy`Ys>IvK@|1%N+M6J-^RCRaZcPP2eQh9DEGZr+ z?8B~wF14mk4Xk<FB_!s@;Ik^r^WOeFdr%!YithENqGRa_M3aAdNbWxWLTvx!b(r41 zOE)-}crDgGRxG0Pi6^y6RlAQ6*C1R>uen{wY^CWwS1PI<8gikY*)3?RSo5l8es4*J z43k<jX6KHv?ml)DiS|ykGYWODT8C6;XMF|t)sFTvHZwXdXALhc(nz=~B2bCW&r92h zQ(E*ifwYA3T8-5KU)LM*raVi5D!H1i-s?9KqR1)@>_BIwc}of=6Pfs%xIxlMDGOJN zvl!a>G)52XMqA%fbgkZi%)%bN*ZzZw2!rn4@+J)2eK#kWuEW{)W~-`y1vhA5-7p%R z&f5N!a9f8cK1Xa=O}=9{wg%}Ur^+8Y(!UCeqw>%wj@|bYHD-bZO~mk3L$9_^MmF3G zvCiK^e@<qzbh$nxQ!!SCVd?7YQnx0YG%4ne457-%;*HJe*_Vc$VW4>q6<v|!CGA%U zw?WMs1}c1KsaVi^QKX*+V?JqASTTY|hl!xB3{7Bs;2{;$TO@+9rcjDBnySi*qR=G$ zwx53^ERPdptI3RmC_hV7tV&X)+qhGV`z1p+^lJM^n$}|GwS#Ia%Hd8VsVuWwE<nq< zo6ymJ5C(z1|NdVf$j{&eKaiO&Gwas+#I?dmB2^^f&|0=$stXnISTM;l9U)8FW2qep zviYSr#c}8^POGem7>G?tHkM8%GqsBMZaB20W$UEt_5r~jc#WlR>Bv{6W>A=!#InoY zLOd04@Rz?*7PpW8u|+}bt`?+Z(GsX{Br4A2$ZZ(26Degmr9`O=t2KgHTL*==R3xcP z&Y(J7hC@6_x8zVz!CX3l4Xtss6i7r#E6kXMNN1~>9KTRzewfp))ij%)SBBl0fZdYP zd!zzQD5u8yk-u|41|Rqz7_tCFUMThZJVj)yQf6^Cwtn|Ew6cm5J|u1<ZJV(}2eIqc zTTp(8S=e;wDivhUKNY83_i?nYURTG#^nv}@`SqJvbL_++(?#a|E%^AYw=yG_u=~qj z#^7ytqvgEyIQu)dG9h;1;GK8ig@61ynMAU_l;N9I^lrTz%ir?>Bq>MWX-AfB&NE;C z62@=-0le`E6-CurMKjoIy)BuUmhMGJb}pPx!@GLWMT+wH2R?wA=MEy)o57~feFp8P zY@YXAyt4<1FD<|iw{FGQu~GEI<4C64)V*QiVk+VzOV^9GWf4ir#<OH2N2m=0WprG) z5vPCV^XmQyEIO5fP3zl^!<@%S4nwnj@@)<J7}>oYgHJz!wq>iZV#_6@_{)&lum)4x z_Of*CLVQ7wdT#XT-(h<H9xAmFog2?aY*8<)6-(d@AA=S6b-#7}Dh@G{cgsZ9cGexg zMTFPe)~{1aR7(XMxcxgQyfmN|YXg?XqdRsoP&vAnV9aZYos6mKyL<1y2S0w_U*m~e zzS(H3%A$^5IoHvI$Duoagl&B8@PFN1Z_+tDBhm(HdWBq*=y$|Ky(~ECR-MpY<Xx#H zOOQEbt?F{-hleon^lrMgsoP#gV@bk3>0qH%mcIF7yzMIvvTN3bPceK>PpJi(=3Nny zbSn}p$dGKQUlX&-t~RR)#F7I<8NCD^yke(vdf#4^aAh}M-{tS9-&^tC4`KU_pToXy z+|K8sx}a)Kh{h{;*V1#hs1xB%(?j>)g~`Wv(9F)f=Qn)(daVB7hZtcp^#LrEr1T1J zZSJ*lVyVVjhy)mkex9Whn=EinKDHe@KlfQI-Fl7M?-c~HnW0;C;+MbUY8?FToy;A+ zs&Nc7VZ=Of+e!G6s#+S5WBU)kgQq_I1@!uH74GJ-+O|%0HXm9Mqlvp|j%0`T>fr9^ zK;qo>XdwZW<>%tTA+<(1^6(>=-2N;hRgBnjvEjN;VbKMbFg--WrGy|XESoH1p|M4` z86(gC^vB4qScASZ&cdpT{~QDN-jC|GJ<MU&Jkt$5{}d))ehJyN>(RYoW1VW4!SSn- zhQds9&RBKn6<EIILJH_8cY5-pA4R|fyXk9RQJqQIfhsg7(W9$V*=(bh%IABME-b8Y z+qKfrGV7sWYH$z_-0%;m%;k_?*oTX5`UYCgSfTb%$?})Qx?YZ5cixGgUHf6||HaS4 zQ7yILZ%M{A?YbHfl24N}7GW5cU8o9QtaoA=3B|2UtX=B5B*E4dry{+49dp#F$gDjL z4&7FW(Sh%O7v4-sRjOiHS&`<DuC2|YNunf}(sUlbz4>M&GVK_Aayt(Hekbnw=tr>f z^o@v9_*iQO1*zeOrts9Q-$pc@!StS&kz$cF`s@pM`rmJXTP&h5G)A74!0e%ZJbl}( zssI|_!%~_hZFypv*S^JE5N&Kvmx7KiG<|fGMO=WrH+@Yhuj+KwiS#l4>@%2nl<r3N z3R}JyExR(tHsiW<@8qI{-6s5~9Oy;SA~}qJJHi*)oUw9o4hiCADb3#zOCiTPVv6Q> zS)mDikfmokO4q2A)hRVZBq2-5q&XC>%HOLkOYxZ66(s8<qU;H~^XM9}XdE2{7nW?9 zh2BKk*wztMfkqrg3aX(>6?=0s4z5xbiOV)}L-&6b)h6(~CIaR#JNw~46+WBiU7IhB zq!Nu<k~0^v9Yri_J17h?UW=~fFxu1?IXty$Lq(JI?Njx8(0$<PjEy!<MzrE7{5CI? zs(mhkOIqS3+3*8=pV#kG(D0fzS2pkKZ4LlZJ&w{U2@dU@@V_S*O;3kXh1)n#tHJB5 zHGb3QMx&wrU3Y{q>R4!TsYnyBg>@G=Ib*cMq^k<}AMpCeYEf&dzfiGI-wOQ7hb+nA zkN7_){y&c3<jd7kgGnL(G$Y?_y!W%(qyHzs0KNg3oGt6Ko&W#<07*qoM6N<$f>xC0 AQ~&?~
literal 0 HcmV?d00001
diff --git a/src/public/javascripts/controls.js b/src/public/javascripts/controls.js index ca29aef..7392fb6 100644 --- a/src/public/javascripts/controls.js +++ b/src/public/javascripts/controls.js @@ -1,6 +1,8 @@ -// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) -// (c) 2005-2008 Ivan Krstic (http://blogs.law.harvard.edu/ivan) -// (c) 2005-2008 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 diff --git a/src/public/javascripts/dragdrop.js b/src/public/javascripts/dragdrop.js index 07229f9..15c6dbc 100644 --- a/src/public/javascripts/dragdrop.js +++ b/src/public/javascripts/dragdrop.js @@ -1,5 +1,6 @@ -// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) -// (c) 2005-2008 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/ @@ -311,7 +312,7 @@ var Draggable = Class.create({ 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); @@ -454,7 +455,7 @@ var Draggable = Class.create({ },
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; @@ -730,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)); @@ -825,7 +826,7 @@ var Sortable = { 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') diff --git a/src/public/javascripts/effects.js b/src/public/javascripts/effects.js index 5a639d2..c81e6c7 100644 --- a/src/public/javascripts/effects.js +++ b/src/public/javascripts/effects.js @@ -1,4 +1,6 @@ -// 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/) @@ -145,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 || {})); } };
@@ -228,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; diff --git a/src/public/javascripts/prototype.js b/src/public/javascripts/prototype.js index dfe8ab4..06249a6 100644 --- a/src/public/javascripts/prototype.js +++ b/src/public/javascripts/prototype.js @@ -1,5 +1,5 @@ -/* Prototype JavaScript framework, version 1.6.0.3 - * (c) 2005-2008 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,32 +7,53 @@ *--------------------------------------------------------------------------*/
var Prototype = { - Version: '1.6.0.3',
- Browser: { - IE: !!(window.attachEvent && - navigator.userAgent.indexOf('Opera') === -1), - Opera: navigator.userAgent.indexOf('Opera') > -1, - 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, + SelectorsAPI: !!document.querySelector, - ElementExtensions: !!window.HTMLElement, - SpecificElementExtensions: - document.createElement('div')['__proto__'] && - document.createElement('div')['__proto__'] !== - document.createElement('form')['__proto__'] + + 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 } };
@@ -40,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(); @@ -56,39 +106,39 @@ 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") { + value.argumentNames()[0] == "$super") { var method = value; value = (function(m) { - return function() { return ancestor[m].apply(this, arguments) }; + return function() { return ancestor[m].apply(this, arguments); }; })(property).wrap(method);
value.valueOf = method.valueOf.bind(method); @@ -99,198 +149,331 @@ Class.Methods = {
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() : 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); + + 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); + }
- toQueryString: function(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) { + function isElement(object) { return !!(object && object.nodeType == 1); - }, + }
- isArray: function(object) { - return object != null && typeof object == "object" && - 'splice' in object && 'join' in object; - }, + function isArray(object) { + return _toString.call(object) === ARRAY_CLASS; + } + + var hasNativeIsArray = (typeof Array.isArray == 'function') + && Array.isArray([]) && !Array.isArray({}); + + if (hasNativeIsArray) { + isArray = Array.isArray; + }
- isHash: function(object) { + 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"; + } + + 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; } -});
-Object.extend(Function.prototype, { - argumentNames: function() { - var names = this.toString().match(/^[\s(]*function[^(]*(([^)]*))/)[1] + 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); - }, + }
- defer: function() { - var args = [0.01].concat($A(arguments)); + 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); }; } -});
-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"'; -}; + return { + argumentNames: argumentNames, + bind: bind, + bindAsEventListener: bindAsEventListener, + curry: curry, + delay: delay, + defer: defer, + wrap: wrap, + methodize: methodize + } +})());
-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; +(function(proto) { + + + 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; @@ -319,8 +502,10 @@ var PeriodicalExecuter = Class.create({ try { this.currentlyExecuting = true; this.execute(); - } finally { this.currentlyExecuting = false; + } catch(e) { + this.currentlyExecuting = false; + throw e; } } } @@ -339,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)) { @@ -354,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,'>'); + }
- 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) : ''; - }, + function unescapeHTML() { + return this.stripTags().replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&'); + }
- 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) { @@ -434,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()); - }, + } + + function parseJSON() { + var json = this.unfilterJSON(); + return JSON.parse(json); + }
- include: function(pattern) { + 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.stripTags().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('') -}); - -String.prototype.escapeHTML.div.appendChild(String.prototype.escapeHTML.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) { @@ -564,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); @@ -594,8 +810,8 @@ Template.Pattern = /(^|.|\r|\n)(#{(.*?)})/;
var $break = { };
-var Enumerable = { - each: function(iterator, context) { +var Enumerable = (function() { + function each(iterator, context) { var index = 0; try { this._each(function(value) { @@ -605,17 +821,17 @@ var Enumerable = { if (e != $break) throw e; } return this; - }, + }
- eachSlice: function(number, iterator, context) { + 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) { + function all(iterator, context) { iterator = iterator || Prototype.K; var result = true; this.each(function(value, index) { @@ -623,9 +839,9 @@ var Enumerable = { if (!result) throw $break; }); return result; - }, + }
- any: function(iterator, context) { + function any(iterator, context) { iterator = iterator || Prototype.K; var result = false; this.each(function(value, index) { @@ -633,18 +849,18 @@ var Enumerable = { throw $break; }); return result; - }, + }
- collect: function(iterator, context) { + function collect(iterator, context) { iterator = iterator || Prototype.K; var results = []; this.each(function(value, index) { results.push(iterator.call(context, value, index)); }); return results; - }, + }
- detect: function(iterator, context) { + function detect(iterator, context) { var result; this.each(function(value, index) { if (iterator.call(context, value, index)) { @@ -653,32 +869,32 @@ var Enumerable = { } }); return result; - }, + }
- findAll: function(iterator, context) { + function findAll(iterator, context) { var results = []; this.each(function(value, index) { if (iterator.call(context, value, index)) results.push(value); }); return results; - }, + }
- grep: function(filter, iterator, context) { + 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.call(context, value, index)); }); return results; - }, + }
- include: function(object) { + function include(object) { if (Object.isFunction(this.indexOf)) if (this.indexOf(object) != -1) return true;
@@ -690,31 +906,31 @@ 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) { + function inject(memo, iterator, context) { this.each(function(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) { + function max(iterator, context) { iterator = iterator || Prototype.K; var result; this.each(function(value, index) { @@ -723,9 +939,9 @@ var Enumerable = { result = value; }); return result; - }, + }
- min: function(iterator, context) { + function min(iterator, context) { iterator = iterator || Prototype.K; var result; this.each(function(value, index) { @@ -734,9 +950,9 @@ var Enumerable = { result = value; }); return result; - }, + }
- partition: function(iterator, context) { + function partition(iterator, context) { iterator = iterator || Prototype.K; var trues = [], falses = []; this.each(function(value, index) { @@ -744,26 +960,26 @@ var Enumerable = { 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) { + function reject(iterator, context) { var results = []; this.each(function(value, index) { if (!iterator.call(context, value, index)) results.push(value); }); return results; - }, + }
- sortBy: function(iterator, context) { + function sortBy(iterator, context) { return this.map(function(value, index) { return { value: value, @@ -773,13 +989,13 @@ var Enumerable = { 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(); @@ -788,336 +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(); + 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) { - $A = function(iterable) { - if (!iterable) return []; - // In Safari, only use the `toArray` method if it's not a NodeList. - // A NodeList is a function, has an function `item` property, and a numeric - // `length` property. Adapted from Google Doctype. - if (!(typeof iterable === 'function' && typeof iterable.length === - 'number' && typeof iterable.item === 'function') && iterable.toArray) - return iterable.toArray(); - var length = iterable.length || 0, 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, context) { - $R(0, this, true).each(iterator, context); - 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 initialize(object) { + this._object = Object.isHash(object) ? object.toObject() : Object.clone(object); + }
- function toQueryPair(key, value) { - if (Object.isUndefined(value)) return key; - return key + '=' + encodeURIComponent(String.interpret(value)); + + 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); + } }
- return { - initialize: function(object) { - this._object = Object.isHash(object) ? object.toObject() : Object.clone(object); - }, + function set(key, value) { + return this._object[key] = value; + }
- _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 get(key) { + if (this._object[key] !== Object.prototype[key]) + return this._object[key]; + }
- set: function(key, value) { - return this._object[key] = value; - }, + function unset(key) { + var value = this._object[key]; + delete this._object[key]; + return value; + }
- get: function(key) { - // simulating poorly supported hasOwnProperty - if (this._object[key] !== Object.prototype[key]) - return this._object[key]; - }, + function toObject() { + return Object.clone(this._object); + }
- unset: function(key) { - var value = this._object[key]; - delete this._object[key]; - return value; - },
- toObject: function() { - return Object.clone(this._object); - },
- keys: function() { - return this.pluck('key'); - }, + function keys() { + return this.pluck('key'); + }
- values: function() { - return this.pluck('value'); - }, + function values() { + return this.pluck('value'); + }
- index: function(value) { - var match = this.detect(function(pair) { - return pair.value === value; - }); - return match && match.key; - }, + function index(value) { + var match = this.detect(function(pair) { + return pair.value === value; + }); + return match && match.key; + }
- merge: function(object) { - return this.clone().update(object); - }, + function merge(object) { + return this.clone().update(object); + }
- update: function(object) { - return new Hash(object).inject(this, function(result, pair) { - result.set(pair.key, pair.value); - return result; - }); - }, + function update(object) { + return new Hash(object).inject(this, function(result, pair) { + result.set(pair.key, pair.value); + return result; + }); + }
- toQueryString: function() { - return this.inject([], function(results, pair) { - var key = encodeURIComponent(pair.key), values = pair.value; + function toQueryPair(key, value) { + if (Object.isUndefined(value)) return key; + return key + '=' + encodeURIComponent(String.interpret(value)); + }
- 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 toQueryString() { + return this.inject([], function(results, pair) { + var key = encodeURIComponent(pair.key), values = pair.value;
- inspect: function() { - return '#<Hash:{' + this.map(function(pair) { - return pair.map(Object.inspect).join(': '); - }).join(', ') + '}>'; - }, + 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('&'); + }
- toJSON: function() { - return Object.toJSON(this.toObject()); - }, + function inspect() { + return '#<Hash:{' + this.map(function(pair) { + return pair.map(Object.inspect).join(': '); + }).join(', ') + '}>'; + }
- clone: function() { - return new Hash(this); - } + 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() { @@ -1164,7 +1453,6 @@ Ajax.Responders.register({ onCreate: function() { Ajax.activeRequestCount++ }, onComplete: function() { Ajax.activeRequestCount-- } }); - Ajax.Base = Class.create({ initialize: function(options) { this.options = { @@ -1186,7 +1474,6 @@ Ajax.Base = Class.create({ this.options.parameters = this.options.parameters.toObject(); } }); - Ajax.Request = Class.create(Ajax.Base, { _complete: false,
@@ -1202,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'; } @@ -1210,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)) @@ -1269,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;
@@ -1323,7 +1607,6 @@ Ajax.Request = Class.create(Ajax.Base, { }
if (state == 'Complete') { - // avoid memory leak in MSIE: clean up this.transport.onreadystatechange = Prototype.emptyFunction; } }, @@ -1340,7 +1623,7 @@ Ajax.Request = Class.create(Ajax.Base, { getHeader: function(name) { try { return this.transport.getResponseHeader(name) || null; - } catch (e) { return null } + } catch (e) { return null; } },
evalResponse: function() { @@ -1360,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(); @@ -1381,6 +1671,7 @@ Ajax.Response = Class.create({ },
status: 0, + statusText: '',
getStatus: Ajax.Request.prototype.getStatus, @@ -1510,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++) @@ -1534,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, @@ -1554,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); @@ -1568,12 +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 || { }); - if (element) this.Element.prototype = element.prototype; -}).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'; @@ -1603,22 +1921,100 @@ 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(){
- replace: function(element, content) { - element = $(element); - if (content && content.toElement) content = content.toElement(); - else if (!Object.isElement(content)) { - content = Object.toHTML(content); - var range = element.ownerDocument.createRange(); + 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); + if (content && content.toElement) content = content.toElement(); + else if (!Object.isElement(content)) { + content = Object.toHTML(content); + var range = element.ownerDocument.createRange(); range.selectNode(element); content.evalScripts.bind(content).defer(); content = range.createContextualFragment(content.stripScripts()); @@ -1679,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).select("*"); + return Element.select(element, "*"); },
firstDescendant: function(element) { @@ -1710,78 +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(); + var ancestors = Element.ancestors(element); return Object.isNumber(expression) ? ancestors[expression] : - Selector.findElement(ancestors, expression, index); + Prototype.Selector.find(ancestors, expression, index); },
down: function(element, expression, index) { element = $(element); - if (arguments.length == 1) return element.firstDescendant(); - return Object.isNumber(expression) ? element.descendants()[expression] : + 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 Object.isNumber(expression) ? previousSiblings[expression] : - Selector.findElement(previousSiblings, expression, index); + 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 Object.isNumber(expression) ? nextSiblings[expression] : - Selector.findElement(nextSiblings, expression, index); + 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; },
@@ -1820,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) { @@ -1840,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; }, @@ -1854,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; @@ -1892,7 +2312,7 @@ Element.Methods = {
scrollTo: function(element) { element = $(element); - var pos = element.cumulativeOffset(); + var pos = Element.cumulativeOffset(element); window.scrollTo(pos[0], pos[1]); return element; }, @@ -1938,37 +2358,12 @@ 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 (Prototype.Browser.Opera) { element.style.top = 0; element.style.left = 0; @@ -2009,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); },
@@ -2034,14 +2431,13 @@ Element.Methods = {
absolutize: function(element) { element = $(element); - if (element.getStyle('position') == 'absolute') return element; - // 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); @@ -2058,12 +2454,11 @@ Element.Methods = {
relativize: function(element) { element = $(element); - if (element.getStyle('position') == 'relative') return element; - // 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'; @@ -2094,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;
@@ -2128,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'; @@ -2158,10 +2546,9 @@ Element.Methods = { } };
-Element.Methods.identify.counter = 1; - Object.extend(Element.Methods, { getElementsBySelector: Element.Methods.select, + childElements: Element.Methods.immediateDescendants });
@@ -2182,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()]) @@ -2219,14 +2603,10 @@ if (Prototype.Browser.Opera) { }
else if (Prototype.Browser.IE) { - // IE doesn't report offsets correctly for static elements, so we change them - // to "relative" to get the values, then change them back. Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap( function(proceed, element) { element = $(element); - // IE throws an error if element is not in document - try { element.offsetParent } - catch(e) { return $(document.body) } + if (!element.parentNode) return $(document.body); var position = element.getStyle('position'); if (position !== 'static') return proceed(element); element.setStyle({ position: 'relative' }); @@ -2240,12 +2620,9 @@ else if (Prototype.Browser.IE) { Element.Methods[method] = Element.Methods[method].wrap( function(proceed, element) { element = $(element); - try { element.offsetParent } - catch(e) { return Element._returnOffset(0,0) } + if (!element.parentNode) return Element._returnOffset(0, 0); var position = element.getStyle('position'); if (position !== 'static') return proceed(element); - // Trigger hasLayout on the offset parent so that IE6 reports - // accurate offsetTop and offsetLeft values for position: fixed. var offsetParent = element.getOffsetParent(); if (offsetParent && offsetParent.getStyle('position') === 'fixed') offsetParent.setStyle({ zoom: 1 }); @@ -2257,14 +2634,6 @@ else if (Prototype.Browser.IE) { ); });
- Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap( - function(proceed, element) { - try { element.offsetParent } - catch(e) { return Element._returnOffset(0,0) } - return proceed(element); - } - ); - Element.Methods.getStyle = function(element, style) { element = $(element); style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); @@ -2306,36 +2675,90 @@ 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.extend({ @@ -2363,8 +2786,8 @@ else if (Prototype.Browser.IE) {
(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, @@ -2391,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)) { @@ -2409,7 +2852,7 @@ else if (Prototype.Browser.WebKit) { (value < 0.00001) ? 0 : value;
if (value == 1) - if(element.tagName.toUpperCase() == 'IMG' && element.width) { + if (element.tagName.toUpperCase() == 'IMG' && element.width) { element.width++; element.width--; } else try { var n = document.createTextNode(' '); @@ -2420,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 { @@ -2438,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 ('outerHTML' in document.createElement('div')) { +if ('outerHTML' in document.documentElement) { Element.Methods.replace = function(element, content) { element = $(element);
@@ -2475,8 +2892,8 @@ if ('outerHTML' in document.createElement('div')) { 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) }); @@ -2498,11 +2915,17 @@ Element._returnOffset = function(l, t) { };
Element._getContentFromAnonymousElement = function(tagName, html) { - var div = new Element('div'), t = Element._insertionTranslations.tags[tagName]; + var div = new Element('div'), + t = Element._insertionTranslations.tags[tagName]; if (t) { div.innerHTML = t[0] + html + t[1]; - t[2].times(function() { div = div.firstChild }); - } else div.innerHTML = html; + for (var i = t[2]; i--; ) { + div = div.firstChild; + } + } + else { + div.innerHTML = html; + } return $A(div.childNodes); };
@@ -2529,12 +2952,13 @@ Element._insertionTranslations = { };
(function() { - 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) { @@ -2548,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.toUpperCase(), 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); @@ -2594,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; @@ -2661,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) { @@ -2686,766 +3159,1803 @@ Element.addMethods = function(methods) { Element.cache = { }; };
-document.viewport = { - getDimensions: function() { - var dimensions = { }, B = Prototype.Browser; - $w('width height').each(function(d) { - var D = d.capitalize(); - if (B.WebKit && !document.evaluate) { - // Safari <3.0 needs self.innerWidth/Height - dimensions[d] = self['inner' + D]; - } else if (B.Opera && parseFloat(window.opera.version()) < 9.5) { - // Opera <9.5 needs document.body.clientWidth/Height - dimensions[d] = document.body['client' + D] - } else { - dimensions[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(); - - if (this.shouldUseSelectorsAPI()) { - this.mode = 'selectorsAPI'; - } else if (this.shouldUseXPath()) { - this.mode = 'xpath'; - this.compileXPathMatcher(); - } else { - this.mode = "normal"; - this.compileMatcher(); - } - - },
- shouldUseXPath: function() { - if (!Prototype.BrowserFeatures.XPath) return false; +(function(viewport) { + var B = Prototype.Browser, doc = document, element, property = {};
- var e = this.expression; + function getRootElement() { + if (B.WebKit && !doc.evaluate) + return document;
- // Safari 3 chokes on :*-of-type and :empty - if (Prototype.Browser.WebKit && - (e.include("-of-type") || e.include(":empty"))) - return false; + if (B.Opera && window.parseFloat(window.opera.version()) < 9.5) + return document.body;
- // XPath can't do namespaced attributes, nor can it read - // the "checked" property from DOM nodes - if ((/([[\w-]*?:|:checked)/).test(e)) - return false; + return document.documentElement; + }
- return true; - }, + function define(D) { + if (!element) element = getRootElement();
- shouldUseSelectorsAPI: function() { - if (!Prototype.BrowserFeatures.SelectorsAPI) return false; + property[D] = 'client' + D;
- if (!Selector._div) Selector._div = new Element('div'); + viewport['get' + D] = function() { return element[property[D]] }; + return viewport['get' + D](); + }
- // Make sure the browser treats the selector as valid. Test on an - // isolated element to minimize cost of this check. - try { - Selector._div.querySelector(this.expression); - } catch(e) { - return false; - } + viewport.getWidth = define.curry('Width');
- return true; - }, + viewport.getHeight = define.curry('Height'); +})(document.viewport);
- compileMatcher: function() { - var e = this.expression, ps = Selector.patterns, h = Selector.handlers, - c = Selector.criteria, le, p, m;
- if (Selector._cache[e]) { - this.matcher = Selector._cache[e]; - return; - } +Element.Storage = { + UID: 1 +};
- this.matcher = ["this.matcher = function(root) {", - "var r = root, h = Selector.handlers, c = false, n;"]; +Element.addMethods({ + getStorage: function(element) { + if (!(element = $(element))) return;
- 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; - } - } + 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();
- compileXPathMatcher: function() { - var e = this.expression, ps = Selector.patterns, - x = Selector.xpath, le, m; + return Element.Storage[uid]; + },
- if (Selector._cache[e]) { - this.xpath = Selector._cache[e]; return; - } + store: function(element, key, value) { + if (!(element = $(element))) return;
- 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; - } - } + if (arguments.length === 2) { + Element.getStorage(element).update(key); + } else { + Element.getStorage(element).set(key, value); }
- this.xpath = this.matcher.join(''); - Selector._cache[this.expression] = this.xpath; + return element; },
- findElements: function(root) { - root = root || document; - var e = this.expression, results; + retrieve: function(element, key, defaultValue) { + if (!(element = $(element))) return; + var hash = Element.getStorage(element), value = hash.get(key);
- switch (this.mode) { - case 'selectorsAPI': - // querySelectorAll queries document-wide, then filters to descendants - // of the context element. That's not what we want. - // Add an explicit context to the selector if necessary. - if (root !== document) { - var oldId = root.id, id = $(root).identify(); - e = "#" + id + " " + e; - } + if (Object.isUndefined(value)) { + hash.set(key, defaultValue); + value = defaultValue; + }
- results = $A(root.querySelectorAll(e)).map(Element.extend); - root.id = oldId; + return value; + },
- return results; - case 'xpath': - return document._getElementsByXPath(this.xpath, root); - default: - return this.matcher(root); - } - }, - - match: function(element) { - this.tokens = []; - - var e = this.expression, ps = Selector.patterns, as = Selector.assertions; - var le, p, m; - - 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); - } - } + 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); + },
- 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; - } - } + purge: function(element) { + if (!(element = $(element))) return; + purgeElement(element);
- return match; - }, + var descendants = element.getElementsByTagName('*'), + i = descendants.length;
- toString: function() { - return this.expression; - }, + while (i--) purgeElement(descendants[i]);
- inspect: function() { - return "#<Selector:" + this.expression.inspect() + ">"; + return null; } });
-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() + "']"; - }, - className: "[contains(concat(' ', @class, ' '), ' #{1} ')]", - id: "[@id='#{1}']", - attrPresence: function(m) { - m[1] = m[1].toLowerCase(); - return new Template("[@#{1}]").evaluate(m); - }, - attr: function(m) { - m[1] = m[1].toLowerCase(); - m[3] = m[5] || m[6]; - return new Template(Selector.xpath.operators[m[2]]).evaluate(m); - }, - 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); - }, - 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}-')]" - }, - 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)]", - 'checked': "[@checked]", - 'disabled': "[(@disabled) and (@type!='hidden')]", - 'enabled': "[not(@disabled) and (@type!='hidden')]", - '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 ") + ")]"; - }, - 'nth-child': function(m) { - return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m); - }, - 'nth-last-child': function(m) { - return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m); - }, - 'nth-of-type': function(m) { - return Selector.xpath.pseudos.nth("position() ", m); - }, - 'nth-last-of-type': function(m) { - return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m); - }, - 'first-of-type': function(m) { - m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m); - }, - 'last-of-type': function(m) { - m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m); - }, - 'only-of-type': function(m) { - var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m); - }, - 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 }); - } - } - } - }, +(function() {
- 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); c = false;', - attr: function(m) { - m[3] = (m[5] || m[6]); - return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); 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]+:)?[\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(); - }, + function toDecimal(pctString) { + var match = pctString.match(/^(\d+)%?$/i); + if (!match) return null; + return (Number(match[1]) / 100); + }
- className: function(element, matches) { - return Element.hasClassName(element, matches[1]); - }, + function getPixelValue(value, property) { + if (Object.isElement(value)) { + element = value; + value = element.getStyle(property); + } + if (value === null) { + return null; + }
- id: function(element, matches) { - return element.id === matches[1]; - }, + if ((/^(?:-)?\d+(.\d+)?(px)?$/i).test(value)) { + return window.parseFloat(value); + }
- attrPresence: function(element, matches) { - return Element.hasAttribute(element, matches[1]); - }, + 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;
- attr: function(element, matches) { - var nodeValue = Element.readAttribute(element, matches[1]); - return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]); + return value; } - },
- handlers: { - // UTILITY FUNCTIONS - // joins two collections - concat: function(a, b) { - for (var i = 0, node; node = b[i]; i++) - a.push(node); - return a; - }, + 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'); + }
- // marks an array of nodes for counting - mark: function(nodes) { - var _true = Prototype.emptyFunction; - for (var i = 0, node; node = nodes[i]; i++) - node._countedByPrototype = _true; - return nodes; - }, + return whole * decimal; + }
- unmark: function(nodes) { - for (var i = 0, node; node = nodes[i]; i++) - node._countedByPrototype = undefined; - return nodes; - }, + return 0; + }
- // 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._countedByPrototype = Prototype.emptyFunction; - 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._countedByPrototype)) node.nodeIndex = j++; - } - } else { - for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++) - if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; + function toCSSPixels(number) { + if (Object.isString(number) && number.endsWith('px')) { + return number; + } + return number + 'px'; + } + + 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; + } + + 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; } },
- // 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])._countedByPrototype) { - n._countedByPrototype = Prototype.emptyFunction; - results.push(Element.extend(n)); - } - return Selector.handlers.unmark(results); + _set: function(property, value) { + return Hash.prototype.set.call(this, property, value); },
- // 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; + set: function(property, value) { + throw "Properties of Element.Layout are read-only."; },
- 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; + get: function($super, property) { + var value = $super(property); + return value === null ? this._compute(property) : value; },
- adjacent: function(nodes) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - var next = this.nextElementSibling(node); - if (next) results.push(next); + _begin: function() { + if (this._prepared) return; + + var element = this.element; + if (isDisplayed(element)) { + this._prepared = true; + return; } - return results; + + 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; },
- 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; + _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; },
- nextElementSibling: function(node) { - while (node = node.nextSibling) - if (node.nodeType == 1) return node; - return null; + _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)); },
- previousElementSibling: function(node) { - while (node = node.previousSibling) - if (node.nodeType == 1) return node; - return null; + 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; },
- // TOKEN FUNCTIONS - tagName: function(nodes, root, tagName, combinator) { - var uTagName = 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() === uTagName) results.push(node); - return results; - } else return root.getElementsByTagName(tagName); + toHash: function() { + var obj = this.toObject.apply(this, arguments); + return new Hash(obj); },
- 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 []; + 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; + }, + + '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; + }, + + 'padding-box-height': function(element) { + var height = this.get('height'), + pTop = this.get('padding-top'), + pBottom = this.get('padding-bottom'); + + return height + pTop + pBottom; + }, + + 'padding-box-width': function(element) { + var width = this.get('width'), + pLeft = this.get('padding-left'), + pRight = this.get('padding-right'); + + return width + pLeft + pRight; + }, + + 'border-box-height': function(element) { + return element.offsetHeight; + }, + + 'border-box-width': function(element) { + return element.offsetWidth; + }, + + '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; + }, + + '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; + }, + + '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'); + } + } + }); + + 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(); } - return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : []; + }); + } + + 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(nodes, root, className, combinator) { - if (nodes && combinator) nodes = this[combinator](nodes); - return Selector.handlers.byClassName(nodes, root, className); + relativeTo: function(offset) { + return new Element.Offset( + this.left - offset.left, + this.top - offset.top + ); },
- 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; + inspect: function() { + return "#<Element.Offset left: #{left} top: #{top}>".interpolate(this); },
- attrPresence: function(nodes, root, attr, combinator) { - if (!nodes) nodes = root.getElementsByTagName("*"); - if (nodes && combinator) nodes = this[combinator](nodes); - var results = []; - for (var i = 0, node; node = nodes[i]; i++) - if (Element.hasAttribute(node, attr)) results.push(node); - return results; + toString: function() { + return "[#{left}, #{top}]".interpolate(this); },
- attr: function(nodes, root, attr, value, operator, combinator) { - if (!nodes) nodes = root.getElementsByTagName("*"); - if (nodes && combinator) nodes = this[combinator](nodes); - 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); + toArray: function() { + return [this.left, this.top]; + } + }); + + function getLayout(element, preCompute) { + return new Element.Layout(element, preCompute); + } + + function measure(element, property) { + return $(element).getLayout().get(property); + } + + function getDimensions(element) { + var layout = $(element).getLayout(); + return { + width: layout.get('width'), + height: layout.get('height') + }; + } + + 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); } - return results; - }, + } + + return $(document.body); + } + + + 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(); + + 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; + } + } while (element); + + valueL -= layout.get('margin-top'); + valueT -= layout.get('margin-left'); + + return new Element.Offset(valueL, valueT); + } + + 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); + } + + function viewportOffset(forElement) { + var valueT = 0, valueL = 0, docBody = document.body; + + 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; + } + } while (element = element.parentNode); + return new Element.Offset(valueL, valueT); + } + + function absolutize(element) { + element = $(element); + + if (Element.getStyle(element, 'position') === 'absolute') { + return element; + } + + var offsetParent = getOffsetParent(element); + var eOffset = element.viewportOffset(), + pOffset = offsetParent.viewportOffset(); + + var offset = eOffset.relativeTo(pOffset); + var layout = element.getLayout(); + + 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; + } + + var originalStyles = + element.retrieve('prototype_absolutize_original_styles'); + + if (originalStyles) element.setStyle(originalStyles); + return element; + } + + 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); + } + + var eOffset = element.viewportOffset(), + pOffset = isBody(parent) ? viewportOffset(parent) : + parent.viewportOffset(); + var retOffset = eOffset.relativeTo(pOffset); + + var layout = element.getLayout(); + var top = retOffset.top - layout.get('margin-top'); + var left = retOffset.left - layout.get('margin-left'); + + return new Element.Offset(left, top); + } + }); + } +})(); +window.$$ = function() { + var expression = $A(arguments).join(', '); + return Prototype.Selector.select(expression, document); +}; + +Prototype.Selector = (function() { + + function select() { + throw new Error('Method "Prototype.Selector.select" must be defined.'); + } + + function match() { + throw new Error('Method "Prototype.Selector.match" must be defined.'); + } + + function find(elements, expression, index) { + index = index || 0; + var match = Prototype.Selector.match, length = elements.length, matchIndex = 0, i; + + for (i = 0; i < length; i++) { + if (match(elements[i], expression) && index == matchIndex++) { + return Element.extend(elements[i]); + } + } + } + + function extendElements(elements) { + for (var i = 0, length = elements.length; i < length; i++) { + Element.extend(elements[i]); + } + return elements; + } + + + 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; + } + } +}
- 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); - } - }, +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; + } + } +}
- 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 contains = document.compareDocumentPosition ? function(a, b){ + return a.compareDocumentPosition(b) & 16; +} : function(a, b){ + return a !== b && (a.contains ? a.contains(b) : true); +};
- // 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; - }); - }, +var isXML = function(elem){ + return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" || + !!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML"; +};
- // 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._countedByPrototype) { - 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); - } - } - h.unmark(nodes); - h.unmark(indexed); - return results; - }, +var posProcess = function(selector, context){ + var tmpSet = [], later = "", match, + root = context.nodeType ? [context] : context;
- '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) continue; - results.push(node); - } - return results; - }, + while ( (match = Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace( Expr.match.PSEUDO, "" ); + }
- '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._countedByPrototype) results.push(node); - h.unmark(exclusions); - return results; - }, + selector = Expr.relative[selector] ? selector + "*" : selector;
- 'enabled': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (!node.disabled && (!node.type || node.type !== 'hidden')) - results.push(node); - return results; - }, + for ( var i = 0, l = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet ); + }
- 'disabled': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (node.disabled) results.push(node); - return results; - }, + return Sizzle.filter( later, tmpSet ); +};
- 'checked': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (node.checked) results.push(node); - return results; - } - },
- operators: { - '=': function(nv, v) { return nv == v; }, - '!=': function(nv, v) { return nv != v; }, - '^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); }, - '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); }, - '*=': function(nv, v) { return nv == v || nv && nv.include(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() + '-'); } - }, +window.Sizzle = Sizzle;
- split: function(expression) { - var expressions = []; - expression.scan(/(([\w#:.~>+()\s-]+|*|[.*?])+)\s*(,|$)/, function(m) { - expressions.push(m[1].strip()); - }); - return expressions; - }, +})();
- matchElements: function(elements, expression) { - var matches = $$(expression), h = Selector.handlers; - h.mark(matches); - for (var i = 0, results = [], element; element = elements[i]; i++) - if (element._countedByPrototype) results.push(element); - h.unmark(matches); - return results; - }, +;(function(engine) { + var extendElements = Prototype.Selector.extendElements;
- findElement: function(elements, expression, index) { - if (Object.isNumber(expression)) { - index = expression; expression = false; - } - return Selector.matchElements(elements, expression || '*')[index || 0]; - }, + function select(selector, scope) { + return extendElements(engine(selector, scope || document)); + }
- findChildElements: function(element, expressions) { - expressions = Selector.split(expressions.join(',')); - 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)); - } - return (l > 1) ? h.unique(results) : results; + function match(element, selector) { + return engine.matches(selector, [element]).length == 1; } -});
-if (Prototype.Browser.IE) { - Object.extend(Selector.handlers, { - // IE returns comment nodes on getElementsByTagName("*"). - // Filter them out. - concat: function(a, b) { - for (var i = 0, node; node = b[i]; i++) - if (node.tagName !== "!") a.push(node); - return a; - }, + Prototype.Selector.engine = engine; + Prototype.Selector.select = select; + Prototype.Selector.match = match; +})(Sizzle);
- // IE improperly serializes _countedByPrototype in (inner|outer)HTML. - unmark: function(nodes) { - for (var i = 0, node; node = nodes[i]; i++) - node.removeAttribute('_countedByPrototype'); - return nodes; - } - }); -} +window.Sizzle = Prototype._original_property; +delete Prototype._original_property;
-function $$() { - return Selector.findChildElements(document, $A(arguments)); -} var Form = { reset: function(form) { - $(form).reset(); + form = $(form); + form.reset(); return form; },
@@ -3460,7 +4970,6 @@ var Form = { 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); } @@ -3480,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) { @@ -3526,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); }); },
@@ -3557,6 +5071,7 @@ Form.Methods = {
/*--------------------------------------------------------------------------*/
+ Form.Element = { focus: function(element) { $(element).focus(); @@ -3570,6 +5085,7 @@ Form.Element = { };
Form.Element.Methods = { + serialize: function(element) { element = $(element); if (!element.disabled && element.name) { @@ -3610,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; @@ -3632,6 +5148,7 @@ Form.Element.Methods = { /*--------------------------------------------------------------------------*/
var Field = Form.Element; + var $F = Form.Element.Methods.getValue;
/*--------------------------------------------------------------------------*/ @@ -3694,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); @@ -3782,354 +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() { + + 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: {} + };
-Event.Methods = (function() { - var isButton; + 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) }, - - element: function(event) { - event = Event.extend(event); - - var node = event.target, - type = event.type, - currentTarget = event.currentTarget; - - if (currentTarget && currentTarget.tagName) { - // Firefox screws up the "click" event when moving between radio buttons - // via arrow keys. It also screws up the "load" and "error" events on images, - // reporting the document as the target instead of the original image. - if (type === 'load' || type === 'error' || - (type === 'click' && currentTarget.tagName.toLowerCase() === 'input' - && currentTarget.type === 'radio')) - node = currentTarget; - } - if (node.nodeType == Node.TEXT_NODE) node = node.parentNode; - return Element.extend(node); - }, + function isLeftClick(event) { return _isButton(event, 0) }
- 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 isMiddleClick(event) { return _isButton(event, 1) }
- pointer: function(event) { - var docElement = document.documentElement, - body = document.body || { scrollLeft: 0, scrollTop: 0 }; - return { - x: event.pageX || (event.clientX + - (docElement.scrollLeft || body.scrollLeft) - - (docElement.clientLeft || 0)), - y: event.pageY || (event.clientY + - (docElement.scrollTop || body.scrollTop) - - (docElement.clientTop || 0)) - }; - }, + function isRightClick(event) { return _isButton(event, 2) } + + 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; + } + + if (node.nodeType == Node.TEXT_NODE) + node = node.parentNode;
- pointerX: function(event) { return Event.pointer(event).x }, - pointerY: function(event) { return Event.pointer(event).y }, + return Element.extend(node); + }
- stop: function(event) { - Event.extend(event); - event.preventDefault(); - event.stopPropagation(); - event.stopped = true; + 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 getEventID(element) { - if (element._prototypeEventID) return element._prototypeEventID[0]; - arguments.callee.id = arguments.callee.id || 1; - return element._prototypeEventID = [++arguments.callee.id]; - } + function _createResponder(element, eventName, handler) { + var registry = Element.retrieve(element, 'prototype_event_registry');
- 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; + } }
+ var CACHE = [];
- // Internet Explorer needs to remove event handlers on page unload - // in order to avoid memory leaks. - if (window.attachEvent) { - window.attachEvent("onunload", destroyCache); - } + if (Prototype.Browser.IE) + window.attachEvent('onunload', _destroyCache);
- // Safari has a dummy event handler on page unload so that it won't - // use its bfcache. Safari <= 3.1 has an issue with restoring the "document" - // object when page is returned to via the back button using its bfcache. - if (Prototype.Browser.WebKit) { + 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;
- var event; - if (document.createEvent) { - event = document.createEvent("HTMLEvents"); - event.initEvent("dataavailable", true, true); - } else { - 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); + }, + + start: function() { + Event.observe(this.element, this.eventName, this.handler); + return this; + }, + + stop: function() { + Event.stopObserving(this.element, this.eventName, this.handler); + return this; + },
- return Event.extend(event); + 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(), - loaded: false -}); + 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;
function fireContentLoadedEvent() { if (document.loaded) return; - if (timer) window.clearInterval(timer); - document.fire("dom:loaded"); + 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; @@ -4158,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 @@ -4179,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); @@ -4206,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') @@ -4217,7 +5846,6 @@ var Position = { element.offsetWidth; },
- // Deprecation layer -- use newer Element methods now (1.5.2).
cumulativeOffset: Element.Methods.cumulativeOffset,
@@ -4317,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/src/public/javascripts/rails.js b/src/public/javascripts/rails.js new file mode 100644 index 0000000..4283ed8 --- /dev/null +++ b/src/public/javascripts/rails.js @@ -0,0 +1,175 @@ +(function() { + // Technique from Juriy Zaytsev + // http://thinkweb2.com/projects/prototype/detecting-event-support-without-brow... + 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, texarea', 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'); + params = element.serialize(); + } else { + method = element.readAttribute('data-method') || 'get'; + url = element.readAttribute('href'); + params = {}; + } + + new Ajax.Request(url, { + method: method, + parameters: params, + evalScripts: true, + + onComplete: function(request) { element.fire("ajax:complete", request); }, + onSuccess: function(request) { element.fire("ajax:success", request); }, + onFailure: function(request) { element.fire("ajax:failure", request); } + }); + + element.fire("ajax:after"); + } + + 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') { + var field = new Element('input', { type: 'hidden', name: '_method', value: method }); + form.insert(field); + } + + if (csrf_param) { + var param = csrf_param.readAttribute('content'), + token = csrf_token.readAttribute('content'), + field = new Element('input', { type: 'hidden', name: param, value: token }); + form.insert(field); + } + + form.submit(); + } + + + document.on("click", "*[data-confirm]", function(event, element) { + var message = element.readAttribute('data-confirm'); + if (!confirm(message)) event.stop(); + }); + + document.on("click", "a[data-remote]", function(event, element) { + if (event.stopped) return; + handleRemote(element); + event.stop(); + }); + + document.on("click", "a[data-method]", function(event, element) { + if (event.stopped) return; + handleMethod(element); + event.stop(); + }); + + document.on("submit", function(event) { + var element = event.findElement(), + message = element.readAttribute('data-confirm'); + if (message && !confirm(message)) { + event.stop(); + return false; + } + + var inputs = element.select("input[type=submit][data-disable-with]"); + inputs.each(function(input) { + input.disabled = true; + input.writeAttribute('data-original-value', input.value); + input.value = input.readAttribute('data-disable-with'); + }); + + var element = event.findElement("form[data-remote]"); + if (element) { + handleRemote(element); + event.stop(); + } + }); + + document.on("ajax:after", "form", function(event, element) { + var inputs = element.select("input[type=submit][disabled=true][data-disable-with]"); + inputs.each(function(input) { + input.value = input.readAttribute('data-original-value'); + input.removeAttribute('data-original-value'); + input.disabled = false; + }); + }); +})(); diff --git a/src/public/robots.txt b/src/public/robots.txt index 4ab9e89..085187f 100644 --- a/src/public/robots.txt +++ b/src/public/robots.txt @@ -1 +1,5 @@ -# See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file \ No newline at end of file +# See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file +# +# To ban all spiders from the entire site uncomment the next two lines: +# User-Agent: * +# Disallow: / diff --git a/src/public/stylesheets/.gitkeep b/src/public/stylesheets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/script/about b/src/script/about deleted file mode 100755 index 7b07d46..0000000 --- a/src/script/about +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../config/boot' -require 'commands/about' \ No newline at end of file diff --git a/src/script/autospec b/src/script/autospec deleted file mode 100755 index 837bbd7..0000000 --- a/src/script/autospec +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env ruby -gem 'test-unit', '1.2.3' if RUBY_VERSION.to_f >= 1.9 -ENV['RSPEC'] = 'true' # allows autotest to discover rspec -ENV['AUTOTEST'] = 'true' # allows autotest to run w/ color on linux -system((RUBY_PLATFORM =~ /mswin|mingw/ ? 'autotest.bat' : 'autotest'), *ARGV) || - $stderr.puts("Unable to find autotest. Please install ZenTest or fix your PATH") diff --git a/src/script/breakpointer b/src/script/breakpointer deleted file mode 100755 index 64af76e..0000000 --- a/src/script/breakpointer +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../config/boot' -require 'commands/breakpointer' \ No newline at end of file diff --git a/src/script/console b/src/script/console deleted file mode 100755 index 42f28f7..0000000 --- a/src/script/console +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../config/boot' -require 'commands/console' \ No newline at end of file diff --git a/src/script/dbconsole b/src/script/dbconsole deleted file mode 100755 index caa60ce..0000000 --- a/src/script/dbconsole +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../config/boot' -require 'commands/dbconsole' diff --git a/src/script/destroy b/src/script/destroy deleted file mode 100755 index fa0e6fc..0000000 --- a/src/script/destroy +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../config/boot' -require 'commands/destroy' \ No newline at end of file diff --git a/src/script/generate b/src/script/generate deleted file mode 100755 index ef976e0..0000000 --- a/src/script/generate +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../config/boot' -require 'commands/generate' \ No newline at end of file diff --git a/src/script/performance/benchmarker b/src/script/performance/benchmarker deleted file mode 100755 index c842d35..0000000 --- a/src/script/performance/benchmarker +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../../config/boot' -require 'commands/performance/benchmarker' diff --git a/src/script/performance/profiler b/src/script/performance/profiler deleted file mode 100755 index d855ac8..0000000 --- a/src/script/performance/profiler +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../../config/boot' -require 'commands/performance/profiler' diff --git a/src/script/performance/request b/src/script/performance/request deleted file mode 100755 index ae3f38c..0000000 --- a/src/script/performance/request +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../../config/boot' -require 'commands/performance/request' diff --git a/src/script/plugin b/src/script/plugin deleted file mode 100755 index 26ca64c..0000000 --- a/src/script/plugin +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../config/boot' -require 'commands/plugin' \ No newline at end of file diff --git a/src/script/process/inspector b/src/script/process/inspector deleted file mode 100755 index bf25ad8..0000000 --- a/src/script/process/inspector +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../../config/boot' -require 'commands/process/inspector' diff --git a/src/script/process/reaper b/src/script/process/reaper deleted file mode 100755 index c77f045..0000000 --- a/src/script/process/reaper +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../../config/boot' -require 'commands/process/reaper' diff --git a/src/script/process/spawner b/src/script/process/spawner deleted file mode 100755 index 7118f39..0000000 --- a/src/script/process/spawner +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../../config/boot' -require 'commands/process/spawner' diff --git a/src/script/rails b/src/script/rails new file mode 100755 index 0000000..f8da2cf --- /dev/null +++ b/src/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' diff --git a/src/script/runner b/src/script/runner deleted file mode 100755 index ccc30f9..0000000 --- a/src/script/runner +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../config/boot' -require 'commands/runner' \ No newline at end of file diff --git a/src/script/server b/src/script/server deleted file mode 100755 index e9b183a..0000000 --- a/src/script/server +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env ruby - -if Process.uid == 0 or Process.gid == 0 - puts "Deltacloud aggregator cannot be run as root" - exit(1) -end - -require File.dirname(__FILE__) + '/../config/boot' -require 'commands/server' diff --git a/src/script/spec b/src/script/spec deleted file mode 100755 index 46fdbe6..0000000 --- a/src/script/spec +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env ruby -if ARGV.any? {|arg| %w[--drb -X --generate-options -G --help -h --version -v].include?(arg)} - require 'rubygems' unless ENV['NO_RUBYGEMS'] -else - gem 'test-unit', '1.2.3' if RUBY_VERSION.to_f >= 1.9 - ENV["RAILS_ENV"] ||= 'test' - require File.expand_path(File.dirname(__FILE__) + "/../config/environment") unless defined?(RAILS_ROOT) -end -require 'spec/autorun' -exit ::Spec::Runner::CommandLine.run diff --git a/src/spec/controllers/cloud_accounts_controller_spec.rb b/src/spec/controllers/cloud_accounts_controller_spec.rb index 7a82a7a..e81121f 100644 --- a/src/spec/controllers/cloud_accounts_controller_spec.rb +++ b/src/spec/controllers/cloud_accounts_controller_spec.rb @@ -1,6 +1,7 @@ require 'spec_helper'
describe CloudAccountsController do + include Authlogic::TestCase
fixtures :all before(:each) do diff --git a/src/spec/controllers/dashboard_controller_spec.rb b/src/spec/controllers/dashboard_controller_spec.rb index bd327ce..dc2c2eb 100644 --- a/src/spec/controllers/dashboard_controller_spec.rb +++ b/src/spec/controllers/dashboard_controller_spec.rb @@ -1,6 +1,7 @@ require 'spec_helper'
describe DashboardController do + include Authlogic::TestCase
fixtures :all before(:each) do diff --git a/src/spec/controllers/hardware_profiles_controller_spec.rb b/src/spec/controllers/hardware_profiles_controller_spec.rb index 5d21841..c6b4fe8 100644 --- a/src/spec/controllers/hardware_profiles_controller_spec.rb +++ b/src/spec/controllers/hardware_profiles_controller_spec.rb @@ -1,6 +1,7 @@ require 'spec_helper'
describe HardwareProfilesController do + include Authlogic::TestCase
fixtures :all before(:each) do diff --git a/src/spec/controllers/instance_controller_spec.rb b/src/spec/controllers/instance_controller_spec.rb index 3df886a..e4f253b 100644 --- a/src/spec/controllers/instance_controller_spec.rb +++ b/src/spec/controllers/instance_controller_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper'
describe InstanceController do + include Authlogic::TestCase + fixtures :all before(:each) do @admin_permission = Factory :admin_permission diff --git a/src/spec/controllers/pools_controller_spec.rb b/src/spec/controllers/pools_controller_spec.rb index c9fcc82..dabf38b 100644 --- a/src/spec/controllers/pools_controller_spec.rb +++ b/src/spec/controllers/pools_controller_spec.rb @@ -1,11 +1,21 @@ require 'spec_helper'
describe PoolsController do + include Authlogic::TestCase + fixtures :all before(:each) do @admin_permission = Factory :admin_permission @admin = @admin_permission.user activate_authlogic + + # since default zone is created in migrations + # and not in seed file, create here + unless Zone.default + dz = Zone.new(:name => "default", :description => "default zone") + dz.save! + @default_zone = MetadataObject.set("default_zone", dz) + end end
it "should provide ui to create new pool" do @@ -20,7 +30,7 @@ describe PoolsController do response.should_not be_success end
- it "should provider means to create new pool" do + it "should provide means to create new pool" do UserSession.create(@admin) lambda do post :create, :pool => { :name => 'foopool' } diff --git a/src/spec/controllers/provider_controller_spec.rb b/src/spec/controllers/provider_controller_spec.rb index 096af3d..5ee470a 100644 --- a/src/spec/controllers/provider_controller_spec.rb +++ b/src/spec/controllers/provider_controller_spec.rb @@ -1,6 +1,7 @@ require 'spec_helper'
describe ProviderController do + include Authlogic::TestCase
fixtures :all before(:each) do diff --git a/src/spec/controllers/templates_controller_spec.rb b/src/spec/controllers/templates_controller_spec.rb index 6e23609..21f8047 100644 --- a/src/spec/controllers/templates_controller_spec.rb +++ b/src/spec/controllers/templates_controller_spec.rb @@ -1,6 +1,7 @@ require 'spec_helper'
describe TemplatesController do + include Authlogic::TestCase
fixtures :all before(:each) do diff --git a/src/spec/controllers/user_sessions_controller_spec.rb b/src/spec/controllers/user_sessions_controller_spec.rb index b890b2e..ce2c2c7 100644 --- a/src/spec/controllers/user_sessions_controller_spec.rb +++ b/src/spec/controllers/user_sessions_controller_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper'
describe UserSessionsController do + include Authlogic::TestCase + fixtures :all before(:each) do @tuser = Factory :tuser @@ -8,7 +10,7 @@ describe UserSessionsController do end
it "should call new method" do - route_for(:controller => 'user_sessions', :action => 'new').should == 'login' + {:get => 'login'}.should route_to(:controller => 'user_sessions', :action => 'new') get :new @current_user.should == nil UserSession.find.should == nil diff --git a/src/spec/controllers/users_controller_spec.rb b/src/spec/controllers/users_controller_spec.rb index 92435f4..3234078 100644 --- a/src/spec/controllers/users_controller_spec.rb +++ b/src/spec/controllers/users_controller_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper'
describe UsersController do + include Authlogic::TestCase + fixtures :all before(:each) do @tuser = Factory :tuser @@ -8,26 +10,21 @@ describe UsersController do @admin = @admin_permission.user activate_authlogic
- @allow_self_service_logins = Factory(:metadata_object, :key => "allow_self_service_logins", :value => "true") + @allow_self_service_logins = MetadataObject.set("allow_self_service_logins", "true")
@default_quota = Factory(:unlimited_quota) - @self_service_default_quota = Factory(:metadata_object, :key => "self_service_default_quota", - :value => @default_quota, - :object_type => "Quota") + @self_service_default_quota = MetadataObject.set("self_service_default_quota",@default_quota)
@default_pool = Factory(:pool, :name => "default_pool") - @self_service_default_quota = Factory(:metadata_object, :key => "self_service_default_pool", - :value => @default_pool, - :object_type => "Pool") + @self_service_default_pool = MetadataObject.set("self_service_default_pool",@default_pool)
@default_role = Role.find(:first, :conditions => ['name = ?', 'Instance Creator and User']) - @self_service_default_quota = Factory(:metadata_object, :key => "self_service_default_role", - :value => @default_role, - :object_type => "Role") + @self_service_default_role = MetadataObject.set("self_service_default_role", @default_role) end
it "should call new method" do - route_for(:controller => 'user_sessions', :action => 'new').should == 'login' + { :get => 'login' }.should route_to(:controller => 'user_sessions', + :action => 'new') get :new @current_user.should == nil UserSession.find.should == nil @@ -47,7 +44,7 @@ describe UsersController do :password_confirmation => "testpass" } }.should change{ User.count } user = User.find(:first, :conditions => ['login = ?', "tuser2"]) - response.should redirect_to(dashboard_url) + response.should redirect_to(:controller => :dashboard) end
it "fails to create pool" do @@ -103,10 +100,10 @@ describe UsersController do response.should be_success end
- test "should update user" do + it "should update user" do UserSession.create(@tuser) - put :update, :id => @tuser.id, :user => { }, :save =>'true' - response.should redirect_to(users_path) + put :update, :id => @tuser.id, :user => { }, :commit =>'Save' + response.should redirect_to(root_path) end
# checks whether proper error template is rendered when an exception raises diff --git a/src/spec/models/provider_spec.rb b/src/spec/models/provider_spec.rb index fcec747..16f7bc4 100644 --- a/src/spec/models/provider_spec.rb +++ b/src/spec/models/provider_spec.rb @@ -61,7 +61,8 @@ describe Provider do end
it "should set valid cloud type" do - @client.driver_name = @provider.cloud_type + ct = @provider.cloud_type + @client.stub!(:driver_name).and_return(ct) @provider.cloud_type = nil @provider.set_cloud_type! @provider.should be_valid diff --git a/src/spec/models/registration_service_spec.rb b/src/spec/models/registration_service_spec.rb index 2a97d11..aa514da 100644 --- a/src/spec/models/registration_service_spec.rb +++ b/src/spec/models/registration_service_spec.rb @@ -29,7 +29,7 @@ describe RegistrationService do r.save.should be_false user.errors.empty?.should be_false user.errors.find_all {|attr,msg| - ["email", "password", "password_confirmation"].include?(attr).should be_true + [:email, :password, :password_confirmation].include?(attr).should be_true } end
diff --git a/src/spec/services/registration_service_spec.rb b/src/spec/services/registration_service_spec.rb index 6764715..452b109 100644 --- a/src/spec/services/registration_service_spec.rb +++ b/src/spec/services/registration_service_spec.rb @@ -49,11 +49,11 @@ describe RegistrationService do describe "with transaction" do
before(:all) do - ActiveSupport::TestCase.use_transactional_fixtures = false + RSpec.configuration.use_transactional_fixtures = false end
after(:all) do - ActiveSupport::TestCase.use_transactional_fixtures = true + RSpec.configuration.use_transactional_fixtures = true end
it "doesn't save user if quota save! raise error and return false if validation failed" do diff --git a/src/spec/spec.opts b/src/spec/spec.opts index 391705b..89da67b 100644 --- a/src/spec/spec.opts +++ b/src/spec/spec.opts @@ -1,4 +1,2 @@ --colour --format progress ---loadby mtime ---reverse diff --git a/src/spec/spec_helper.rb b/src/spec/spec_helper.rb index 52e5de0..feda751 100644 --- a/src/spec/spec_helper.rb +++ b/src/spec/spec_helper.rb @@ -1,63 +1,30 @@ -# This file is copied to ~/spec when you run 'ruby script/generate rspec' -# from the project root directory. +# This file is copied to spec/ when you run 'rails generate rspec:install' ENV["RAILS_ENV"] ||= 'test' -require File.expand_path(File.join(File.dirname(__FILE__),'..','config','environment')) -require 'spec/autorun' -require 'spec/rails' +require File.expand_path("../../config/environment", __FILE__) +require 'rspec/rails' require 'authlogic/test_case' require 'timecop'
-# Uncomment the next line to use webrat's matchers -#require 'webrat/integrations/rspec-rails' +# Requires supporting ruby files with custom matchers and macros, etc, +# in spec/support/ and its subdirectories. +Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
-# Requires supporting files with custom matchers and macros, etc, -# in ./support/ and its subdirectories. -Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f} - -Spec::Runner.configure do |config| - # If you're not using ActiveRecord you should remove these - # lines, delete config/database.yml and disable :active_record - # in your config/boot.rb - config.use_transactional_fixtures = true - config.use_instantiated_fixtures = false - config.fixture_path = RAILS_ROOT + '/spec/fixtures/' - - # == Fixtures - # - # You can declare fixtures for each example_group like this: - # describe "...." do - # fixtures :table_a, :table_b - # - # Alternatively, if you prefer to declare them only once, you can - # do so right here. Just uncomment the next line and replace the fixture - # names with your fixtures. - # - # config.global_fixtures = :table_a, :table_b - # - # If you declare global fixtures, be aware that they will be declared - # for all of your examples, even those that don't use them. - # - # You can also declare which fixtures to use (for example fixtures for test/fixtures): - # - # config.fixture_path = RAILS_ROOT + '/spec/fixtures/' - # +RSpec.configure do |config| # == Mock Framework # - # RSpec uses its own mocking framework by default. If you prefer to - # use mocha, flexmock or RR, uncomment the appropriate line: + # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line: # # config.mock_with :mocha # config.mock_with :flexmock # config.mock_with :rr - # - # == Notes - # - # For more information take a look at Spec::Runner::Configuration and Spec::Runner - config.before(:each, :type => :controller) do - #activate_authlogic - @default_zone_metadata = Factory.create(:default_zone_metadata) - end - config.after(:each, :type => :controller) do - #current_user_session.destroy - end + config.mock_with :rspec + + # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures + config.fixture_path = "#{::Rails.root}/spec/fixtures" + + # If you're not using ActiveRecord, or you'd prefer not to run each of your + # examples within a transaction, remove the following line or assign false + # instead of true. + config.use_transactional_fixtures = true + #config.use_instantiated_fixtures = false end diff --git a/src/test/performance/browsing_test.rb b/src/test/performance/browsing_test.rb new file mode 100644 index 0000000..867fc8c --- /dev/null +++ b/src/test/performance/browsing_test.rb @@ -0,0 +1,9 @@ +require 'test_helper' +require 'rails/performance_test_help' + +# Profiling results for each test method are written to tmp/performance. +class BrowsingTest < ActionDispatch::PerformanceTest + def test_homepage + get '/' + end +end
On 11/02/10 - 04:51:38PM, Mohammed Morsi wrote: <snip>
80 files changed, 4233 insertions(+), 2669 deletions(-)
Nice work on a prototype, Mo. This is more painful than I would have hoped; a rough count of our source lines show 11,000 lines of code total, so this is changing more than 50% of it. In your first message, you say:
- All the gems and plugins we depend on seem to have been updated to work against Rails 3. The upstream communities seem to be on the ball regarding this matter
That's good in terms of the code being available, but we still would need to get this stuff packaged up for Fedora. Aside from Rails 3 itself, do you have a feeling as to how many RPMs that are currently in fedora would need to be updated, and how many we would need to add, to get this to work?
On 11/04/2010 09:31 AM, Chris Lalancette wrote:
On 11/02/10 - 04:51:38PM, Mohammed Morsi wrote:
<snip>
80 files changed, 4233 insertions(+), 2669 deletions(-)
Nice work on a prototype, Mo. This is more painful than I would have hoped; a rough count of our source lines show 11,000 lines of code total, so this is changing more than 50% of it. In your first message, you say:
Note that 5081 of those changes are in public/javascripts/prototype.js which rails itself provides.
Rails 2.3.5 ships with prototype.js v1.6.0.3 where as Rails 3 ships with v1.7rc2. All in all, I'm not sure we even use / need this library (since we use jquery) and if not it probably can be removed.
Also alot of the other changes are to the rails framework itself, for example all the scripts located in the scripts/ directory have been replaced with the single 'rails' script. Granted, there were quite a few changes needed to our app to conform to the new api, but these mostly reside in the app/, config/, spec/, and features/ directories (and even then some of the changes in those dirs are for the rails generated stuff as well).
- All the gems and plugins we depend on seem to have been updated to work against Rails 3. The upstream communities seem to be on the ball regarding this matter
That's good in terms of the code being available, but we still would need to get this stuff packaged up for Fedora. Aside from Rails 3 itself, do you have a feeling as to how many RPMs that are currently in fedora would need to be updated, and how many we would need to add, to get this to work?
I just ran through the list of gems installed on the system I was trying this on and came up with the following which might need to be updated in Fedora (I say might as some of these may just be the latest version of the packages available that were automatically pulled in)
* rails, activesupport, activerecord, actionpack, activeresource, actionmailer - 2.3.8 -> 3.0.1 * compass - 0.8.17 -> 0.10.6 * cucumber - 0.9.0 -> 0.9.3 * erubis - 2.6.5 -> 2.6.6 * gherkin - 2.2.4 -> 2.2.9 * haml - 3.0.17 -> 3.0.23 * polyglot - 0.2.5 -> 0.3.1 * rack - 1.1.0 -> 1.2.1 * rack-test - 0.5.4 -> 0.5.6 * rspec - 1.3.0 -> 2.0.1 * simple-navigation - 3.0.0 -> 3.0.2 * sinatra - 1.0 -> 1.1.0 * sqlite3-ruby - 1.2.4 -> 1.3.2 * term-ansicolor - 1.0.3 -> 1.0.5 * thor - 0.13.6 -> 0.14.3 * treetop - 1.3.0 -> 1.4.8
And the following would need to be packaged:
* arel (1.0.1) * autotest (4.4.2) * bundler (1.0.3) * database_cleaner (0.6.0) * factory_girl_rails (1.0) * i18n (0.4.2) * mail (2.2.29) * tilt (1.1) * timecop (0.3.5) * rack-mount (0.6.13) * railties (3.0.1) * rspec-core, rspec-expectations, rspec-mocks, rspec-rails (2.0.1) * tzinfo (0.3.23)
Our explicit dependencies can be found in the Gemfile included in the patch.
-Mo
deltacloud-devel@lists.fedorahosted.org