Jason Guiditta
2009-Jul-20 14:58 UTC
[Ovirt-devel] Upgrade server to run on Rails 2.3.2/F11
Note that one of the 8 patches (#6) will be sent separately in reply to this email, as some of the replaced lines are too long, so git won't let me send the email. However, there is nothing wrong with that patch, and it should be applied in the sequence listed below. Note also that I assume this will be tested on a clean f11 install, rather than an upgrade of an existing ovirt server (since if it was on F11, it was broken anyway). [PATCH server 1/8] Update core app config for Rails 2.3.2 [PATCH server 2/8] test_helper and unit test updates for Rails 2.3.2 [PATCH server 3/8] Update functional tests to work with Rails 2.3.2 [PATCH server 4/8] Switch from old connection style to current. [PATCH server 5/8] No need to track schema.rb and logs right now. [PATCH server 6/8] Update will_paginate to latest version. [PATCH server 7/8] Install render_component plugin. [PATCH server 8/8] Wrapper for mongrel to run with rails 2.3.2
Jason Guiditta
2009-Jul-20 14:58 UTC
[Ovirt-devel] [PATCH server 1/8] Update core app config for Rails 2.3.2
This patch updates app config and makes any
required filename changes to support rails 2.3.2.
Notable changes are:
* application.rb -> application_controller.rb
* cleanup of environment.rb
* new config/initializers dir (this is where much of
the environment.rb stuff went)
* gettext/rails -> gettext_rails
Also note that applying this patch makes ovirt server
no longer run on Fedora 10, as Rails 2.3.2 is not in that
yum repo. If you wish to run the app on F10 after this
upgrade, you can probably still do so with:
gem update rails
but of course this has the potential to cause issues with
yum and gem conflicting.
Signed-off-by: Jason Guiditta <jason.guiditt at gmail.com>
Signed-off-by: Jason Guiditta <jason.guiditta at gmail.com>
---
src/app/controllers/application.rb | 200 --------
src/app/controllers/application_controller.rb | 198 ++++++++
src/config.ru | 7 +
src/config/boot.rb | 11 +-
src/config/environment.rb | 38 +--
src/config/initializers/backtrace_silencers.rb | 7 +
src/config/initializers/inflections.rb | 10 +
src/config/initializers/mime_types.rb | 5 +
src/config/initializers/new_rails_defaults.rb | 19 +
src/config/initializers/session_store.rb | 15 +
src/public/javascripts/controls.js | 136 +++---
src/public/javascripts/dragdrop.js | 175 ++++----
src/public/javascripts/effects.js | 130 +++---
src/public/javascripts/prototype.js | 629 ++++++++++++++----------
14 files changed, 861 insertions(+), 719 deletions(-)
delete mode 100644 src/app/controllers/application.rb
create mode 100644 src/app/controllers/application_controller.rb
create mode 100644 src/config.ru
create mode 100644 src/config/initializers/backtrace_silencers.rb
create mode 100644 src/config/initializers/inflections.rb
create mode 100644 src/config/initializers/mime_types.rb
create mode 100644 src/config/initializers/new_rails_defaults.rb
create mode 100644 src/config/initializers/session_store.rb
diff --git a/src/app/controllers/application.rb
b/src/app/controllers/application.rb
deleted file mode 100644
index e50f71e..0000000
--- a/src/app/controllers/application.rb
+++ /dev/null
@@ -1,200 +0,0 @@
-#
-# Copyright (C) 2008 Red Hat, Inc.
-# Written by Scott Seago <sseago at 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.
-
-# Filters added to this controller apply to all controllers in the application.
-# Likewise, all the methods added will be available for all controllers.
-
-
-class ApplicationController < ActionController::Base
- # FIXME: once all controller classes include this, remove here
- include ApplicationService
-
- # Pick a unique cookie name to distinguish our session data from others'
- session :session_key => '_ovirt_session_id'
- init_gettext "ovirt"
- layout :choose_layout
-
- before_filter :is_logged_in, :get_help_section
-
- # General error handlers, must be in order from least specific
- # to most specific
- rescue_from Exception, :with => :handle_general_error
- rescue_from PermissionError, :with => :handle_perm_error
- rescue_from ActionError, :with => :handle_action_error
- rescue_from PartialSuccessError, :with => :handle_partial_success_error
-
- def choose_layout
- if(params[:component_layout])
- return (ENV["RAILS_ENV"] !=
"production")?'components/' <<
params[:component_layout]:'redux'
- end
- return 'redux'
- end
-
- def is_logged_in
- redirect_to(:controller => "/login", :action =>
"login") unless get_login_user
- end
-
- def get_help_section
- help = HelpSection.find(:first, :conditions => [ "controller = ?
AND action = ?", controller_name, action_name ])
- @help_section = help ? help.section : ""
- if @help_section.index('#')
- help_sections = @help_section.split('#')
- @help_section = help_sections[0]
- @anchor = help_sections[1]
- else
- @help_section = @help_section
- @anchor = ""
- end
- end
-
- def get_login_user
- (ENV["RAILS_ENV"] == "production") ? session[:user] :
"ovirtadmin"
- end
-
- protected
- # permissions checking
-
- def handle_perm_error(error)
- handle_error(:error => error, :status => :forbidden,
- :title => "Access denied")
- end
-
- def handle_partial_success_error(error)
- failures_arr = error.failures.collect do |resource, reason|
- if resource.respond_to?(:display_name)
- resource.display_name + ": " + reason
- else
- reason
- end
- end
- @successes = error.successes
- @failures = error.failures
- handle_error(:error => error, :status => :ok,
- :message => error.message + ": " +
failures_arr.join(", "),
- :title => "Some actions failed")
- end
-
- def handle_action_error(error)
- handle_error(:error => error, :status => :conflict,
- :title => "Action Error")
- end
-
- def handle_general_error(error)
- flash[:errmsg] = error.message
- handle_error(:error => error, :status => :internal_server_error,
- :title => "Internal Server Error")
- end
-
- def handle_error(hash)
- log_error(hash[:error]) if hash[:error]
- msg = hash[:message] || hash[:error].message
- title = hash[:title] || "Internal Server Error"
- status = hash[:status] || :internal_server_error
- respond_to do |format|
- format.html { html_error_page(title, msg) }
- format.json { render :json => json_error_hash(msg, status) }
- format.xml { render :xml => xml_errors(msg), :status => status }
- end
- end
-
- def html_error_page(title, msg)
- @title = title
- @errmsg = msg
- @ajax = params[:ajax]
- @nolayout = params[:nolayout]
- if @layout
- render :layout => @layout
- elsif @ajax
- render :template => 'layouts/popup-error', :layout =>
'tabs-and-content'
- elsif @nolayout
- render :template => 'layouts/popup-error', :layout =>
'help-and-content'
- else
- render :template => 'layouts/popup-error', :layout =>
'popup'
- end
- end
-
- # don't define find_opts for array inputs
- def json_hash(full_items, attributes, arg_list=[], find_opts={},
id_method=:id)
- page = params[:page].to_i
- paginate_opts = {:page => page,
- :order => "#{params[:sortname]}
#{params[:sortorder]}",
- :per_page => params[:rp]}
- arg_list << find_opts.merge(paginate_opts)
- item_list = full_items.paginate(*arg_list)
- json_hash = {}
- json_hash[:page] = page
- json_hash[:total] = item_list.total_entries
- json_hash[:rows] = item_list.collect do |item|
- item_hash = {}
- item_hash[:id] = item.send(id_method)
- item_hash[:cell] = attributes.collect do |attr|
- if attr.is_a? Array
- value = item
- attr.each { |attr_item| value = (value.nil? ? nil :
value.send(attr_item))}
- value
- else
- item.send(attr)
- end
- end
- item_hash
- end
- json_hash
- end
-
- # json_list is a helper method used to format data for paginated flexigrid
tables
- #
- # FIXME: what is the intent of this comment? don't define find_opts for
array inputs
- def json_list(full_items, attributes, arg_list=[], find_opts={},
id_method=:id)
- render :json => json_hash(full_items, attributes, arg_list, find_opts,
id_method).to_json
- end
-
- private
- def json_error_hash(msg, status)
- json = {}
- json[:success] = (status == :ok)
- json.merge!(instance_errors)
- # There's a potential issue here: if we add :errors for an object
- # that the view won't generate inline error messages for, the user
- # won't get any indication what the error is. But if we set :alert
- # unconditionally, the user will get validation errors twice: once
- # inline in the form, and once in the flash
- json[:alert] = msg unless json[:errors]
- return json
- end
-
- def xml_errors(msg)
- xml = {}
- xml[:message] = msg
- xml.merge!(instance_errors)
- return xml
- end
-
- def instance_errors
- hash = {}
- instance_variables.each do |ivar|
- val = instance_variable_get(ivar)
- if val && val.respond_to?(:errors) && val.errors.size
> 0
- hash[:object] = ivar[1, ivar.size]
- hash[:errors] ||= []
- hash[:errors] += val.errors.localize_error_messages.to_a
- end
- end
- return hash
- end
-end
diff --git a/src/app/controllers/application_controller.rb
b/src/app/controllers/application_controller.rb
new file mode 100644
index 0000000..5ce625a
--- /dev/null
+++ b/src/app/controllers/application_controller.rb
@@ -0,0 +1,198 @@
+#
+# Copyright (C) 2008 Red Hat, Inc.
+# Written by Scott Seago <sseago at 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.
+
+# Filters added to this controller apply to all controllers in the application.
+# Likewise, all the methods added will be available for all controllers.
+
+
+class ApplicationController < ActionController::Base
+ # FIXME: once all controller classes include this, remove here
+ include ApplicationService
+
+ init_gettext "ovirt"
+ layout :choose_layout
+
+ before_filter :is_logged_in, :get_help_section
+
+ # General error handlers, must be in order from least specific
+ # to most specific
+ rescue_from Exception, :with => :handle_general_error
+ rescue_from PermissionError, :with => :handle_perm_error
+ rescue_from ActionError, :with => :handle_action_error
+ rescue_from PartialSuccessError, :with => :handle_partial_success_error
+
+ def choose_layout
+ if(params[:component_layout])
+ return (ENV["RAILS_ENV"] !=
"production")?'components/' <<
params[:component_layout]:'redux'
+ end
+ return 'redux'
+ end
+
+ def is_logged_in
+ redirect_to(:controller => "/login", :action =>
"login") unless get_login_user
+ end
+
+ def get_help_section
+ help = HelpSection.find(:first, :conditions => [ "controller = ?
AND action = ?", controller_name, action_name ])
+ @help_section = help ? help.section : ""
+ if @help_section.index('#')
+ help_sections = @help_section.split('#')
+ @help_section = help_sections[0]
+ @anchor = help_sections[1]
+ else
+ @help_section = @help_section
+ @anchor = ""
+ end
+ end
+
+ def get_login_user
+ (ENV["RAILS_ENV"] == "production") ? session[:user] :
"ovirtadmin"
+ end
+
+ protected
+ # permissions checking
+
+ def handle_perm_error(error)
+ handle_error(:error => error, :status => :forbidden,
+ :title => "Access denied")
+ end
+
+ def handle_partial_success_error(error)
+ failures_arr = error.failures.collect do |resource, reason|
+ if resource.respond_to?(:display_name)
+ resource.display_name + ": " + reason
+ else
+ reason
+ end
+ end
+ @successes = error.successes
+ @failures = error.failures
+ handle_error(:error => error, :status => :ok,
+ :message => error.message + ": " +
failures_arr.join(", "),
+ :title => "Some actions failed")
+ end
+
+ def handle_action_error(error)
+ handle_error(:error => error, :status => :conflict,
+ :title => "Action Error")
+ end
+
+ def handle_general_error(error)
+ flash[:errmsg] = error.message
+ handle_error(:error => error, :status => :internal_server_error,
+ :title => "Internal Server Error")
+ end
+
+ def handle_error(hash)
+ log_error(hash[:error]) if hash[:error]
+ msg = hash[:message] || hash[:error].message
+ title = hash[:title] || "Internal Server Error"
+ status = hash[:status] || :internal_server_error
+ respond_to do |format|
+ format.html { html_error_page(title, msg) }
+ format.json { render :json => json_error_hash(msg, status) }
+ format.xml { render :xml => xml_errors(msg), :status => status }
+ end
+ end
+
+ def html_error_page(title, msg)
+ @title = title
+ @errmsg = msg
+ @ajax = params[:ajax]
+ @nolayout = params[:nolayout]
+ if @layout
+ render :layout => @layout
+ elsif @ajax
+ render :template => 'layouts/popup-error', :layout =>
'tabs-and-content'
+ elsif @nolayout
+ render :template => 'layouts/popup-error', :layout =>
'help-and-content'
+ else
+ render :template => 'layouts/popup-error', :layout =>
'popup'
+ end
+ end
+
+ # don't define find_opts for array inputs
+ def json_hash(full_items, attributes, arg_list=[], find_opts={},
id_method=:id)
+ page = params[:page].to_i
+ paginate_opts = {:page => page,
+ :order => "#{params[:sortname]}
#{params[:sortorder]}",
+ :per_page => params[:rp]}
+ arg_list << find_opts.merge(paginate_opts)
+ item_list = full_items.paginate(*arg_list)
+ json_hash = {}
+ json_hash[:page] = page
+ json_hash[:total] = item_list.total_entries
+ json_hash[:rows] = item_list.collect do |item|
+ item_hash = {}
+ item_hash[:id] = item.send(id_method)
+ item_hash[:cell] = attributes.collect do |attr|
+ if attr.is_a? Array
+ value = item
+ attr.each { |attr_item| value = (value.nil? ? nil :
value.send(attr_item))}
+ value
+ else
+ item.send(attr)
+ end
+ end
+ item_hash
+ end
+ json_hash
+ end
+
+ # json_list is a helper method used to format data for paginated flexigrid
tables
+ #
+ # FIXME: what is the intent of this comment? don't define find_opts for
array inputs
+ def json_list(full_items, attributes, arg_list=[], find_opts={},
id_method=:id)
+ render :json => json_hash(full_items, attributes, arg_list, find_opts,
id_method).to_json
+ end
+
+ private
+ def json_error_hash(msg, status)
+ json = {}
+ json[:success] = (status == :ok)
+ json.merge!(instance_errors)
+ # There's a potential issue here: if we add :errors for an object
+ # that the view won't generate inline error messages for, the user
+ # won't get any indication what the error is. But if we set :alert
+ # unconditionally, the user will get validation errors twice: once
+ # inline in the form, and once in the flash
+ json[:alert] = msg unless json[:errors]
+ return json
+ end
+
+ def xml_errors(msg)
+ xml = {}
+ xml[:message] = msg
+ xml.merge!(instance_errors)
+ return xml
+ end
+
+ def instance_errors
+ hash = {}
+ instance_variables.each do |ivar|
+ val = instance_variable_get(ivar)
+ if val && val.respond_to?(:errors) && val.errors.size
> 0
+ hash[:object] = ivar[1, ivar.size]
+ hash[:errors] ||= []
+ hash[:errors] += val.errors.localize_error_messages.to_a
+ end
+ end
+ return hash
+ end
+end
diff --git a/src/config.ru b/src/config.ru
new file mode 100644
index 0000000..acbfe4e
--- /dev/null
+++ b/src/config.ru
@@ -0,0 +1,7 @@
+# Rack Dispatcher
+
+# Require your environment file to bootstrap Rails
+require File.dirname(__FILE__) + '/config/environment'
+
+# Dispatch the request
+run ActionController::Dispatcher.new
diff --git a/src/config/boot.rb b/src/config/boot.rb
index cd21fb9..0ad0f78 100644
--- a/src/config/boot.rb
+++ b/src/config/boot.rb
@@ -44,6 +44,7 @@ module Rails
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
@@ -67,7 +68,7 @@ module Rails
class << self
def rubygems_version
- Gem::RubyGemsVersion if defined? Gem::RubyGemsVersion
+ Gem::RubyGemsVersion rescue nil
end
def gem_version
@@ -82,14 +83,14 @@ module Rails
def load_rubygems
require 'rubygems'
-
- unless rubygems_version >= '0.9.4'
- $stderr.puts %(Rails requires RubyGems >= 0.9.4 (you have
#{rubygems_version}). Please `gem update --system` and try again.)
+ min_version = '1.3.1'
+ 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 %(Rails requires RubyGems >= 0.9.4. Please install
RubyGems and try again: http://rubygems.rubyforge.org)
+ $stderr.puts %Q(Rails requires RubyGems >= #{min_version}. Please
install RubyGems and try again: http://rubygems.rubyforge.org)
exit 1
end
diff --git a/src/config/environment.rb b/src/config/environment.rb
index 98a2fbb..9d9a66d 100644
--- a/src/config/environment.rb
+++ b/src/config/environment.rb
@@ -19,9 +19,8 @@
# Be sure to restart your web server when you modify this file.
-# Uncomment below to force Rails into production mode when
-# you don't control web/app server and can't set it the proper way
-# ENV['RAILS_ENV'] ||= 'production'
+# 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')
@@ -42,7 +41,7 @@ Rails::Initializer.run do |config|
# config.gem "hpricot", :version => '0.6', :source =>
"http://code.whytheluckystiff.net"
# config.gem "aws-s3", :lib => "aws/s3"
config.gem "cobbler"
- config.gem "gettext", :lib => "gettext/rails"
+ config.gem "gettext", :lib => "gettext_rails"
# Only load the plugins named here, in the order given. By default, all
plugins
# in vendor/plugins are loaded in alphabetical order.
@@ -61,20 +60,6 @@ Rails::Initializer.run do |config|
# Run "rake -D time" for a list of tasks for finding time zone
names. Uncomment to use default local time.
config.time_zone = 'UTC'
- # Your secret key for verifying cookie session data integrity.
- # If you change this key, all old sessions will become invalid!
- # Make sure the secret is at least 30 characters and all random,
- # no regular words or you'll be exposed to dictionary attacks.
- config.action_controller.session = {
- :session_key => "_ovirt_session_id",
- :secret => "a covert ovirt phrase or some such"
- }
-
- # 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")
- config.action_controller.session_store = :active_record_store
-
# 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
@@ -83,17 +68,8 @@ Rails::Initializer.run do |config|
# Activate observers that should always be running
# config.active_record.observers = :cacher, :garbage_collector
config.active_record.observers = :host_observer, :vm_observer
-end
-# Add new inflection rules using the following format
-# (all these examples are active by default):
-# Inflector.inflections do |inflect|
-# inflect.plural /^(ox)$/i, '\1en'
-# inflect.singular /^(ox)en/i, '\1'
-# inflect.irregular 'person', 'people'
-# inflect.uncountable %w( fish sheep )
-# end
-
-# Add new mime types for use in respond_to blocks:
-# Mime::Type.register "text/richtext", :rtf
-# Mime::Type.register "application/x-mobile", :mobile
+ # 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
+end
diff --git a/src/config/initializers/backtrace_silencers.rb
b/src/config/initializers/backtrace_silencers.rb
new file mode 100644
index 0000000..c2169ed
--- /dev/null
+++ b/src/config/initializers/backtrace_silencers.rb
@@ -0,0 +1,7 @@
+# Be sure to restart your server when you modify this file.
+
+# You can add backtrace silencers for libraries that you're using but
don't wish to see in your backtraces.
+# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
+
+# You can also remove all the silencers if you're trying do debug a problem
that might steem from framework code.
+# Rails.backtrace_cleaner.remove_silencers!
\ No newline at end of file
diff --git a/src/config/initializers/inflections.rb
b/src/config/initializers/inflections.rb
new file mode 100644
index 0000000..9e8b013
--- /dev/null
+++ b/src/config/initializers/inflections.rb
@@ -0,0 +1,10 @@
+# Be sure to restart your server when you modify this file.
+
+# Add new inflection rules using the following format
+# (all these examples are active by default):
+# ActiveSupport::Inflector.inflections do |inflect|
+# inflect.plural /^(ox)$/i, '\1en'
+# inflect.singular /^(ox)en/i, '\1'
+# inflect.irregular 'person', 'people'
+# inflect.uncountable %w( fish sheep )
+# end
diff --git a/src/config/initializers/mime_types.rb
b/src/config/initializers/mime_types.rb
new file mode 100644
index 0000000..72aca7e
--- /dev/null
+++ b/src/config/initializers/mime_types.rb
@@ -0,0 +1,5 @@
+# Be sure to restart your server when you modify this file.
+
+# Add new mime types for use in respond_to blocks:
+# Mime::Type.register "text/richtext", :rtf
+# Mime::Type.register_alias "text/html", :iphone
diff --git a/src/config/initializers/new_rails_defaults.rb
b/src/config/initializers/new_rails_defaults.rb
new file mode 100644
index 0000000..8ec3186
--- /dev/null
+++ b/src/config/initializers/new_rails_defaults.rb
@@ -0,0 +1,19 @@
+# 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/session_store.rb
b/src/config/initializers/session_store.rb
new file mode 100644
index 0000000..64dbf51
--- /dev/null
+++ b/src/config/initializers/session_store.rb
@@ -0,0 +1,15 @@
+# Be sure to restart your server when you modify this file.
+
+# Your secret key for verifying cookie session data integrity.
+# If you change this key, all old sessions will become invalid!
+# Make sure the secret is at least 30 characters and all random,
+# no regular words or you'll be exposed to dictionary attacks.
+ActionController::Base.session = {
+ :key => '_rails23-app_session',
+ :secret =>
'41713a6b4a92b5b7af55314d2ef6fc499a177269ea91b9fdaa7d15c42e1234b70b32f52278ae26b774b38dbdfeb7d078585d10f643e81b6615d32410f192f1de'
+}
+
+# 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
diff --git a/src/public/javascripts/controls.js
b/src/public/javascripts/controls.js
index 1de3b29..ca29aef 100644
--- a/src/public/javascripts/controls.js
+++ b/src/public/javascripts/controls.js
@@ -1,22 +1,22 @@
// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us,
http://mir.aculo.us)
-// (c) 2005-2007 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
-// (c) 2005-2007 Jon Tirsen (http://www.tirsen.com)
+// (c) 2005-2008 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
+// (c) 2005-2008 Jon Tirsen (http://www.tirsen.com)
// Contributors:
// Richard Livsey
// Rahul Bhargava
// Rob Wills
-//
+//
// script.aculo.us is freely distributable under the terms of an MIT-style
license.
// For details, see the script.aculo.us web site: http://script.aculo.us/
-// Autocompleter.Base handles all the autocompletion functionality
+// Autocompleter.Base handles all the autocompletion functionality
// that's independent of the data source for autocompletion. This
// includes drawing the autocompletion menu, observing keyboard
// and mouse events, and similar.
//
-// Specific autocompleters need to provide, at the very least,
+// Specific autocompleters need to provide, at the very least,
// a getUpdatedChoices function that will be invoked every time
-// the text inside the monitored textbox changes. This method
+// the text inside the monitored textbox changes. This method
// should get the text for which to provide autocompletion by
// invoking this.getToken(), NOT by directly accessing
// this.element.value. This is to allow incremental tokenized
@@ -30,23 +30,23 @@
// will incrementally autocomplete with a comma as the token.
// Additionally, ',' in the above example can be replaced with
// a token array, e.g. { tokens: [',', '\n'] } which
-// enables autocompletion on multiple tokens. This is most
-// useful when one of the tokens is \n (a newline), as it
+// enables autocompletion on multiple tokens. This is most
+// useful when one of the tokens is \n (a newline), as it
// allows smart autocompletion after linebreaks.
if(typeof Effect == 'undefined')
throw("controls.js requires including script.aculo.us' effects.js
library");
-var Autocompleter = { }
+var Autocompleter = { };
Autocompleter.Base = Class.create({
baseInitialize: function(element, update, options) {
- element = $(element)
+ element = $(element);
this.element = element;
- this.update = $(update);
- this.hasFocus = false;
- this.changed = false;
- this.active = false;
- this.index = 0;
+ this.update = $(update);
+ this.hasFocus = false;
+ this.changed = false;
+ this.active = false;
+ this.index = 0;
this.entryCount = 0;
this.oldElementValue = this.element.value;
@@ -59,28 +59,28 @@ Autocompleter.Base = Class.create({
this.options.tokens = this.options.tokens || [];
this.options.frequency = this.options.frequency || 0.4;
this.options.minChars = this.options.minChars || 1;
- this.options.onShow = this.options.onShow ||
- function(element, update){
+ this.options.onShow = this.options.onShow ||
+ function(element, update){
if(!update.style.position || update.style.position=='absolute')
{
update.style.position = 'absolute';
Position.clone(element, update, {
- setHeight: false,
+ setHeight: false,
offsetTop: element.offsetHeight
});
}
Effect.Appear(update,{duration:0.15});
};
- this.options.onHide = this.options.onHide ||
+ this.options.onHide = this.options.onHide ||
function(element, update){ new Effect.Fade(update,{duration:0.15}) };
- if(typeof(this.options.tokens) == 'string')
+ if(typeof(this.options.tokens) == 'string')
this.options.tokens = new Array(this.options.tokens);
// Force carriage returns as token delimiters anyway
if (!this.options.tokens.include('\n'))
this.options.tokens.push('\n');
this.observer = null;
-
+
this.element.setAttribute('autocomplete','off');
Element.hide(this.update);
@@ -91,10 +91,10 @@ Autocompleter.Base = Class.create({
show: function() {
if(Element.getStyle(this.update, 'display')=='none')
this.options.onShow(this.element, this.update);
- if(!this.iefix &&
+ if(!this.iefix &&
(Prototype.Browser.IE) &&
(Element.getStyle(this.update, 'position')=='absolute'))
{
- new Insertion.After(this.update,
+ new Insertion.After(this.update,
'<iframe id="' + this.update.id + '_iefix"
'+
'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);"
' +
'src="javascript:false;" frameborder="0"
scrolling="no"></iframe>');
@@ -102,7 +102,7 @@ Autocompleter.Base = Class.create({
}
if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
},
-
+
fixIEOverlapping: function() {
Position.clone(this.update, this.iefix,
{setTop:(!this.update.style.height)});
this.iefix.style.zIndex = 1;
@@ -150,15 +150,15 @@ Autocompleter.Base = Class.create({
Event.stop(event);
return;
}
- else
- if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||
+ else
+ if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||
(Prototype.Browser.WebKit > 0 && event.keyCode == 0))
return;
this.changed = true;
this.hasFocus = true;
if(this.observer) clearTimeout(this.observer);
- this.observer =
+ this.observer setTimeout(this.onObserverEvent.bind(this),
this.options.frequency*1000);
},
@@ -170,35 +170,35 @@ Autocompleter.Base = Class.create({
onHover: function(event) {
var element = Event.findElement(event, 'LI');
- if(this.index != element.autocompleteIndex)
+ if(this.index != element.autocompleteIndex)
{
this.index = element.autocompleteIndex;
this.render();
}
Event.stop(event);
},
-
+
onClick: function(event) {
var element = Event.findElement(event, 'LI');
this.index = element.autocompleteIndex;
this.selectEntry();
this.hide();
},
-
+
onBlur: function(event) {
// needed to make click events working
setTimeout(this.hide.bind(this), 250);
this.hasFocus = false;
- this.active = false;
- },
-
+ this.active = false;
+ },
+
render: function() {
if(this.entryCount > 0) {
for (var i = 0; i < this.entryCount; i++)
- this.index==i ?
- Element.addClassName(this.getEntry(i),"selected") :
+ this.index==i ?
+ Element.addClassName(this.getEntry(i),"selected") :
Element.removeClassName(this.getEntry(i),"selected");
- if(this.hasFocus) {
+ if(this.hasFocus) {
this.show();
this.active = true;
}
@@ -207,27 +207,27 @@ Autocompleter.Base = Class.create({
this.hide();
}
},
-
+
markPrevious: function() {
- if(this.index > 0) this.index--
+ if(this.index > 0) this.index--;
else this.index = this.entryCount-1;
this.getEntry(this.index).scrollIntoView(true);
},
-
+
markNext: function() {
- if(this.index < this.entryCount-1) this.index++
+ if(this.index < this.entryCount-1) this.index++;
else this.index = 0;
this.getEntry(this.index).scrollIntoView(false);
},
-
+
getEntry: function(index) {
return this.update.firstChild.childNodes[index];
},
-
+
getCurrentEntry: function() {
return this.getEntry(this.index);
},
-
+
selectEntry: function() {
this.active = false;
this.updateElement(this.getCurrentEntry());
@@ -244,7 +244,7 @@ Autocompleter.Base = Class.create({
if(nodes.length>0) value = Element.collectTextNodes(nodes[0],
this.options.select);
} else
value = Element.collectTextNodesIgnoreClass(selectedElement,
'informal');
-
+
var bounds = this.getTokenBounds();
if (bounds[0] != -1) {
var newValue = this.element.value.substr(0, bounds[0]);
@@ -257,7 +257,7 @@ Autocompleter.Base = Class.create({
}
this.oldElementValue = this.element.value;
this.element.focus();
-
+
if (this.options.afterUpdateElement)
this.options.afterUpdateElement(this.element, selectedElement);
},
@@ -269,20 +269,20 @@ Autocompleter.Base = Class.create({
Element.cleanWhitespace(this.update.down());
if(this.update.firstChild && this.update.down().childNodes) {
- this.entryCount =
+ this.entryCount this.update.down().childNodes.length;
for (var i = 0; i < this.entryCount; i++) {
var entry = this.getEntry(i);
entry.autocompleteIndex = i;
this.addObservers(entry);
}
- } else {
+ } else {
this.entryCount = 0;
}
this.stopIndicator();
this.index = 0;
-
+
if(this.entryCount==1 && this.options.autoSelect) {
this.selectEntry();
this.hide();
@@ -298,7 +298,7 @@ Autocompleter.Base = Class.create({
},
onObserverEvent: function() {
- this.changed = false;
+ this.changed = false;
this.tokenBounds = null;
if(this.getToken().length>=this.options.minChars) {
this.getUpdatedChoices();
@@ -358,7 +358,7 @@ Ajax.Autocompleter = Class.create(Autocompleter.Base, {
this.options.parameters = this.options.callback ?
this.options.callback(this.element, entry) : entry;
- if(this.options.defaultParams)
+ if(this.options.defaultParams)
this.options.parameters += '&' + this.options.defaultParams;
new Ajax.Request(this.url, this.options);
@@ -382,7 +382,7 @@ Ajax.Autocompleter = Class.create(Autocompleter.Base, {
// - choices - How many autocompletion choices to offer
//
// - partialSearch - If false, the autocompleter will match entered
-// text only at the beginning of strings in the
+// text only at the beginning of strings in the
// autocomplete array. Defaults to true, which will
// match text at the beginning of any *word* in the
// strings in the autocomplete array. If you want to
@@ -399,7 +399,7 @@ Ajax.Autocompleter = Class.create(Autocompleter.Base, {
// - ignoreCase - Whether to ignore case when autocompleting.
// Defaults to true.
//
-// It's possible to pass in a custom function as the 'selector'
+// It's possible to pass in a custom function as the 'selector'
// option, if you prefer to write your own autocompletion logic.
// In that case, the other options above will not apply unless
// you support them.
@@ -427,20 +427,20 @@ Autocompleter.Local = Class.create(Autocompleter.Base, {
var entry = instance.getToken();
var count = 0;
- for (var i = 0; i < instance.options.array.length &&
- ret.length < instance.options.choices ; i++) {
+ for (var i = 0; i < instance.options.array.length &&
+ ret.length < instance.options.choices ; i++) {
var elem = instance.options.array[i];
- var foundPos = instance.options.ignoreCase ?
- elem.toLowerCase().indexOf(entry.toLowerCase()) :
+ var foundPos = instance.options.ignoreCase ?
+ elem.toLowerCase().indexOf(entry.toLowerCase()) :
elem.indexOf(entry);
while (foundPos != -1) {
- if (foundPos == 0 && elem.length != entry.length) {
- ret.push("<li><strong>" + elem.substr(0,
entry.length) + "</strong>" +
+ if (foundPos == 0 && elem.length != entry.length) {
+ ret.push("<li><strong>" + elem.substr(0,
entry.length) + "</strong>" +
elem.substr(entry.length) + "</li>");
break;
- } else if (entry.length >= instance.options.partialChars
&&
+ } else if (entry.length >= instance.options.partialChars
&&
instance.options.partialSearch && foundPos != -1) {
if (instance.options.fullSearch ||
/\s/.test(elem.substr(foundPos-1,1))) {
partial.push("<li>" + elem.substr(0, foundPos)
+ "<strong>" +
@@ -450,14 +450,14 @@ Autocompleter.Local = Class.create(Autocompleter.Base, {
}
}
- foundPos = instance.options.ignoreCase ?
- elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) :
+ foundPos = instance.options.ignoreCase ?
+ elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) :
elem.indexOf(entry, foundPos + 1);
}
}
if (partial.length)
- ret = ret.concat(partial.slice(0, instance.options.choices -
ret.length))
+ ret = ret.concat(partial.slice(0, instance.options.choices -
ret.length));
return "<ul>" + ret.join('') +
"</ul>";
}
}, options || { });
@@ -474,7 +474,7 @@ Field.scrollFreeActivate = function(field) {
setTimeout(function() {
Field.activate(field);
}, 1);
-}
+};
Ajax.InPlaceEditor = Class.create({
initialize: function(element, url, options) {
@@ -604,7 +604,7 @@ Ajax.InPlaceEditor = Class.create({
this.triggerCallback('onEnterHover');
},
getText: function() {
- return this.element.innerHTML;
+ return this.element.innerHTML.unescapeHTML();
},
handleAJAXFailure: function(transport) {
this.triggerCallback('onFailure', transport);
@@ -780,7 +780,7 @@ Ajax.InPlaceCollectionEditor =
Class.create(Ajax.InPlaceEditor, {
onSuccess: function(transport) {
var js = transport.responseText.strip();
if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check
- throw 'Server returned an invalid collection
representation.';
+ throw('Server returned an invalid collection
representation.');
this._collection = eval(js);
this.checkForExternalText();
}.bind(this),
@@ -937,7 +937,7 @@ Ajax.InPlaceCollectionEditor.DefaultOptions = {
loadingCollectionText: 'Loading options...'
};
-// Delayed observer, like Form.Element.Observer,
+// Delayed observer, like Form.Element.Observer,
// but waits for delay after last key input
// Ideal for live-search fields
@@ -947,7 +947,7 @@ Form.Element.DelayedObserver = Class.create({
this.element = $(element);
this.callback = callback;
this.timer = null;
- this.lastValue = $F(this.element);
+ this.lastValue = $F(this.element);
Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
},
delayedListener: function(event) {
@@ -960,4 +960,4 @@ Form.Element.DelayedObserver = Class.create({
this.timer = null;
this.callback(this.element, $F(this.element));
}
-});
+});
\ No newline at end of file
diff --git a/src/public/javascripts/dragdrop.js
b/src/public/javascripts/dragdrop.js
index e2e7d4a..07229f9 100644
--- a/src/public/javascripts/dragdrop.js
+++ b/src/public/javascripts/dragdrop.js
@@ -1,6 +1,6 @@
// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us,
http://mir.aculo.us)
-// (c) 2005-2007 Sammi Williams (http://www.oriontransfer.co.nz,
sammi at oriontransfer.co.nz)
-//
+// (c) 2005-2008 Sammi Williams (http://www.oriontransfer.co.nz,
sammi at oriontransfer.co.nz)
+//
// script.aculo.us is freely distributable under the terms of an MIT-style
license.
// For details, see the script.aculo.us web site: http://script.aculo.us/
@@ -32,7 +32,7 @@ var Droppables = {
options._containers.push($(containment));
}
}
-
+
if(options.accept) options.accept = [options.accept].flatten();
Element.makePositioned(element); // fix IE
@@ -40,34 +40,34 @@ var Droppables = {
this.drops.push(options);
},
-
+
findDeepestChild: function(drops) {
deepest = drops[0];
-
+
for (i = 1; i < drops.length; ++i)
if (Element.isParent(drops[i].element, deepest.element))
deepest = drops[i];
-
+
return deepest;
},
isContained: function(element, drop) {
var containmentNode;
if(drop.tree) {
- containmentNode = element.treeNode;
+ containmentNode = element.treeNode;
} else {
containmentNode = element.parentNode;
}
return drop._containers.detect(function(c) { return containmentNode == c
});
},
-
+
isAffected: function(point, element, drop) {
return (
(drop.element!=element) &&
((!drop._containers) ||
this.isContained(element, drop)) &&
((!drop.accept) ||
- (Element.classNames(element).detect(
+ (Element.classNames(element).detect(
function(v) { return drop.accept.include(v) } ) )) &&
Position.within(drop.element, point[0], point[1]) );
},
@@ -87,12 +87,12 @@ var Droppables = {
show: function(point, element) {
if(!this.drops.length) return;
var drop, affected = [];
-
+
this.drops.each( function(drop) {
if(Droppables.isAffected(point, element, drop))
affected.push(drop);
});
-
+
if(affected.length>0)
drop = Droppables.findDeepestChild(affected);
@@ -101,7 +101,7 @@ var Droppables = {
Position.within(drop.element, point[0], point[1]);
if(drop.onHover)
drop.onHover(element, drop.element, Position.overlap(drop.overlap,
drop.element));
-
+
if (drop != this.last_active) Droppables.activate(drop);
}
},
@@ -121,25 +121,25 @@ var Droppables = {
if(this.last_active)
this.deactivate(this.last_active);
}
-}
+};
var Draggables = {
drags: [],
observers: [],
-
+
register: function(draggable) {
if(this.drags.length == 0) {
this.eventMouseUp = this.endDrag.bindAsEventListener(this);
this.eventMouseMove = this.updateDrag.bindAsEventListener(this);
this.eventKeypress = this.keyPress.bindAsEventListener(this);
-
+
Event.observe(document, "mouseup", this.eventMouseUp);
Event.observe(document, "mousemove", this.eventMouseMove);
Event.observe(document, "keypress", this.eventKeypress);
}
this.drags.push(draggable);
},
-
+
unregister: function(draggable) {
this.drags = this.drags.reject(function(d) { return d==draggable });
if(this.drags.length == 0) {
@@ -148,24 +148,24 @@ var Draggables = {
Event.stopObserving(document, "keypress", this.eventKeypress);
}
},
-
+
activate: function(draggable) {
- if(draggable.options.delay) {
- this._timeout = setTimeout(function() {
- Draggables._timeout = null;
- window.focus();
- Draggables.activeDraggable = draggable;
- }.bind(this), draggable.options.delay);
+ if(draggable.options.delay) {
+ this._timeout = setTimeout(function() {
+ Draggables._timeout = null;
+ window.focus();
+ Draggables.activeDraggable = draggable;
+ }.bind(this), draggable.options.delay);
} else {
window.focus(); // allows keypress events if window isn't currently
focused, fails for Safari
this.activeDraggable = draggable;
}
},
-
+
deactivate: function() {
this.activeDraggable = null;
},
-
+
updateDrag: function(event) {
if(!this.activeDraggable) return;
var pointer = [Event.pointerX(event), Event.pointerY(event)];
@@ -173,36 +173,36 @@ var Draggables = {
// the same coordinates, prevent needless redrawing (moz bug?)
if(this._lastPointer && (this._lastPointer.inspect() ==
pointer.inspect())) return;
this._lastPointer = pointer;
-
+
this.activeDraggable.updateDrag(event, pointer);
},
-
+
endDrag: function(event) {
- if(this._timeout) {
- clearTimeout(this._timeout);
- this._timeout = null;
+ if(this._timeout) {
+ clearTimeout(this._timeout);
+ this._timeout = null;
}
if(!this.activeDraggable) return;
this._lastPointer = null;
this.activeDraggable.endDrag(event);
this.activeDraggable = null;
},
-
+
keyPress: function(event) {
if(this.activeDraggable)
this.activeDraggable.keyPress(event);
},
-
+
addObserver: function(observer) {
this.observers.push(observer);
this._cacheObserverCallbacks();
},
-
+
removeObserver: function(element) { // element instead of observer fixes mem
leaks
this.observers = this.observers.reject( function(o) { return
o.element==element });
this._cacheObserverCallbacks();
},
-
+
notify: function(eventName, draggable, event) { // 'onStart',
'onEnd', 'onDrag'
if(this[eventName+'Count'] > 0)
this.observers.each( function(o) {
@@ -210,7 +210,7 @@ var Draggables = {
});
if(draggable.options[eventName]) draggable.options[eventName](draggable,
event);
},
-
+
_cacheObserverCallbacks: function() {
['onStart','onEnd','onDrag'].each(
function(eventName) {
Draggables[eventName+'Count'] = Draggables.observers.select(
@@ -218,7 +218,7 @@ var Draggables = {
).length;
});
}
-}
+};
/*--------------------------------------------------------------------------*/
@@ -234,12 +234,12 @@ var Draggable = Class.create({
},
endeffect: function(element) {
var toOpacity = Object.isNumber(element._opacity) ? element._opacity :
1.0;
- new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,
+ new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,
queue: {scope:'_draggable', position:'end'},
- afterFinish: function(){
- Draggable._dragging[element] = false
+ afterFinish: function(){
+ Draggable._dragging[element] = false
}
- });
+ });
},
zindex: 1000,
revert: false,
@@ -250,57 +250,57 @@ var Draggable = Class.create({
snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] }
delay: 0
};
-
+
if(!arguments[1] || Object.isUndefined(arguments[1].endeffect))
Object.extend(defaults, {
starteffect: function(element) {
element._opacity = Element.getOpacity(element);
Draggable._dragging[element] = true;
- new Effect.Opacity(element, {duration:0.2, from:element._opacity,
to:0.7});
+ new Effect.Opacity(element, {duration:0.2, from:element._opacity,
to:0.7});
}
});
-
+
var options = Object.extend(defaults, arguments[1] || { });
this.element = $(element);
-
+
if(options.handle && Object.isString(options.handle))
this.handle = this.element.down('.'+options.handle, 0);
-
+
if(!this.handle) this.handle = $(options.handle);
if(!this.handle) this.handle = this.element;
-
+
if(options.scroll && !options.scroll.scrollTo &&
!options.scroll.outerHTML) {
options.scroll = $(options.scroll);
this._isScrollChild = Element.childOf(this.element, options.scroll);
}
- Element.makePositioned(this.element); // fix IE
+ Element.makePositioned(this.element); // fix IE
this.options = options;
- this.dragging = false;
+ this.dragging = false;
this.eventMouseDown = this.initDrag.bindAsEventListener(this);
Event.observe(this.handle, "mousedown", this.eventMouseDown);
-
+
Draggables.register(this);
},
-
+
destroy: function() {
Event.stopObserving(this.handle, "mousedown",
this.eventMouseDown);
Draggables.unregister(this);
},
-
+
currentDelta: function() {
return([
parseInt(Element.getStyle(this.element,'left') || '0'),
parseInt(Element.getStyle(this.element,'top') || '0')]);
},
-
+
initDrag: function(event) {
if(!Object.isUndefined(Draggable._dragging[this.element]) &&
Draggable._dragging[this.element]) return;
- if(Event.isLeftClick(event)) {
+ if(Event.isLeftClick(event)) {
// abort on form elements, fixes a Firefox issue
var src = Event.element(event);
if((tag_name = src.tagName.toUpperCase()) && (
@@ -309,34 +309,34 @@ var Draggable = Class.create({
tag_name=='OPTION' ||
tag_name=='BUTTON' ||
tag_name=='TEXTAREA')) return;
-
+
var pointer = [Event.pointerX(event), Event.pointerY(event)];
var pos = Position.cumulativeOffset(this.element);
this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
-
+
Draggables.activate(this);
Event.stop(event);
}
},
-
+
startDrag: function(event) {
this.dragging = true;
if(!this.delta)
this.delta = this.currentDelta();
-
+
if(this.options.zindex) {
this.originalZ =
parseInt(Element.getStyle(this.element,'z-index') || 0);
this.element.style.zIndex = this.options.zindex;
}
-
+
if(this.options.ghosting) {
this._clone = this.element.cloneNode(true);
- this.element._originallyAbsolute =
(this.element.getStyle('position') == 'absolute');
- if (!this.element._originallyAbsolute)
+ this._originallyAbsolute = (this.element.getStyle('position') ==
'absolute');
+ if (!this._originallyAbsolute)
Position.absolutize(this.element);
this.element.parentNode.insertBefore(this._clone, this.element);
}
-
+
if(this.options.scroll) {
if (this.options.scroll == window) {
var where = this._getWindowScroll(this.options.scroll);
@@ -347,15 +347,15 @@ var Draggable = Class.create({
this.originalScrollTop = this.options.scroll.scrollTop;
}
}
-
+
Draggables.notify('onStart', this, event);
-
+
if(this.options.starteffect) this.options.starteffect(this.element);
},
-
+
updateDrag: function(event, pointer) {
if(!this.dragging) this.startDrag(event);
-
+
if(!this.options.quiet){
Position.prepare();
Droppables.show(pointer, this.element);
@@ -403,9 +403,9 @@ var Draggable = Class.create({
}
if(this.options.ghosting) {
- if (!this.element._originallyAbsolute)
+ if (!this._originallyAbsolute)
Position.relativize(this.element);
- delete this.element._originallyAbsolute;
+ delete this._originallyAbsolute;
Element.remove(this._clone);
this._clone = null;
}
@@ -433,7 +433,7 @@ var Draggable = Class.create({
if(this.options.zindex)
this.element.style.zIndex = this.originalZ;
- if(this.options.endeffect)
+ if(this.options.endeffect)
this.options.endeffect(this.element);
Draggables.deactivate(this);
@@ -468,8 +468,8 @@ var Draggable = Class.create({
pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
}
- var p = [0,1].map(function(i){
- return (point[i]-pos[i]-this.offset[i])
+ var p = [0,1].map(function(i){
+ return (point[i]-pos[i]-this.offset[i])
}.bind(this));
if(this.options.snap) {
@@ -478,10 +478,10 @@ var Draggable = Class.create({
} else {
if(Object.isArray(this.options.snap)) {
p = p.map( function(v, i) {
- return (v/this.options.snap[i]).round()*this.options.snap[i]
}.bind(this))
+ return (v/this.options.snap[i]).round()*this.options.snap[i]
}.bind(this));
} else {
p = p.map( function(v) {
- return (v/this.options.snap).round()*this.options.snap }.bind(this))
+ return (v/this.options.snap).round()*this.options.snap }.bind(this));
}
}}
@@ -560,7 +560,7 @@ var Draggable = Class.create({
H = documentElement.clientHeight;
} else {
W = body.offsetWidth;
- H = body.offsetHeight
+ H = body.offsetHeight;
}
}
return { top: T, left: L, width: W, height: H };
@@ -591,9 +591,9 @@ var SortableObserver = Class.create({
var Sortable = {
SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,
-
+
sortables: { },
-
+
_findRootElement: function(element) {
while (element.tagName.toUpperCase() != "BODY") {
if(element.id && Sortable.sortables[element.id]) return element;
@@ -608,7 +608,8 @@ var Sortable = {
},
destroy: function(element){
- var s = Sortable.options(element);
+ element = $(element);
+ var s = Sortable.sortables[element.id];
if(s) {
Draggables.removeObserver(s.element);
@@ -689,14 +690,14 @@ var Sortable = {
tree: options.tree,
hoverclass: options.hoverclass,
onHover: Sortable.onHover
- }
+ };
var options_for_tree = {
onHover: Sortable.onEmptyHover,
overlap: options.overlap,
containment: options.containment,
hoverclass: options.hoverclass
- }
+ };
// fix for gecko engine
Element.cleanWhitespace(element);
@@ -832,7 +833,7 @@ var Sortable = {
Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) +
'px'});
else
Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) +
'px'});
-
+
Sortable._marker.show();
},
@@ -851,11 +852,11 @@ var Sortable = {
children: [],
position: parent.children.length,
container: $(children[i]).down(options.treeTag)
- }
+ };
/* Get the element containing the children and recurse over it */
if (child.container)
- this._tree(child.container, options, child)
+ this._tree(child.container, options, child);
parent.children.push (child);
}
@@ -880,7 +881,7 @@ var Sortable = {
children: [],
container: element,
position: 0
- }
+ };
return Sortable._tree(element, options, root);
},
@@ -931,7 +932,7 @@ var Sortable = {
if (options.tree) {
return Sortable.tree(element, arguments[1]).children.map( function (item)
{
- return [name + Sortable._constructIndex(item) + "[id]=" +
+ return [name + Sortable._constructIndex(item) + "[id]=" +
encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
}).flatten().join('&');
} else {
@@ -940,14 +941,14 @@ var Sortable = {
}).join('&');
}
}
-}
+};
// Returns true if child is contained within element
Element.isParent = function(child, element) {
if (!child.parentNode || child == element) return false;
if (child.parentNode == element) return true;
return Element.isParent(child.parentNode, element);
-}
+};
Element.findChildren = function(element, only, recursive, tagName) {
if(!element.hasChildNodes()) return null;
@@ -965,8 +966,8 @@ Element.findChildren = function(element, only, recursive,
tagName) {
});
return (elements.length>0 ? elements.flatten() : []);
-}
+};
Element.offsetSize = function (element, type) {
return element['offset' + ((type=='vertical' ||
type=='height') ? 'Height' : 'Width')];
-}
+};
\ No newline at end of file
diff --git a/src/public/javascripts/effects.js
b/src/public/javascripts/effects.js
index b0f056b..5a639d2 100644
--- a/src/public/javascripts/effects.js
+++ b/src/public/javascripts/effects.js
@@ -3,9 +3,9 @@
// Justin Palmer (http://encytemedia.com/)
// Mark Pilgrim (http://diveintomark.org/)
// Martin Bialasinki
-//
+//
// script.aculo.us is freely distributable under the terms of an MIT-style
license.
-// For details, see the script.aculo.us web site: http://script.aculo.us/
+// For details, see the script.aculo.us web site: http://script.aculo.us/
// converts rgb() and #xxx to #xxxxxx format,
// returns self (or first argument) if not convertable
@@ -32,7 +32,7 @@ Element.collectTextNodes = function(element) {
}).flatten().join('');
};
-Element.collectTextNodesIgnoreClass = function(element, className) {
+Element.collectTextNodesIgnoreClass = function(element, className) {
return $A($(element).childNodes).collect( function(node) {
return (node.nodeType==3 ? node.nodeValue :
((node.hasChildNodes() && !Element.hasClassName(node,className))
?
@@ -70,25 +70,20 @@ var Effect = {
Transitions: {
linear: Prototype.K,
sinoidal: function(pos) {
- return (-Math.cos(pos*Math.PI)/2) + 0.5;
+ return (-Math.cos(pos*Math.PI)/2) + .5;
},
reverse: function(pos) {
return 1-pos;
},
flicker: function(pos) {
- var pos = ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
+ var pos = ((-Math.cos(pos*Math.PI)/4) + .75) + Math.random()/4;
return pos > 1 ? 1 : pos;
},
wobble: function(pos) {
- return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
+ return (-Math.cos(pos*Math.PI*(9*pos))/2) + .5;
},
pulse: function(pos, pulses) {
- pulses = pulses || 5;
- return (
- ((pos % (1/pulses)) * pulses).round() == 0 ?
- ((pos * pulses * 2) - (pos * pulses * 2).floor()) :
- 1 - ((pos * pulses * 2) - (pos * pulses * 2).floor())
- );
+ return (-Math.cos((pos*((pulses||5)-.5)*2)*Math.PI)/2) + .5;
},
spring: function(pos) {
return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));
@@ -223,7 +218,7 @@ Effect.Queues = {
instances: $H(),
get: function(queueName) {
if (!Object.isString(queueName)) return queueName;
-
+
return this.instances.get(queueName) ||
this.instances.set(queueName, new Effect.ScopedQueue());
}
@@ -249,18 +244,30 @@ Effect.Base = Class.create({
this.totalTime = this.finishOn-this.startOn;
this.totalFrames = this.options.fps*this.options.duration;
- eval('this.render = function(pos){ '+
- 'if
(this.state=="idle"){this.state="running";'+
- codeForEvent(this.options,'beforeSetup')+
- (this.setup ? 'this.setup();':'')+
- codeForEvent(this.options,'afterSetup')+
- '};if (this.state=="running"){'+
-
'pos=this.options.transition(pos)*'+this.fromToDelta+'+'+this.options.from+';'+
- 'this.position=pos;'+
- codeForEvent(this.options,'beforeUpdate')+
- (this.update ? 'this.update(pos);':'')+
- codeForEvent(this.options,'afterUpdate')+
- '}}');
+ this.render = (function() {
+ function dispatch(effect, eventName) {
+ if (effect.options[eventName + 'Internal'])
+ effect.options[eventName + 'Internal'](effect);
+ if (effect.options[eventName])
+ effect.options[eventName](effect);
+ }
+
+ return function(pos) {
+ if (this.state === "idle") {
+ this.state = "running";
+ dispatch(this, 'beforeSetup');
+ if (this.setup) this.setup();
+ dispatch(this, 'afterSetup');
+ }
+ if (this.state === "running") {
+ pos = (this.options.transition(pos) * this.fromToDelta) +
this.options.from;
+ this.position = pos;
+ dispatch(this, 'beforeUpdate');
+ if (this.update) this.update(pos);
+ dispatch(this, 'afterUpdate');
+ }
+ };
+ })();
this.event('beforeStart');
if (!this.options.sync)
@@ -392,7 +399,7 @@ Effect.Move = Class.create(Effect.Base, {
// for backwards compatibility
Effect.MoveBy = function(element, toTop, toLeft) {
- return new Effect.Move(element,
+ return new Effect.Move(element,
Object.extend({ x: toLeft, y: toTop }, arguments[3] || { }));
};
@@ -507,17 +514,16 @@ Effect.Highlight = Class.create(Effect.Base, {
Effect.ScrollTo = function(element) {
var options = arguments[1] || { },
- scrollOffsets = document.viewport.getScrollOffsets(),
- elementOffsets = $(element).cumulativeOffset(),
- max = (window.height || document.body.scrollHeight) -
document.viewport.getHeight();
+ scrollOffsets = document.viewport.getScrollOffsets(),
+ elementOffsets = $(element).cumulativeOffset();
if (options.offset) elementOffsets[1] += options.offset;
return new Effect.Tween(null,
scrollOffsets.top,
- elementOffsets[1] > max ? max : elementOffsets[1],
+ elementOffsets[1],
options,
- function(p){ scrollTo(scrollOffsets.left, p.round()) }
+ function(p){ scrollTo(scrollOffsets.left, p.round()); }
);
};
@@ -554,7 +560,7 @@ Effect.Appear = function(element) {
Effect.Puff = function(element) {
element = $(element);
- var oldStyle = {
+ var oldStyle = {
opacity: element.getInlineOpacity(),
position: element.getStyle('position'),
top: element.style.top,
@@ -563,12 +569,12 @@ Effect.Puff = function(element) {
height: element.style.height
};
return new Effect.Parallel(
- [ new Effect.Scale(element, 200,
+ [ new Effect.Scale(element, 200,
{ sync: true, scaleFromCenter: true, scaleContent: true,
restoreAfterFinish: true }),
new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],
Object.extend({ duration: 1.0,
beforeSetupInternal: function(effect) {
- Position.absolutize(effect.effects[0].element)
+ Position.absolutize(effect.effects[0].element);
},
afterFinishInternal: function(effect) {
effect.effects[0].element.hide().setStyle(oldStyle); }
@@ -580,12 +586,12 @@ Effect.BlindUp = function(element) {
element = $(element);
element.makeClipping();
return new Effect.Scale(element, 0,
- Object.extend({ scaleContent: false,
+ Object.extend({ scaleContent: false,
scaleX: false,
restoreAfterFinish: true,
afterFinishInternal: function(effect) {
effect.element.hide().undoClipping();
- }
+ }
}, arguments[1] || { })
);
};
@@ -619,13 +625,13 @@ Effect.SwitchOff = function(element) {
new Effect.Scale(effect.element, 1, {
duration: 0.3, scaleFromCenter: true,
scaleX: false, scaleContent: false, restoreAfterFinish: true,
- beforeSetup: function(effect) {
+ beforeSetup: function(effect) {
effect.element.makePositioned().makeClipping();
},
afterFinishInternal: function(effect) {
effect.element.hide().undoClipping().undoPositioned().setStyle({opacity:
oldOpacity});
}
- })
+ });
}
}, arguments[1] || { }));
};
@@ -646,7 +652,7 @@ Effect.DropOut = function(element) {
},
afterFinishInternal: function(effect) {
effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
- }
+ }
}, arguments[1] || { }));
};
@@ -674,7 +680,7 @@ Effect.Shake = function(element) {
new Effect.Move(effect.element,
{ x: -distance, y: 0, duration: split, afterFinishInternal:
function(effect) {
effect.element.undoPositioned().setStyle(oldStyle);
- }}) }}) }}) }}) }}) }});
+ }}); }}); }}); }}); }}); }});
};
Effect.SlideDown = function(element) {
@@ -682,7 +688,7 @@ Effect.SlideDown = function(element) {
// SlideDown need to have the content of the element wrapped in a container
element with fixed height!
var oldInnerBottom = element.down().getStyle('bottom');
var elementDimensions = element.getDimensions();
- return new Effect.Scale(element, 100, Object.extend({
+ return new Effect.Scale(element, 100, Object.extend({
scaleContent: false,
scaleX: false,
scaleFrom: window.opera ? 0 : 1,
@@ -742,7 +748,7 @@ Effect.Squish = function(element) {
effect.element.makeClipping();
},
afterFinishInternal: function(effect) {
- effect.element.hide().undoClipping();
+ effect.element.hide().undoClipping();
}
});
};
@@ -810,13 +816,13 @@ Effect.Grow = function(element) {
sync: true, scaleFrom: window.opera ? 1 : 0, transition:
options.scaleTransition, restoreAfterFinish: true})
], Object.extend({
beforeSetup: function(effect) {
- effect.effects[0].element.setStyle({height:
'0px'}).show();
+ effect.effects[0].element.setStyle({height:
'0px'}).show();
},
afterFinishInternal: function(effect) {
effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle);
}
}, options)
- )
+ );
}
});
};
@@ -838,7 +844,7 @@ Effect.Shrink = function(element) {
var dims = element.getDimensions();
var moveX, moveY;
-
+
switch (options.direction) {
case 'top-left':
moveX = moveY = 0;
@@ -877,11 +883,13 @@ Effect.Shrink = function(element) {
Effect.Pulsate = function(element) {
element = $(element);
- var options = arguments[1] || { };
- var oldOpacity = element.getInlineOpacity();
- var transition = options.transition || Effect.Transitions.sinoidal;
- var reverser = function(pos){ return
transition(1-Effect.Transitions.pulse(pos, options.pulses)) };
- reverser.bind(transition);
+ var options = arguments[1] || { },
+ oldOpacity = element.getInlineOpacity(),
+ transition = options.transition || Effect.Transitions.linear,
+ reverser = function(pos){
+ return 1 - transition((-Math.cos((pos*(options.pulses||5)*2)*Math.PI)/2)
+ .5);
+ };
+
return new Effect.Opacity(element,
Object.extend(Object.extend({ duration: 2.0, from: 0,
afterFinishInternal: function(effect) { effect.element.setStyle({opacity:
oldOpacity}); }
@@ -934,7 +942,7 @@ Effect.Morph = Class.create(Effect.Base, {
effect.transforms.each(function(transform) {
effect.element.style[transform.style] = '';
});
- }
+ };
}
}
this.start(options);
@@ -945,7 +953,7 @@ Effect.Morph = Class.create(Effect.Base, {
if (!color || ['rgba(0, 0, 0,
0)','transparent'].include(color)) color = '#ffffff';
color = color.parseColor();
return $R(0,2).map(function(i){
- return parseInt( color.slice(i*2+1,i*2+3), 16 )
+ return parseInt( color.slice(i*2+1,i*2+3), 16 );
});
}
this.transforms = this.style.map(function(pair){
@@ -978,7 +986,7 @@ Effect.Morph = Class.create(Effect.Base, {
transform.unit != 'color' &&
(isNaN(transform.originalValue) || isNaN(transform.targetValue))
)
- )
+ );
});
},
update: function(position) {
@@ -1074,14 +1082,14 @@ if (document.defaultView &&
document.defaultView.getComputedStyle) {
Element.getStyles = function(element) {
element = $(element);
var css = element.currentStyle, styles;
- styles = Element.CSS_PROPERTIES.inject({ }, function(hash, property) {
- hash.set(property, css[property]);
- return hash;
+ styles = Element.CSS_PROPERTIES.inject({ }, function(results, property) {
+ results[property] = css[property];
+ return results;
});
- if (!styles.opacity) styles.set('opacity', element.getOpacity());
+ if (!styles.opacity) styles.opacity = element.getOpacity();
return styles;
};
-};
+}
Effect.Methods = {
morph: function(element, style) {
@@ -1090,7 +1098,7 @@ Effect.Methods = {
return element;
},
visualEffect: function(element, effect, options) {
- element = $(element)
+ element = $(element);
var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() +
s.substring(1);
new Effect[klass](element, options);
return element;
@@ -1109,7 +1117,7 @@ $w('fade appear grow shrink fold blindUp blindDown
slideUp slideDown '+
element = $(element);
Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element,
options);
return element;
- }
+ };
}
);
@@ -1117,4 +1125,4 @@ $w('getInlineOpacity forceRerendering setContentZoom
collectTextNodes collectTex
function(f) { Effect.Methods[f] = Element[f]; }
);
-Element.addMethods(Effect.Methods);
+Element.addMethods(Effect.Methods);
\ No newline at end of file
diff --git a/src/public/javascripts/prototype.js
b/src/public/javascripts/prototype.js
index 9f6c857..dfe8ab4 100644
--- a/src/public/javascripts/prototype.js
+++ b/src/public/javascripts/prototype.js
@@ -1,5 +1,5 @@
-/* Prototype JavaScript framework, version 1.6.0.1
- * (c) 2005-2007 Sam Stephenson
+/* Prototype JavaScript framework, version 1.6.0.3
+ * (c) 2005-2008 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,23 +7,26 @@
*--------------------------------------------------------------------------*/
var Prototype = {
- Version: '1.6.0.1',
+ Version: '1.6.0.3',
Browser: {
- IE: !!(window.attachEvent && !window.opera),
- Opera: !!window.opera,
+ 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,
+ Gecko: navigator.userAgent.indexOf('Gecko') > -1 &&
+ navigator.userAgent.indexOf('KHTML') === -1,
MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
},
BrowserFeatures: {
XPath: !!document.evaluate,
+ SelectorsAPI: !!document.querySelector,
ElementExtensions: !!window.HTMLElement,
SpecificElementExtensions:
- document.createElement('div').__proto__ &&
- document.createElement('div').__proto__ !=-
document.createElement('form').__proto__
+ document.createElement('div')['__proto__'] &&
+ document.createElement('div')['__proto__'] !=+
document.createElement('form')['__proto__']
},
ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
@@ -83,12 +86,13 @@ Class.Methods = {
var property = properties[i], value = source[property];
if (ancestor && Object.isFunction(value) &&
value.argumentNames().first() == "$super") {
- var method = value, value = Object.extend((function(m) {
+ var method = value;
+ value = (function(m) {
return function() { return ancestor[m].apply(this, arguments) };
- })(property).wrap(method), {
- valueOf: function() { return method },
- toString: function() { return method.toString() }
- });
+ })(property).wrap(method);
+
+ value.valueOf = method.valueOf.bind(method);
+ value.toString = method.toString.bind(method);
}
this.prototype[property] = value;
}
@@ -110,7 +114,7 @@ Object.extend(Object, {
try {
if (Object.isUndefined(object)) return 'undefined';
if (object === null) return 'null';
- return object.inspect ? object.inspect() : object.toString();
+ return object.inspect ? object.inspect() : String(object);
} catch (e) {
if (e instanceof RangeError) return '...';
throw e;
@@ -167,11 +171,12 @@ Object.extend(Object, {
},
isElement: function(object) {
- return object && object.nodeType == 1;
+ return !!(object && object.nodeType == 1);
},
isArray: function(object) {
- return object && object.constructor === Array;
+ return object != null && typeof object == "object"
&&
+ 'splice' in object && 'join' in object;
},
isHash: function(object) {
@@ -197,7 +202,8 @@ Object.extend(Object, {
Object.extend(Function.prototype, {
argumentNames: function() {
- var names =
this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip");
+ var names = this.toString().match(/^[\s\(]*function[^(]*\(([^\)]*)\)/)[1]
+ .replace(/\s+/g, '').split(',');
return names.length == 1 && !names[0] ? [] : names;
},
@@ -231,6 +237,11 @@ Object.extend(Function.prototype, {
}, timeout);
},
+ defer: function() {
+ var args = [0.01].concat($A(arguments));
+ return this.delay.apply(this, args);
+ },
+
wrap: function(wrapper) {
var __method = this;
return function() {
@@ -247,8 +258,6 @@ Object.extend(Function.prototype, {
}
});
-Function.prototype.defer = Function.prototype.delay.curry(0.01);
-
Date.prototype.toJSON = function() {
return '"' + this.getUTCFullYear() + '-' +
(this.getUTCMonth() + 1).toPaddedString(2) + '-' +
@@ -529,7 +538,7 @@ if (Prototype.Browser.WebKit || Prototype.Browser.IE)
Object.extend(String.proto
return
this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
},
unescapeHTML: function() {
- return
this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
+ return
this.stripTags().replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
}
});
@@ -546,7 +555,7 @@ Object.extend(String.prototype.escapeHTML, {
text: document.createTextNode('')
});
-with (String.prototype.escapeHTML) div.appendChild(text);
+String.prototype.escapeHTML.div.appendChild(String.prototype.escapeHTML.text);
var Template = Class.create({
initialize: function(template, pattern) {
@@ -578,7 +587,7 @@ var Template = Class.create({
}
return before + String.interpret(ctx);
- }.bind(this));
+ });
}
});
Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
@@ -588,10 +597,9 @@ var $break = { };
var Enumerable = {
each: function(iterator, context) {
var index = 0;
- iterator = iterator.bind(context);
try {
this._each(function(value) {
- iterator(value, index++);
+ iterator.call(context, value, index++);
});
} catch (e) {
if (e != $break) throw e;
@@ -600,47 +608,46 @@ var Enumerable = {
},
eachSlice: function(number, iterator, context) {
- iterator = iterator ? iterator.bind(context) : Prototype.K;
var index = -number, slices = [], array = this.toArray();
+ if (number < 1) return array;
while ((index += number) < array.length)
slices.push(array.slice(index, index+number));
return slices.collect(iterator, context);
},
all: function(iterator, context) {
- iterator = iterator ? iterator.bind(context) : Prototype.K;
+ iterator = iterator || Prototype.K;
var result = true;
this.each(function(value, index) {
- result = result && !!iterator(value, index);
+ result = result && !!iterator.call(context, value, index);
if (!result) throw $break;
});
return result;
},
any: function(iterator, context) {
- iterator = iterator ? iterator.bind(context) : Prototype.K;
+ iterator = iterator || Prototype.K;
var result = false;
this.each(function(value, index) {
- if (result = !!iterator(value, index))
+ if (result = !!iterator.call(context, value, index))
throw $break;
});
return result;
},
collect: function(iterator, context) {
- iterator = iterator ? iterator.bind(context) : Prototype.K;
+ iterator = iterator || Prototype.K;
var results = [];
this.each(function(value, index) {
- results.push(iterator(value, index));
+ results.push(iterator.call(context, value, index));
});
return results;
},
detect: function(iterator, context) {
- iterator = iterator.bind(context);
var result;
this.each(function(value, index) {
- if (iterator(value, index)) {
+ if (iterator.call(context, value, index)) {
result = value;
throw $break;
}
@@ -649,17 +656,16 @@ var Enumerable = {
},
findAll: function(iterator, context) {
- iterator = iterator.bind(context);
var results = [];
this.each(function(value, index) {
- if (iterator(value, index))
+ if (iterator.call(context, value, index))
results.push(value);
});
return results;
},
grep: function(filter, iterator, context) {
- iterator = iterator ? iterator.bind(context) : Prototype.K;
+ iterator = iterator || Prototype.K;
var results = [];
if (Object.isString(filter))
@@ -667,7 +673,7 @@ var Enumerable = {
this.each(function(value, index) {
if (filter.match(value))
- results.push(iterator(value, index));
+ results.push(iterator.call(context, value, index));
});
return results;
},
@@ -695,9 +701,8 @@ var Enumerable = {
},
inject: function(memo, iterator, context) {
- iterator = iterator.bind(context);
this.each(function(value, index) {
- memo = iterator(memo, value, index);
+ memo = iterator.call(context, memo, value, index);
});
return memo;
},
@@ -710,10 +715,10 @@ var Enumerable = {
},
max: function(iterator, context) {
- iterator = iterator ? iterator.bind(context) : Prototype.K;
+ iterator = iterator || Prototype.K;
var result;
this.each(function(value, index) {
- value = iterator(value, index);
+ value = iterator.call(context, value, index);
if (result == null || value >= result)
result = value;
});
@@ -721,10 +726,10 @@ var Enumerable = {
},
min: function(iterator, context) {
- iterator = iterator ? iterator.bind(context) : Prototype.K;
+ iterator = iterator || Prototype.K;
var result;
this.each(function(value, index) {
- value = iterator(value, index);
+ value = iterator.call(context, value, index);
if (result == null || value < result)
result = value;
});
@@ -732,10 +737,10 @@ var Enumerable = {
},
partition: function(iterator, context) {
- iterator = iterator ? iterator.bind(context) : Prototype.K;
+ iterator = iterator || Prototype.K;
var trues = [], falses = [];
this.each(function(value, index) {
- (iterator(value, index) ?
+ (iterator.call(context, value, index) ?
trues : falses).push(value);
});
return [trues, falses];
@@ -750,19 +755,20 @@ var Enumerable = {
},
reject: function(iterator, context) {
- iterator = iterator.bind(context);
var results = [];
this.each(function(value, index) {
- if (!iterator(value, index))
+ if (!iterator.call(context, value, index))
results.push(value);
});
return results;
},
sortBy: function(iterator, context) {
- iterator = iterator.bind(context);
return this.map(function(value, index) {
- return {value: value, criteria: iterator(value, index)};
+ return {
+ value: value,
+ criteria: iterator.call(context, value, index)
+ };
}).sort(function(left, right) {
var a = left.criteria, b = right.criteria;
return a < b ? -1 : a > b ? 1 : 0;
@@ -806,20 +812,24 @@ Object.extend(Enumerable, {
function $A(iterable) {
if (!iterable) return [];
if (iterable.toArray) return iterable.toArray();
- var length = iterable.length, results = new Array(length);
+ var length = iterable.length || 0, results = new Array(length);
while (length--) results[length] = iterable[length];
return results;
}
if (Prototype.Browser.WebKit) {
- function $A(iterable) {
+ $A = function(iterable) {
if (!iterable) return [];
- if (!(Object.isFunction(iterable) && iterable == '[object
NodeList]') &&
- iterable.toArray) return iterable.toArray();
- var length = iterable.length, results = new Array(length);
+ // 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;
- }
+ };
}
Array.from = $A;
@@ -962,8 +972,8 @@ Object.extend(Number.prototype, {
return this + 1;
},
- times: function(iterator) {
- $R(0, this, true).each(iterator);
+ times: function(iterator, context) {
+ $R(0, this, true).each(iterator, context);
return this;
},
@@ -1010,7 +1020,9 @@ var Hash = Class.create(Enumerable, (function() {
},
get: function(key) {
- return this._object[key];
+ // simulating poorly supported hasOwnProperty
+ if (this._object[key] !== Object.prototype[key])
+ return this._object[key];
},
unset: function(key) {
@@ -1050,14 +1062,14 @@ var Hash = Class.create(Enumerable, (function() {
},
toQueryString: function() {
- return this.map(function(pair) {
+ return this.inject([], function(results, pair) {
var key = encodeURIComponent(pair.key), values = pair.value;
if (values && typeof values == 'object') {
if (Object.isArray(values))
- return values.map(toQueryPair.curry(key)).join('&');
- }
- return toQueryPair(key, values);
+ return results.concat(values.map(toQueryPair.curry(key)));
+ } else results.push(toQueryPair(key, values));
+ return results;
}).join('&');
},
@@ -1298,7 +1310,7 @@ Ajax.Request = Class.create(Ajax.Base, {
var contentType = response.getHeader('Content-type');
if (this.options.evalJS == 'force'
- || (this.options.evalJS && contentType
+ || (this.options.evalJS && this.isSameOrigin() &&
contentType
&&
contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
this.evalResponse();
}
@@ -1316,9 +1328,18 @@ Ajax.Request = Class.create(Ajax.Base, {
}
},
+ isSameOrigin: function() {
+ var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
+ return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
+ protocol: location.protocol,
+ domain: document.domain,
+ port: location.port ? ':' + location.port : ''
+ }));
+ },
+
getHeader: function(name) {
try {
- return this.transport.getResponseHeader(name);
+ return this.transport.getResponseHeader(name) || null;
} catch (e) { return null }
},
@@ -1391,7 +1412,8 @@ Ajax.Response = Class.create({
if (!json) return null;
json = decodeURIComponent(escape(json));
try {
- return json.evalJSON(this.request.options.sanitizeJSON);
+ return json.evalJSON(this.request.options.sanitizeJSON ||
+ !this.request.isSameOrigin());
} catch (e) {
this.request.dispatchException(e);
}
@@ -1404,7 +1426,8 @@ Ajax.Response = Class.create({
this.responseText.blank())
return null;
try {
- return this.responseText.evalJSON(options.sanitizeJSON);
+ return this.responseText.evalJSON(options.sanitizeJSON ||
+ !this.request.isSameOrigin());
} catch (e) {
this.request.dispatchException(e);
}
@@ -1546,6 +1569,7 @@ if (!Node.ELEMENT_NODE) {
return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
};
Object.extend(this.Element, element || { });
+ if (element) this.Element.prototype = element.prototype;
}).call(window);
Element.cache = { };
@@ -1562,12 +1586,14 @@ Element.Methods = {
},
hide: function(element) {
- $(element).style.display = 'none';
+ element = $(element);
+ element.style.display = 'none';
return element;
},
show: function(element) {
- $(element).style.display = '';
+ element = $(element);
+ element.style.display = '';
return element;
},
@@ -1608,24 +1634,28 @@ Element.Methods = {
Object.isElement(insertions) || (insertions &&
(insertions.toElement || insertions.toHTML)))
insertions = {bottom:insertions};
- var content, t, range;
+ var content, insert, tagName, childNodes;
- for (position in insertions) {
+ for (var position in insertions) {
content = insertions[position];
position = position.toLowerCase();
- t = Element._insertionTranslations[position];
+ insert = Element._insertionTranslations[position];
if (content && content.toElement) content = content.toElement();
if (Object.isElement(content)) {
- t.insert(element, content);
+ insert(element, content);
continue;
}
content = Object.toHTML(content);
- range = element.ownerDocument.createRange();
- t.initializeRange(element, range);
- t.insert(element,
range.createContextualFragment(content.stripScripts()));
+ tagName = ((position == 'before' || position == 'after')
+ ? element.parentNode : element).tagName.toUpperCase();
+
+ childNodes = Element._getContentFromAnonymousElement(tagName,
content.stripScripts());
+
+ if (position == 'top' || position == 'after')
childNodes.reverse();
+ childNodes.each(insert.curry(element));
content.evalScripts.bind(content).defer();
}
@@ -1670,7 +1700,7 @@ Element.Methods = {
},
descendants: function(element) {
- return $(element).getElementsBySelector("*");
+ return $(element).select("*");
},
firstDescendant: function(element) {
@@ -1709,32 +1739,31 @@ Element.Methods = {
element = $(element);
if (arguments.length == 1) return $(element.parentNode);
var ancestors = element.ancestors();
- return expression ? Selector.findElement(ancestors, expression, index) :
- ancestors[index || 0];
+ return Object.isNumber(expression) ? ancestors[expression] :
+ Selector.findElement(ancestors, expression, index);
},
down: function(element, expression, index) {
element = $(element);
if (arguments.length == 1) return element.firstDescendant();
- var descendants = element.descendants();
- return expression ? Selector.findElement(descendants, expression, index) :
- descendants[index || 0];
+ return Object.isNumber(expression) ? element.descendants()[expression] :
+ Element.select(element, expression)[index || 0];
},
previous: function(element, expression, index) {
element = $(element);
if (arguments.length == 1) return
$(Selector.handlers.previousElementSibling(element));
var previousSiblings = element.previousSiblings();
- return expression ? Selector.findElement(previousSiblings, expression,
index) :
- previousSiblings[index || 0];
+ return Object.isNumber(expression) ? previousSiblings[expression] :
+ Selector.findElement(previousSiblings, expression, index);
},
next: function(element, expression, index) {
element = $(element);
if (arguments.length == 1) return
$(Selector.handlers.nextElementSibling(element));
var nextSiblings = element.nextSiblings();
- return expression ? Selector.findElement(nextSiblings, expression, index) :
- nextSiblings[index || 0];
+ return Object.isNumber(expression) ? nextSiblings[expression] :
+ Selector.findElement(nextSiblings, expression, index);
},
select: function() {
@@ -1848,23 +1877,16 @@ Element.Methods = {
descendantOf: function(element, ancestor) {
element = $(element), ancestor = $(ancestor);
- var originalAncestor = ancestor;
if (element.compareDocumentPosition)
return (element.compareDocumentPosition(ancestor) & 8) === 8;
- if (element.sourceIndex && !Prototype.Browser.Opera) {
- var e = element.sourceIndex, a = ancestor.sourceIndex,
- nextAncestor = ancestor.nextSibling;
- if (!nextAncestor) {
- do { ancestor = ancestor.parentNode; }
- while (!(nextAncestor = ancestor.nextSibling) &&
ancestor.parentNode);
- }
- if (nextAncestor) return (e > a && e <
nextAncestor.sourceIndex);
- }
+ if (ancestor.contains)
+ return ancestor.contains(element) && ancestor !== element;
while (element = element.parentNode)
- if (element == originalAncestor) return true;
+ if (element == ancestor) return true;
+
return false;
},
@@ -1879,7 +1901,7 @@ Element.Methods = {
element = $(element);
style = style == 'float' ? 'cssFloat' : style.camelize();
var value = element.style[style];
- if (!value) {
+ if (!value || value == 'auto') {
var css = document.defaultView.getComputedStyle(element, null);
value = css ? css[style] : null;
}
@@ -1918,7 +1940,7 @@ Element.Methods = {
getDimensions: function(element) {
element = $(element);
- var display = $(element).getStyle('display');
+ var display = element.getStyle('display');
if (display != 'none' && display != null) // Safari bug
return {width: element.offsetWidth, height: element.offsetHeight};
@@ -1947,7 +1969,7 @@ Element.Methods = {
element.style.position = 'relative';
// Opera returns the offset relative to the positioning context, when an
// element is position relative but top and left have not been defined
- if (window.opera) {
+ if (Prototype.Browser.Opera) {
element.style.top = 0;
element.style.left = 0;
}
@@ -2002,9 +2024,9 @@ Element.Methods = {
valueL += element.offsetLeft || 0;
element = element.offsetParent;
if (element) {
- if (element.tagName == 'BODY') break;
+ if (element.tagName.toUpperCase() == 'BODY') break;
var p = Element.getStyle(element, 'position');
- if (p == 'relative' || p == 'absolute') break;
+ if (p !== 'static') break;
}
} while (element);
return Element._returnOffset(valueL, valueT);
@@ -2012,7 +2034,7 @@ Element.Methods = {
absolutize: function(element) {
element = $(element);
- if (element.getStyle('position') == 'absolute') return;
+ if (element.getStyle('position') == 'absolute') return
element;
// Position.prepare(); // To be done manually by Scripty when it needs it.
var offsets = element.positionedOffset();
@@ -2036,7 +2058,7 @@ Element.Methods = {
relativize: function(element) {
element = $(element);
- if (element.getStyle('position') == 'relative') return;
+ if (element.getStyle('position') == 'relative') return
element;
// Position.prepare(); // To be done manually by Scripty when it needs it.
element.style.position = 'relative';
@@ -2087,7 +2109,7 @@ Element.Methods = {
element = forElement;
do {
- if (!Prototype.Browser.Opera || element.tagName == 'BODY') {
+ if (!Prototype.Browser.Opera || (element.tagName &&
(element.tagName.toUpperCase() == 'BODY'))) {
valueT -= element.scrollTop || 0;
valueL -= element.scrollLeft || 0;
}
@@ -2153,46 +2175,6 @@ Element._attributeTranslations = {
}
};
-
-if (!document.createRange || Prototype.Browser.Opera) {
- Element.Methods.insert = function(element, insertions) {
- element = $(element);
-
- if (Object.isString(insertions) || Object.isNumber(insertions) ||
- Object.isElement(insertions) || (insertions &&
(insertions.toElement || insertions.toHTML)))
- insertions = { bottom: insertions };
-
- var t = Element._insertionTranslations, content, position, pos, tagName;
-
- for (position in insertions) {
- content = insertions[position];
- position = position.toLowerCase();
- pos = t[position];
-
- if (content && content.toElement) content = content.toElement();
- if (Object.isElement(content)) {
- pos.insert(element, content);
- continue;
- }
-
- content = Object.toHTML(content);
- tagName = ((position == 'before' || position == 'after')
- ? element.parentNode : element).tagName.toUpperCase();
-
- if (t.tags[tagName]) {
- var fragments = Element._getContentFromAnonymousElement(tagName,
content.stripScripts());
- if (position == 'top' || position == 'after')
fragments.reverse();
- fragments.each(pos.insert.curry(element));
- }
- else element.insertAdjacentHTML(pos.adjacency, content.stripScripts());
-
- content.evalScripts.bind(content).defer();
- }
-
- return element;
- };
-}
-
if (Prototype.Browser.Opera) {
Element.Methods.getStyle = Element.Methods.getStyle.wrap(
function(proceed, element, style) {
@@ -2237,12 +2219,36 @@ if (Prototype.Browser.Opera) {
}
else if (Prototype.Browser.IE) {
- $w('positionedOffset getOffsetParent
viewportOffset').each(function(method) {
+ // 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) }
+ var position = element.getStyle('position');
+ if (position !== 'static') return proceed(element);
+ element.setStyle({ position: 'relative' });
+ var value = proceed(element);
+ element.setStyle({ position: position });
+ return value;
+ }
+ );
+
+ $w('positionedOffset viewportOffset').each(function(method) {
Element.Methods[method] = Element.Methods[method].wrap(
function(proceed, element) {
element = $(element);
+ try { element.offsetParent }
+ catch(e) { return Element._returnOffset(0,0) }
var position = element.getStyle('position');
- if (position != 'static') return proceed(element);
+ 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 });
element.setStyle({ position: 'relative' });
var value = proceed(element);
element.setStyle({ position: position });
@@ -2251,6 +2257,14 @@ 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();
@@ -2324,7 +2338,10 @@ else if (Prototype.Browser.IE) {
};
Element._attributeTranslations.write = {
- names: Object.clone(Element._attributeTranslations.read.names),
+ names: Object.extend({
+ cellpadding: 'cellPadding',
+ cellspacing: 'cellSpacing'
+ }, Element._attributeTranslations.read.names),
values: {
checked: function(element, value) {
element.checked = !!value;
@@ -2339,7 +2356,7 @@ else if (Prototype.Browser.IE) {
Element._attributeTranslations.has = {};
$w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
- 'encType maxLength readOnly longDesc').each(function(attr) {
+ 'encType maxLength readOnly longDesc
frameBorder').each(function(attr) {
Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
Element._attributeTranslations.has[attr.toLowerCase()] = attr;
});
@@ -2392,7 +2409,7 @@ else if (Prototype.Browser.WebKit) {
(value < 0.00001) ? 0 : value;
if (value == 1)
- if(element.tagName == 'IMG' && element.width) {
+ if(element.tagName.toUpperCase() == 'IMG' &&
element.width) {
element.width++; element.width--;
} else try {
var n = document.createTextNode(' ');
@@ -2444,7 +2461,7 @@ if (Prototype.Browser.IE || Prototype.Browser.Opera) {
};
}
-if (document.createElement('div').outerHTML) {
+if ('outerHTML' in document.createElement('div')) {
Element.Methods.replace = function(element, content) {
element = $(element);
@@ -2482,45 +2499,25 @@ Element._returnOffset = function(l, t) {
Element._getContentFromAnonymousElement = function(tagName, html) {
var div = new Element('div'), t =
Element._insertionTranslations.tags[tagName];
- div.innerHTML = t[0] + html + t[1];
- t[2].times(function() { div = div.firstChild });
+ if (t) {
+ div.innerHTML = t[0] + html + t[1];
+ t[2].times(function() { div = div.firstChild });
+ } else div.innerHTML = html;
return $A(div.childNodes);
};
Element._insertionTranslations = {
- before: {
- adjacency: 'beforeBegin',
- insert: function(element, node) {
- element.parentNode.insertBefore(node, element);
- },
- initializeRange: function(element, range) {
- range.setStartBefore(element);
- }
+ before: function(element, node) {
+ element.parentNode.insertBefore(node, element);
},
- top: {
- adjacency: 'afterBegin',
- insert: function(element, node) {
- element.insertBefore(node, element.firstChild);
- },
- initializeRange: function(element, range) {
- range.selectNodeContents(element);
- range.collapse(true);
- }
+ top: function(element, node) {
+ element.insertBefore(node, element.firstChild);
},
- bottom: {
- adjacency: 'beforeEnd',
- insert: function(element, node) {
- element.appendChild(node);
- }
+ bottom: function(element, node) {
+ element.appendChild(node);
},
- after: {
- adjacency: 'afterEnd',
- insert: function(element, node) {
- element.parentNode.insertBefore(node, element.nextSibling);
- },
- initializeRange: function(element, range) {
- range.setStartAfter(element);
- }
+ after: function(element, node) {
+ element.parentNode.insertBefore(node, element.nextSibling);
},
tags: {
TABLE: ['<table>', '</table>',
1],
@@ -2532,7 +2529,6 @@ Element._insertionTranslations = {
};
(function() {
- this.bottom.initializeRange = this.top.initializeRange;
Object.extend(this.tags, {
THEAD: this.tags.TBODY,
TFOOT: this.tags.TBODY,
@@ -2544,7 +2540,7 @@ Element.Methods.Simulated = {
hasAttribute: function(element, attribute) {
attribute = Element._attributeTranslations.has[attribute] || attribute;
var node = $(element).getAttributeNode(attribute);
- return node && node.specified;
+ return !!(node && node.specified);
}
};
@@ -2553,9 +2549,9 @@ Element.Methods.ByTag = { };
Object.extend(Element, Element.Methods);
if (!Prototype.BrowserFeatures.ElementExtensions &&
- document.createElement('div').__proto__) {
+ document.createElement('div')['__proto__']) {
window.HTMLElement = { };
- window.HTMLElement.prototype =
document.createElement('div').__proto__;
+ window.HTMLElement.prototype =
document.createElement('div')['__proto__'];
Prototype.BrowserFeatures.ElementExtensions = true;
}
@@ -2570,7 +2566,7 @@ Element.extend = (function() {
element.nodeType != 1 || element == window) return element;
var methods = Object.clone(Methods),
- tagName = element.tagName, property, value;
+ tagName = element.tagName.toUpperCase(), property, value;
// extend methods for specific tags
if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
@@ -2666,7 +2662,7 @@ Element.addMethods = function(methods) {
if (window[klass]) return window[klass];
window[klass] = { };
- window[klass].prototype = document.createElement(tagName).__proto__;
+ window[klass].prototype =
document.createElement(tagName)['__proto__'];
return window[klass];
}
@@ -2692,12 +2688,18 @@ Element.addMethods = function(methods) {
document.viewport = {
getDimensions: function() {
- var dimensions = { };
- var B = Prototype.Browser;
+ var dimensions = { }, B = Prototype.Browser;
$w('width height').each(function(d) {
var D = d.capitalize();
- dimensions[d] = (B.WebKit && !document.evaluate) ?
self['inner' + D] :
- (B.Opera) ? document.body['client' + D] :
document.documentElement['client' + D];
+ 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;
},
@@ -2716,14 +2718,24 @@ document.viewport = {
window.pageYOffset || document.documentElement.scrollTop ||
document.body.scrollTop);
}
};
-/* Portions of the Selector class are derived from Jack Slocum???s DomQuery,
+/* Portions of the Selector class are derived from Jack Slocum's DomQuery,
* part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
* license. Please see http://www.yui-ext.com/ for more information. */
var Selector = Class.create({
initialize: function(expression) {
this.expression = expression.strip();
- this.compileMatcher();
+
+ if (this.shouldUseSelectorsAPI()) {
+ this.mode = 'selectorsAPI';
+ } else if (this.shouldUseXPath()) {
+ this.mode = 'xpath';
+ this.compileXPathMatcher();
+ } else {
+ this.mode = "normal";
+ this.compileMatcher();
+ }
+
},
shouldUseXPath: function() {
@@ -2738,16 +2750,29 @@ var Selector = Class.create({
// XPath can't do namespaced attributes, nor can it read
// the "checked" property from DOM nodes
- if ((/(\[[\w-]*?:|:checked)/).test(this.expression))
+ if ((/(\[[\w-]*?:|:checked)/).test(e))
return false;
return true;
},
- compileMatcher: function() {
- if (this.shouldUseXPath())
- return this.compileXPathMatcher();
+ shouldUseSelectorsAPI: function() {
+ if (!Prototype.BrowserFeatures.SelectorsAPI) return false;
+
+ if (!Selector._div) Selector._div = new Element('div');
+
+ // 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;
+ }
+ return true;
+ },
+
+ compileMatcher: function() {
var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
c = Selector.criteria, le, p, m;
@@ -2765,7 +2790,7 @@ var Selector = Class.create({
p = ps[i];
if (m = e.match(p)) {
this.matcher.push(Object.isFunction(c[i]) ? c[i](m) :
- new Template(c[i]).evaluate(m));
+ new Template(c[i]).evaluate(m));
e = e.replace(m[0], '');
break;
}
@@ -2804,8 +2829,27 @@ var Selector = Class.create({
findElements: function(root) {
root = root || document;
- if (this.xpath) return document._getElementsByXPath(this.xpath, root);
- return this.matcher(root);
+ var e = this.expression, results;
+
+ 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;
+ }
+
+ results = $A(root.querySelectorAll(e)).map(Element.extend);
+ root.id = oldId;
+
+ return results;
+ case 'xpath':
+ return document._getElementsByXPath(this.xpath, root);
+ default:
+ return this.matcher(root);
+ }
},
match: function(element) {
@@ -2896,10 +2940,10 @@ Object.extend(Selector, {
'first-child': '[not(preceding-sibling::*)]',
'last-child': '[not(following-sibling::*)]',
'only-child': '[not(preceding-sibling::* or
following-sibling::*)]',
- 'empty': "[count(*) = 0 and (count(text()) = 0 or
translate(text(), ' \t\r\n', '') = '')]",
+ 'empty': "[count(*) = 0 and (count(text()) =
0)]",
'checked': "[@checked]",
- 'disabled': "[@disabled]",
- 'enabled': "[not(@disabled)]",
+ '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;
@@ -2959,13 +3003,13 @@ Object.extend(Selector, {
},
criteria: {
- tagName: 'n = h.tagName(n, r, "#{1}", c); c =
false;',
- className: 'n = h.className(n, r, "#{1}", c); c =
false;',
- id: 'n = h.id(n, r, "#{1}", c); c =
false;',
- attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c =
false;',
+ 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 = false;').evaluate(m);
+ 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, '\\"');
@@ -2989,8 +3033,9 @@ Object.extend(Selector, {
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]+)\]/,
+ 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|([^'"][^\]]*?)))?\]/
},
@@ -3014,7 +3059,7 @@ Object.extend(Selector, {
attr: function(element, matches) {
var nodeValue = Element.readAttribute(element, matches[1]);
- return Selector.operators[matches[2]](nodeValue, matches[3]);
+ return nodeValue && Selector.operators[matches[2]](nodeValue,
matches[5] || matches[6]);
}
},
@@ -3029,14 +3074,15 @@ Object.extend(Selector, {
// marks an array of nodes for counting
mark: function(nodes) {
+ var _true = Prototype.emptyFunction;
for (var i = 0, node; node = nodes[i]; i++)
- node._counted = true;
+ node._countedByPrototype = _true;
return nodes;
},
unmark: function(nodes) {
for (var i = 0, node; node = nodes[i]; i++)
- node._counted = undefined;
+ node._countedByPrototype = undefined;
return nodes;
},
@@ -3044,15 +3090,15 @@ Object.extend(Selector, {
// "ofType" flag indicates whether we're indexing for
nth-of-type
// rather than nth-child
index: function(parentNode, reverse, ofType) {
- parentNode._counted = true;
+ 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._counted))
node.nodeIndex = j++;
+ 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._counted))
node.nodeIndex = j++;
+ if (node.nodeType == 1 && (!ofType ||
node._countedByPrototype)) node.nodeIndex = j++;
}
},
@@ -3061,8 +3107,8 @@ Object.extend(Selector, {
if (nodes.length == 0) return nodes;
var results = [], n;
for (var i = 0, l = nodes.length; i < l; i++)
- if (!(n = nodes[i])._counted) {
- n._counted = true;
+ if (!(n = nodes[i])._countedByPrototype) {
+ n._countedByPrototype = Prototype.emptyFunction;
results.push(Element.extend(n));
}
return Selector.handlers.unmark(results);
@@ -3102,7 +3148,7 @@ Object.extend(Selector, {
nextElementSibling: function(node) {
while (node = node.nextSibling)
- if (node.nodeType == 1) return node;
+ if (node.nodeType == 1) return node;
return null;
},
@@ -3114,7 +3160,7 @@ Object.extend(Selector, {
// TOKEN FUNCTIONS
tagName: function(nodes, root, tagName, combinator) {
- tagName = tagName.toUpperCase();
+ var uTagName = tagName.toUpperCase();
var results = [], h = Selector.handlers;
if (nodes) {
if (combinator) {
@@ -3127,7 +3173,7 @@ Object.extend(Selector, {
if (tagName == "*") return nodes;
}
for (var i = 0, node; node = nodes[i]; i++)
- if (node.tagName.toUpperCase() == tagName) results.push(node);
+ if (node.tagName.toUpperCase() === uTagName) results.push(node);
return results;
} else return root.getElementsByTagName(tagName);
},
@@ -3174,16 +3220,18 @@ Object.extend(Selector, {
return results;
},
- attrPresence: function(nodes, root, attr) {
+ 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;
},
- attr: function(nodes, root, attr, value, operator) {
+ 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);
@@ -3262,7 +3310,7 @@ Object.extend(Selector, {
var h = Selector.handlers, results = [], indexed = [], m;
h.mark(nodes);
for (var i = 0, node; node = nodes[i]; i++) {
- if (!node.parentNode._counted) {
+ if (!node.parentNode._countedByPrototype) {
h.index(node.parentNode, reverse, ofType);
indexed.push(node.parentNode);
}
@@ -3289,7 +3337,7 @@ Object.extend(Selector, {
'empty': function(nodes, value, root) {
for (var i = 0, results = [], node; node = nodes[i]; i++) {
// IE treats comments as element nodes
- if (node.tagName == '!' || (node.firstChild &&
!node.innerHTML.match(/^\s*$/))) continue;
+ if (node.tagName == '!' || node.firstChild) continue;
results.push(node);
}
return results;
@@ -3300,14 +3348,15 @@ Object.extend(Selector, {
var exclusions = new Selector(selector).findElements(root);
h.mark(exclusions);
for (var i = 0, results = [], node; node = nodes[i]; i++)
- if (!node._counted) results.push(node);
+ if (!node._countedByPrototype) results.push(node);
h.unmark(exclusions);
return results;
},
'enabled': function(nodes, value, root) {
for (var i = 0, results = [], node; node = nodes[i]; i++)
- if (!node.disabled) results.push(node);
+ if (!node.disabled && (!node.type || node.type !==
'hidden'))
+ results.push(node);
return results;
},
@@ -3327,18 +3376,29 @@ Object.extend(Selector, {
operators: {
'=': function(nv, v) { return nv == v; },
'!=': function(nv, v) { return nv != v; },
- '^=': function(nv, v) { return nv.startsWith(v); },
+ '^=': function(nv, v) { return nv == 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() + '-'); }
+ '|=': function(nv, v) { return ('-' + (nv ||
"").toUpperCase() +
+ '-').include('-' + (v || "").toUpperCase() +
'-'); }
+ },
+
+ 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 = new Selector(expression).findElements(), h =
Selector.handlers;
+ var matches = $$(expression), h = Selector.handlers;
h.mark(matches);
for (var i = 0, results = [], element; element = elements[i]; i++)
- if (element._counted) results.push(element);
+ if (element._countedByPrototype) results.push(element);
h.unmark(matches);
return results;
},
@@ -3351,11 +3411,7 @@ Object.extend(Selector, {
},
findChildElements: function(element, expressions) {
- var exprs = expressions.join(',');
- expressions = [];
- exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
- expressions.push(m[1].strip());
- });
+ 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());
@@ -3366,13 +3422,22 @@ Object.extend(Selector, {
});
if (Prototype.Browser.IE) {
- // IE returns comment nodes on getElementsByTagName("*").
- // Filter them out.
- Selector.handlers.concat = function(a, b) {
- for (var i = 0, node; node = b[i]; i++)
- if (node.tagName !== "!") a.push(node);
- return a;
- };
+ 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;
+ },
+
+ // 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;
+ }
+ });
}
function $$() {
@@ -3392,7 +3457,7 @@ var Form = {
var data = elements.inject({ }, function(result, element) {
if (!element.disabled && element.name) {
key = element.name; value = $(element).getValue();
- if (value != null && (element.type != 'submit' ||
(!submitted &&
+ if (value != null && element.type != 'file' &&
(element.type != 'submit' || (!submitted &&
submit !== false && (!submit || key == submit) &&
(submitted = true)))) {
if (key in result) {
// a key is already present; construct an array of values
@@ -3553,7 +3618,6 @@ Form.Element.Methods = {
disable: function(element) {
element = $(element);
- element.blur();
element.disabled = true;
return element;
},
@@ -3593,22 +3657,22 @@ Form.Element.Serializers = {
else element.value = value;
},
- select: function(element, index) {
- if (Object.isUndefined(index))
+ select: function(element, value) {
+ if (Object.isUndefined(value))
return this[element.type == 'select-one' ?
'selectOne' : 'selectMany'](element);
else {
- var opt, value, single = !Object.isArray(index);
+ var opt, currentValue, single = !Object.isArray(value);
for (var i = 0, length = element.length; i < length; i++) {
opt = element.options[i];
- value = this.optionValue(opt);
+ currentValue = this.optionValue(opt);
if (single) {
- if (value == index) {
+ if (currentValue == value) {
opt.selected = true;
return;
}
}
- else opt.selected = index.include(value);
+ else opt.selected = value.include(currentValue);
}
}
},
@@ -3779,8 +3843,23 @@ Event.Methods = (function() {
isRightClick: function(event) { return isButton(event, 2) },
element: function(event) {
- var node = Event.extend(event).target;
- return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode :
node);
+ 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);
},
findElement: function(event, expression) {
@@ -3791,11 +3870,15 @@ Event.Methods = (function() {
},
pointer: function(event) {
+ var docElement = document.documentElement,
+ body = document.body || { scrollLeft: 0, scrollTop: 0 };
return {
x: event.pageX || (event.clientX +
- (document.documentElement.scrollLeft || document.body.scrollLeft)),
+ (docElement.scrollLeft || body.scrollLeft) -
+ (docElement.clientLeft || 0)),
y: event.pageY || (event.clientY +
- (document.documentElement.scrollTop || document.body.scrollTop))
+ (docElement.scrollTop || body.scrollTop) -
+ (docElement.clientTop || 0))
};
},
@@ -3840,7 +3923,7 @@ Event.extend = (function() {
};
} else {
- Event.prototype = Event.prototype ||
document.createEvent("HTMLEvents").__proto__;
+ Event.prototype = Event.prototype ||
document.createEvent("HTMLEvents")['__proto__'];
Object.extend(Event.prototype, methods);
return Prototype.K;
}
@@ -3850,9 +3933,9 @@ Object.extend(Event, (function() {
var cache = Event.cache;
function getEventID(element) {
- if (element._eventID) return element._eventID;
+ if (element._prototypeEventID) return element._prototypeEventID[0];
arguments.callee.id = arguments.callee.id || 1;
- return element._eventID = ++arguments.callee.id;
+ return element._prototypeEventID = [++arguments.callee.id];
}
function getDOMEventName(eventName) {
@@ -3880,7 +3963,7 @@ Object.extend(Event, (function() {
return false;
Event.extend(event);
- handler.call(element, event)
+ handler.call(element, event);
};
wrapper.handler = handler;
@@ -3905,10 +3988,20 @@ Object.extend(Event, (function() {
cache[id][eventName] = null;
}
+
+ // Internet Explorer needs to remove event handlers on page unload
+ // in order to avoid memory leaks.
if (window.attachEvent) {
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) {
+ window.addEventListener('unload', Prototype.emptyFunction, false);
+ }
+
return {
observe: function(element, eventName, handler) {
element = $(element);
@@ -3962,11 +4055,12 @@ Object.extend(Event, (function() {
if (element == document && document.createEvent &&
!element.dispatchEvent)
element = document.documentElement;
+ var event;
if (document.createEvent) {
- var event = document.createEvent("HTMLEvents");
+ event = document.createEvent("HTMLEvents");
event.initEvent("dataavailable", true, true);
} else {
- var event = document.createEventObject();
+ event = document.createEventObject();
event.eventType = "ondataavailable";
}
@@ -3995,20 +4089,21 @@ Element.addMethods({
Object.extend(document, {
fire: Element.Methods.fire.methodize(),
observe: Element.Methods.observe.methodize(),
- stopObserving: Element.Methods.stopObserving.methodize()
+ stopObserving: Element.Methods.stopObserving.methodize(),
+ loaded: false
});
(function() {
/* Support for the DOMContentLoaded event is based on work by Dan Webb,
Matthias Miller, Dean Edwards and John Resig. */
- var timer, fired = false;
+ var timer;
function fireContentLoadedEvent() {
- if (fired) return;
+ if (document.loaded) return;
if (timer) window.clearInterval(timer);
document.fire("dom:loaded");
- fired = true;
+ document.loaded = true;
}
if (document.addEventListener) {
--
1.6.2.5
Jason Guiditta
2009-Jul-20 14:58 UTC
[Ovirt-devel] [PATCH server 2/8] test_helper and unit test updates for Rails 2.3.2
Rails 2.3.2 changes test_helper use ActiveSupport::TestCase
rather than Test::Unit::TestCase, so unit test need to be
updated accordingly as well.
Signed-off-by: Jason Guiditta <jason.guiditta at gmail.com>
---
src/test/test_helper.rb | 2 +-
src/test/unit/active_record_env_test.rb | 2 +-
src/test/unit/host_browser_awaken_test.rb | 2 +-
src/test/unit/host_test.rb | 2 +-
src/test/unit/nic_test.rb | 2 +-
src/test/unit/permission_test.rb | 2 +-
src/test/unit/pool_test.rb | 2 +-
src/test/unit/quota_test.rb | 2 +-
src/test/unit/storage_pool_test.rb | 2 +-
src/test/unit/storage_volume_test.rb | 2 +-
src/test/unit/task_test.rb | 2 +-
11 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/src/test/test_helper.rb b/src/test/test_helper.rb
index fc84648..009dfc8 100644
--- a/src/test/test_helper.rb
+++ b/src/test/test_helper.rb
@@ -21,7 +21,7 @@ ENV["RAILS_ENV"] = "test"
require File.expand_path(File.dirname(__FILE__) +
"/../config/environment")
require 'test_help'
-class Test::Unit::TestCase
+class ActiveSupport::TestCase
# Transactional fixtures accelerate your tests by wrapping each test method
# in a transaction that's rolled back on completion. This ensures that
the
# test database remains unchanged so your fixtures don't have to be
reloaded
diff --git a/src/test/unit/active_record_env_test.rb
b/src/test/unit/active_record_env_test.rb
index 26fa139..a9a9c5a 100644
--- a/src/test/unit/active_record_env_test.rb
+++ b/src/test/unit/active_record_env_test.rb
@@ -20,7 +20,7 @@
require File.dirname(__FILE__) + '/../test_helper'
require File.dirname(__FILE__) + '/../../dutils/active_record_env'
-class ActiveRecordEnvTest < Test::Unit::TestCase
+class ActiveRecordEnvTest < ActiveSupport::TestCase
fixtures :pools, :hosts, :vms, :boot_types,
:networks, :nics, :ip_addresses, :privileges, :roles, :permissions,
:quotas, :storage_pools, :storage_volumes, :tasks
diff --git a/src/test/unit/host_browser_awaken_test.rb
b/src/test/unit/host_browser_awaken_test.rb
index d251e90..a7cf31c 100644
--- a/src/test/unit/host_browser_awaken_test.rb
+++ b/src/test/unit/host_browser_awaken_test.rb
@@ -31,7 +31,7 @@ require 'host-browser'
# +HostBrowserAwakenTest+ ensures that the host-browser daemon works correctly
# during the identify phase of operation.
#
-class HostBrowserAwakenTest < Test::Unit::TestCase
+class HostBrowserAwakenTest < ActiveSupport::TestCase
def setup
@session = flexmock('session')
diff --git a/src/test/unit/host_test.rb b/src/test/unit/host_test.rb
index 338fbaf..4d40990 100644
--- a/src/test/unit/host_test.rb
+++ b/src/test/unit/host_test.rb
@@ -19,7 +19,7 @@
require File.dirname(__FILE__) + '/../test_helper'
-class HostTest < Test::Unit::TestCase
+class HostTest < ActiveSupport::TestCase
fixtures :hosts
fixtures :pools
fixtures :vms
diff --git a/src/test/unit/nic_test.rb b/src/test/unit/nic_test.rb
index 07f54c6..46fab10 100644
--- a/src/test/unit/nic_test.rb
+++ b/src/test/unit/nic_test.rb
@@ -19,7 +19,7 @@
require File.dirname(__FILE__) + '/../test_helper'
-class NicTest < Test::Unit::TestCase
+class NicTest < ActiveSupport::TestCase
fixtures :ip_addresses
fixtures :nics
fixtures :hosts
diff --git a/src/test/unit/permission_test.rb b/src/test/unit/permission_test.rb
index 2ac78d5..344e615 100644
--- a/src/test/unit/permission_test.rb
+++ b/src/test/unit/permission_test.rb
@@ -19,7 +19,7 @@
require File.dirname(__FILE__) + '/../test_helper'
-class PermissionTest < Test::Unit::TestCase
+class PermissionTest < ActiveSupport::TestCase
fixtures :privileges, :roles, :permissions
fixtures :pools
diff --git a/src/test/unit/pool_test.rb b/src/test/unit/pool_test.rb
index c9a5554..bf9164d 100644
--- a/src/test/unit/pool_test.rb
+++ b/src/test/unit/pool_test.rb
@@ -19,7 +19,7 @@
require File.dirname(__FILE__) + '/../test_helper'
-class PoolTest < Test::Unit::TestCase
+class PoolTest < ActiveSupport::TestCase
fixtures :pools
def setup
diff --git a/src/test/unit/quota_test.rb b/src/test/unit/quota_test.rb
index 5903cc8..ec2f5cd 100644
--- a/src/test/unit/quota_test.rb
+++ b/src/test/unit/quota_test.rb
@@ -19,7 +19,7 @@
require File.dirname(__FILE__) + '/../test_helper'
-class QuotaTest < Test::Unit::TestCase
+class QuotaTest < ActiveSupport::TestCase
fixtures :quotas
fixtures :pools
diff --git a/src/test/unit/storage_pool_test.rb
b/src/test/unit/storage_pool_test.rb
index 4e18a8c..bd969ad 100644
--- a/src/test/unit/storage_pool_test.rb
+++ b/src/test/unit/storage_pool_test.rb
@@ -19,7 +19,7 @@
require File.dirname(__FILE__) + '/../test_helper'
-class StoragePoolTest < Test::Unit::TestCase
+class StoragePoolTest < ActiveSupport::TestCase
fixtures :storage_pools
fixtures :pools
fixtures :vms
diff --git a/src/test/unit/storage_volume_test.rb
b/src/test/unit/storage_volume_test.rb
index f0e144e..4ec8760 100644
--- a/src/test/unit/storage_volume_test.rb
+++ b/src/test/unit/storage_volume_test.rb
@@ -19,7 +19,7 @@
require File.dirname(__FILE__) + '/../test_helper'
-class StorageVolumeTest < Test::Unit::TestCase
+class StorageVolumeTest < ActiveSupport::TestCase
fixtures :storage_volumes
fixtures :storage_pools
fixtures :vms
diff --git a/src/test/unit/task_test.rb b/src/test/unit/task_test.rb
index 761e739..0f94052 100644
--- a/src/test/unit/task_test.rb
+++ b/src/test/unit/task_test.rb
@@ -19,7 +19,7 @@
require File.dirname(__FILE__) + '/../test_helper'
-class TaskTest < Test::Unit::TestCase
+class TaskTest < ActiveSupport::TestCase
fixtures :pools, :hosts, :vms, :privileges, :roles, :permissions, :tasks
def setup
--
1.6.2.5
Jason Guiditta
2009-Jul-20 14:58 UTC
[Ovirt-devel] [PATCH server 3/8] Update functional tests to work with Rails 2.3.2
Signed-off-by: Jason Guiditta <jason.guiditta at gmail.com> --- .../functional/managed_node_configuration_test.rb | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/src/test/functional/managed_node_configuration_test.rb b/src/test/functional/managed_node_configuration_test.rb index a0a66e9..8759b02 100644 --- a/src/test/functional/managed_node_configuration_test.rb +++ b/src/test/functional/managed_node_configuration_test.rb @@ -23,7 +23,7 @@ require 'managed_node_configuration' # Performs unit tests on the +ManagedNodeConfiguration+ class. # -class ManagedNodeConfigurationTest < Test::Unit::TestCase +class ManagedNodeConfigurationTest < ActiveSupport::TestCase fixtures :bonding_types fixtures :bondings fixtures :bondings_nics -- 1.6.2.5
Jason Guiditta
2009-Jul-20 14:58 UTC
[Ovirt-devel] [PATCH server 4/8] Switch from old connection style to current.
establish_connetion has been deprecated, so switch to
setup_connection.
Signed-off-by: Jason Guiditta <jason.guiditta at gmail.com>
---
src/app/helpers/ldap_connection.rb | 2 +-
src/script/grant_admin_privileges | 2 +-
src/vendor/plugins/active_ldap/init.rb | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/app/helpers/ldap_connection.rb
b/src/app/helpers/ldap_connection.rb
index af8b41b..b8cb0e3 100644
--- a/src/app/helpers/ldap_connection.rb
+++ b/src/app/helpers/ldap_connection.rb
@@ -31,7 +31,7 @@ class LDAPConnection
host = @@config[ENV['RAILS_ENV']]["host"] if host == nil
port = @@config[ENV['RAILS_ENV']]["port"] if port == nil
- ActiveLdap::Base.establish_connection(:host => host,
+ ActiveLdap::Base.setup_connection(:host => host,
:port => port,
:base => base) if LDAPConnection.connected? == false
end
diff --git a/src/script/grant_admin_privileges
b/src/script/grant_admin_privileges
index cdf36e7..a0e340a 100755
--- a/src/script/grant_admin_privileges
+++ b/src/script/grant_admin_privileges
@@ -9,7 +9,7 @@ ldap_config = YAML::load(File.open(File.dirname(__FILE__)
+"/../config/ldap.yml"
uid = ARGV[0]
base, host = ldap_config["production"]["base"],
ldap_config["production"]["host"]
-ActiveLdap::Base.establish_connection :base => base, :host => host,
:try_sasl => false
+ActiveLdap::Base.setup_connection :base => base, :host => host, :try_sasl
=> false
if Account.exists?("uid=#{uid}")
puts "Creating an admin account for #{uid}..."
diff --git a/src/vendor/plugins/active_ldap/init.rb
b/src/vendor/plugins/active_ldap/init.rb
index 3b4291e..e8395cf 100644
--- a/src/vendor/plugins/active_ldap/init.rb
+++ b/src/vendor/plugins/active_ldap/init.rb
@@ -13,7 +13,7 @@ ldap_configuration_file = File.join(RAILS_ROOT,
'config', 'ldap.yml')
if File.exist?(ldap_configuration_file)
configurations = YAML.load(ERB.new(IO.read(ldap_configuration_file)).result)
ActiveLdap::Base.configurations = configurations
- ActiveLdap::Base.establish_connection
+ ActiveLdap::Base.setup_connection
else
ActiveLdap::Base.class_eval do
format = _("You should run 'script/generator
scaffold_active_ldap' to make %s.")
--
1.6.2.5
Jason Guiditta
2009-Jul-20 14:58 UTC
[Ovirt-devel] [PATCH server 5/8] No need to track schema.rb and logs right now.
Signed-off-by: Jason Guiditta <jason.guiditta at gmail.com> --- .gitignore | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/.gitignore b/.gitignore index 0fd1d9b..9cfdd9f 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ missing stamp-h1 ovirt-server*.gz ovirt-server.spec +schema.rb +log/ -- 1.6.2.5
Jason Guiditta
2009-Jul-20 14:58 UTC
[Ovirt-devel] [PATCH server 7/8] Install render_component plugin.
This is no longer in core rails (and we should
look at removing it's use altogether asap).
Signed-off-by: Jason Guiditta <jason.guiditta at gmail.com>
---
src/vendor/plugins/render_component/README | 37 +++++
src/vendor/plugins/render_component/Rakefile | 22 +++
src/vendor/plugins/render_component/init.rb | 2 +
.../plugins/render_component/lib/components.rb | 141 ++++++++++++++++++++
.../plugins/render_component/test/abstract_unit.rb | 8 +
.../render_component/test/components_test.rb | 136 +++++++++++++++++++
6 files changed, 346 insertions(+), 0 deletions(-)
create mode 100644 src/vendor/plugins/render_component/README
create mode 100644 src/vendor/plugins/render_component/Rakefile
create mode 100644 src/vendor/plugins/render_component/init.rb
create mode 100644 src/vendor/plugins/render_component/lib/components.rb
create mode 100644 src/vendor/plugins/render_component/test/abstract_unit.rb
create mode 100644 src/vendor/plugins/render_component/test/components_test.rb
diff --git a/src/vendor/plugins/render_component/README
b/src/vendor/plugins/render_component/README
new file mode 100644
index 0000000..a6a318a
--- /dev/null
+++ b/src/vendor/plugins/render_component/README
@@ -0,0 +1,37 @@
+Components allow you to call other actions for their rendered response while
executing another action. You can either delegate
+the entire response rendering or you can mix a partial response in with your
other content.
+
+ class WeblogController < ActionController::Base
+ # Performs a method and then lets hello_world output its render
+ def delegate_action
+ do_other_stuff_before_hello_world
+ render_component :controller => "greeter", :action =>
"hello_world", :params => { :person => "david" }
+ end
+ end
+
+ class GreeterController < ActionController::Base
+ def hello_world
+ render :text => "#{params[:person]} says, Hello World!"
+ end
+ end
+
+The same can be done in a view to do a partial rendering:
+
+ Let's see a greeting:
+ <%= render_component :controller => "greeter", :action =>
"hello_world" %>
+
+It is also possible to specify the controller as a class constant, bypassing
the inflector
+code to compute the controller class at runtime:
+
+<%= render_component :controller => GreeterController, :action =>
"hello_world" %>
+
+== When to use components
+
+Components should be used with care. They're significantly slower than
simply splitting reusable parts into partials and
+conceptually more complicated. Don't use components as a way of separating
concerns inside a single application. Instead,
+reserve components to those rare cases where you truly have reusable view and
controller elements that can be employed
+across many applications at once.
+
+So to repeat: Components are a special-purpose approach that can often be
replaced with better use of partials and filters.
+
+Copyright (c) 2007 David Heinemeier Hansson, released under the MIT license
\ No newline at end of file
diff --git a/src/vendor/plugins/render_component/Rakefile
b/src/vendor/plugins/render_component/Rakefile
new file mode 100644
index 0000000..d99407b
--- /dev/null
+++ b/src/vendor/plugins/render_component/Rakefile
@@ -0,0 +1,22 @@
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+desc 'Default: run unit tests.'
+task :default => :test
+
+desc 'Test the components plugin.'
+Rake::TestTask.new(:test) do |t|
+ t.libs << 'lib'
+ t.pattern = 'test/**/*_test.rb'
+ t.verbose = true
+end
+
+desc 'Generate documentation for the components plugin.'
+Rake::RDocTask.new(:rdoc) do |rdoc|
+ rdoc.rdoc_dir = 'rdoc'
+ rdoc.title = 'Components'
+ rdoc.options << '--line-numbers' <<
'--inline-source'
+ rdoc.rdoc_files.include('README')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+end
\ No newline at end of file
diff --git a/src/vendor/plugins/render_component/init.rb
b/src/vendor/plugins/render_component/init.rb
new file mode 100644
index 0000000..b428c52
--- /dev/null
+++ b/src/vendor/plugins/render_component/init.rb
@@ -0,0 +1,2 @@
+require 'components'
+ActionController::Base.send :include, Components
diff --git a/src/vendor/plugins/render_component/lib/components.rb
b/src/vendor/plugins/render_component/lib/components.rb
new file mode 100644
index 0000000..9263cde
--- /dev/null
+++ b/src/vendor/plugins/render_component/lib/components.rb
@@ -0,0 +1,141 @@
+module Components
+ def self.included(base) #:nodoc:
+ base.class_eval do
+ include InstanceMethods
+ extend ClassMethods
+ helper HelperMethods
+
+ # If this controller was instantiated to process a component request,
+ # +parent_controller+ points to the instantiator of this controller.
+ attr_accessor :parent_controller
+
+ alias_method_chain :process_cleanup, :render_component
+ alias_method_chain :session=, :render_component
+ alias_method_chain :flash, :render_component
+ alias_method_chain :perform_action, :render_component
+ alias_method_chain :send_response, :render_component
+
+ alias_method :component_request?, :parent_controller
+ end
+ end
+
+ module ClassMethods
+ # Track parent controller to identify component requests
+ def process_with_components(request, response, parent_controller = nil)
#:nodoc:
+ controller = new
+ controller.parent_controller = parent_controller
+ controller.process(request, response)
+ end
+ end
+
+ module HelperMethods
+ def render_component(options)
+ @controller.__send__(:render_component_as_string, options)
+ end
+ end
+
+ module InstanceMethods
+ def perform_action_with_render_component
+ perform_action_without_render_component
+ remove_instance_variable(:@_flash) if defined? @_flash
+ end
+
+ # Extracts the action_name from the request parameters and performs that
action.
+ def process_with_components(request, response, method = :perform_action,
*arguments) #:nodoc:
+ flash.discard if component_request?
+ process_without_components(request, response, method, *arguments)
+ end
+
+ def send_response_with_render_component
+ response.prepare! unless component_request?
+ response
+ end
+
+ protected
+ # Renders the component specified as the response for the current method
+ def render_component(options) #:doc:
+ component_logging(options) do
+ render_for_text(component_response(options, true).body,
response.status)
+ end
+ end
+
+ # Returns the component response as a string
+ def render_component_as_string(options) #:doc:
+ component_logging(options) do
+ response = component_response(options, false)
+
+ if redirected = response.redirected_to
+ render_component_as_string(redirected)
+ else
+ response.body
+ end
+ end
+ end
+
+ def flash_with_render_component(refresh = false) #:nodoc:
+ if !defined?(@_flash) || refresh
+ @_flash + if defined?(@parent_controller)
+ @parent_controller.flash
+ else
+ flash_without_render_component
+ end
+ end
+ @_flash
+ end
+
+ private
+ def component_response(options, reuse_response)
+ klass = component_class(options)
+ request = request_for_component(klass.controller_path, options)
+ new_response = reuse_response ? response : response.dup
+
+ klass.process_with_components(request, new_response, self)
+ end
+
+ # determine the controller class for the component request
+ def component_class(options)
+ if controller = options[:controller]
+ controller.is_a?(Class) ? controller :
"#{controller.camelize}Controller".constantize
+ else
+ self.class
+ end
+ end
+
+ # Create a new request object based on the current request.
+ # The new request inherits the session from the current request,
+ # bypassing any session options set for the component controller's
class
+ def request_for_component(controller_path, options)
+ new_request = request.dup
+ new_request.session = request.session
+
+ new_request.instance_variable_set(
+ :@parameters,
+ (options[:params] || {}).with_indifferent_access.update(
+ "controller" => controller_path, "action"
=> options[:action], "id" => options[:id]
+ )
+ )
+
+ new_request
+ end
+
+ def component_logging(options)
+ if logger
+ logger.info "Start rendering component (#{options.inspect}):
"
+ result = yield
+ logger.info "\n\nEnd of component rendering"
+ result
+ else
+ yield
+ end
+ end
+
+ def session_with_render_component=(options = {})
+ session_without_render_component=(options) unless component_request?
+ end
+
+ def process_cleanup_with_render_component
+ process_cleanup_without_render_component unless component_request?
+ end
+ end
+end
diff --git a/src/vendor/plugins/render_component/test/abstract_unit.rb
b/src/vendor/plugins/render_component/test/abstract_unit.rb
new file mode 100644
index 0000000..f022971
--- /dev/null
+++ b/src/vendor/plugins/render_component/test/abstract_unit.rb
@@ -0,0 +1,8 @@
+require 'rubygems'
+require 'test/unit'
+require 'action_controller'
+require 'action_controller/test_process'
+ActionController::Routing::Routes.reload rescue nil
+
+$: << File.dirname(__FILE__) + "/../lib"
+require File.dirname(__FILE__) + "/../init"
diff --git a/src/vendor/plugins/render_component/test/components_test.rb
b/src/vendor/plugins/render_component/test/components_test.rb
new file mode 100644
index 0000000..53fcd7f
--- /dev/null
+++ b/src/vendor/plugins/render_component/test/components_test.rb
@@ -0,0 +1,136 @@
+require File.dirname(__FILE__) + '/abstract_unit'
+
+class CallerController < ActionController::Base
+ def calling_from_controller
+ render_component(:controller => "callee", :action =>
"being_called")
+ end
+
+ def calling_from_controller_with_params
+ render_component(:controller => "callee", :action =>
"being_called", :params => { "name" =>
"David" })
+ end
+
+ def calling_from_controller_with_different_status_code
+ render_component(:controller => "callee", :action =>
"blowing_up")
+ end
+
+ def calling_from_template
+ render :inline => "Ring, ring: <%= render_component(:controller
=> 'callee', :action => 'being_called') %>"
+ end
+
+ def internal_caller
+ render :inline => "Are you there? <%= render_component(:action
=> 'internal_callee') %>"
+ end
+
+ def internal_callee
+ render :text => "Yes, ma'am"
+ end
+
+ def set_flash
+ render_component(:controller => "callee", :action =>
"set_flash")
+ end
+
+ def use_flash
+ render_component(:controller => "callee", :action =>
"use_flash")
+ end
+
+ def calling_redirected
+ render_component(:controller => "callee", :action =>
"redirected")
+ end
+
+ def calling_redirected_as_string
+ render :inline => "<%= render_component(:controller =>
'callee', :action => 'redirected') %>"
+ end
+
+ def rescue_action(e) raise end
+end
+
+class CalleeController < ActionController::Base
+ def being_called
+ render :text => "#{params[:name] || "Lady"} of the House,
speaking"
+ end
+
+ def blowing_up
+ render :text => "It's game over, man, just game over,
man!", :status => 500
+ end
+
+ def set_flash
+ flash[:notice] = 'My stoney baby'
+ render :text => 'flash is set'
+ end
+
+ def use_flash
+ render :text => flash[:notice] || 'no flash'
+ end
+
+ def redirected
+ redirect_to :controller => "callee", :action =>
"being_called"
+ end
+
+ def rescue_action(e) raise end
+end
+
+class ComponentsTest < ActionController::TestCase
+ tests CallerController
+
+ def test_calling_from_controller
+ get :calling_from_controller
+ assert_equal "Lady of the House, speaking", @response.body
+ end
+
+ def test_calling_from_controller_with_params
+ get :calling_from_controller_with_params
+ assert_equal "David of the House, speaking", @response.body
+ end
+
+ def test_calling_from_controller_with_different_status_code
+ get :calling_from_controller_with_different_status_code
+ assert_equal 500, @response.response_code
+ end
+
+ def test_calling_from_template
+ get :calling_from_template
+ assert_equal "Ring, ring: Lady of the House, speaking",
@response.body
+ end
+
+ def test_etag_is_set_for_parent_template_when_calling_from_template
+ get :calling_from_template
+ expected_etag = etag_for("Ring, ring: Lady of the House,
speaking")
+ assert_equal expected_etag, @response.headers['ETag']
+ end
+
+ def test_internal_calling
+ get :internal_caller
+ assert_equal "Are you there? Yes, ma'am", @response.body
+ end
+
+ def test_flash
+ get :set_flash
+ assert_equal 'My stoney baby', flash[:notice]
+ get :use_flash
+ assert_equal 'My stoney baby', @response.body
+ get :use_flash
+ assert_equal 'no flash', @response.body
+ end
+
+ def test_component_redirect_redirects
+ get :calling_redirected
+
+ assert_redirected_to :controller=>"callee", :action =>
"being_called"
+ end
+
+ def test_component_multiple_redirect_redirects
+ test_component_redirect_redirects
+ test_internal_calling
+ end
+
+ def test_component_as_string_redirect_renders_redirected_action
+ get :calling_redirected_as_string
+
+ assert_equal "Lady of the House, speaking", @response.body
+ end
+
+ protected
+ def etag_for(text)
+ %("#{Digest::MD5.hexdigest(text)}")
+ end
+end
--
1.6.2.5
Jason Guiditta
2009-Jul-20 14:58 UTC
[Ovirt-devel] [PATCH server 8/8] Wrapper for mongrel to run with rails 2.3.2
This file is needed because we use --prefix when running mongrel_rails (which I think we need for now). It wraps the AbstractRequest call that is no longer in rails (but triggered by --prefix) so mongrel does not constantly die. It is possible there is a way now in rails itself to specify something in place of this flag, but I have not been able to find where to put that setting yet. Signed-off-by: Jason Guiditta <jason.guiditta at gmail.com> --- src/config/initializers/abstract_request.rb | 14 ++++++++++++++ 1 files changed, 14 insertions(+), 0 deletions(-) create mode 100644 src/config/initializers/abstract_request.rb diff --git a/src/config/initializers/abstract_request.rb b/src/config/initializers/abstract_request.rb new file mode 100644 index 0000000..938106d --- /dev/null +++ b/src/config/initializers/abstract_request.rb @@ -0,0 +1,14 @@ +#This is a (hopefully) temporary workaround to help +#mongrel, since it hooks into the now-gone AbstracRequest +#class. + +module ActionController + class AbstractRequest < ActionController::Request + def self.relative_url_root=(path) + ActionController::Base.relative_url_root=(path) + end + def self.relative_url_root + ActionController::Base.relative_url_root + end + end +end -- 1.6.2.5
Jason Guiditta
2009-Jul-20 15:03 UTC
[Ovirt-devel] [PATCH server 6/8] Update will_paginate to latest version.
The file git send-email doesnt like is attached -------------- next part -------------- A non-text attachment was scrubbed... Name: 0006-Update-will_paginate-to-latest-version.patch Type: text/x-patch Size: 63525 bytes Desc: not available URL: <http://listman.redhat.com/archives/ovirt-devel/attachments/20090720/f0e4d361/attachment.bin>
Jason Guiditta
2009-Jul-20 17:01 UTC
[Ovirt-devel] Upgrade server to run on Rails 2.3.2/F11
On Mon, 2009-07-20 at 10:58 -0400, Jason Guiditta wrote:> Note that one of the 8 patches (#6) will be sent separately in reply > to this email, as some of the replaced lines are too long, so git > won't let me send the email. However, there is nothing wrong with > that patch, and it should be applied in the sequence listed below. > > Note also that I assume this will be tested on a clean f11 install, rather > than an upgrade of an existing ovirt server (since if it was on F11, > it was broken anyway). > > [PATCH server 1/8] Update core app config for Rails 2.3.2 > [PATCH server 2/8] test_helper and unit test updates for Rails 2.3.2 > [PATCH server 3/8] Update functional tests to work with Rails 2.3.2 > [PATCH server 4/8] Switch from old connection style to current. > [PATCH server 5/8] No need to track schema.rb and logs right now. > [PATCH server 6/8] Update will_paginate to latest version. > [PATCH server 7/8] Install render_component plugin. > [PATCH server 8/8] Wrapper for mongrel to run with rails 2.3.2 > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-develSet is now pushed to next. Thanks to all for testing. -j