aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile3
-rw-r--r--actionmailer/CHANGELOG3
-rw-r--r--actionmailer/lib/action_mailer/old_api.rb2
-rw-r--r--actionpack/CHANGELOG11
-rw-r--r--actionpack/lib/action_controller/caching/pages.rb6
-rw-r--r--actionpack/lib/action_controller/metal/conditional_get.rb2
-rw-r--r--actionpack/lib/action_controller/metal/http_authentication.rb2
-rw-r--r--actionpack/lib/action_controller/test_case.rb7
-rw-r--r--actionpack/lib/action_dispatch/http/cache.rb13
-rw-r--r--actionpack/lib/action_dispatch/http/response.rb4
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helper.rb3
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb5
-rw-r--r--actionpack/lib/action_view/helpers/form_options_helper.rb14
-rw-r--r--actionpack/lib/action_view/helpers/form_tag_helper.rb3
-rw-r--r--actionpack/lib/action_view/helpers/number_helper.rb44
-rw-r--r--actionpack/lib/action_view/helpers/prototype_helper.rb3
-rw-r--r--actionpack/lib/action_view/helpers/tag_helper.rb41
-rw-r--r--actionpack/lib/action_view/helpers/text_helper.rb27
-rw-r--r--actionpack/lib/action_view/helpers/url_helper.rb11
-rw-r--r--actionpack/lib/action_view/renderer/abstract_renderer.rb13
-rw-r--r--actionpack/lib/action_view/renderer/template_renderer.rb4
-rw-r--r--actionpack/lib/action_view/template.rb2
-rw-r--r--actionpack/test/activerecord/controller_runtime_test.rb2
-rw-r--r--actionpack/test/controller/action_pack_assertions_test.rb8
-rw-r--r--actionpack/test/controller/log_subscriber_test.rb2
-rw-r--r--actionpack/test/dispatch/response_test.rb4
-rw-r--r--actionpack/test/template/number_helper_test.rb3
-rw-r--r--actionpack/test/template/tag_helper_test.rb7
-rw-r--r--actionpack/test/template/template_test.rb4
-rw-r--r--activemodel/CHANGELOG3
-rw-r--r--activerecord/CHANGELOG4
-rw-r--r--activerecord/lib/active_record/attribute_methods.rb2
-rw-r--r--activerecord/lib/active_record/attribute_methods/read.rb2
-rw-r--r--activerecord/lib/active_record/callbacks.rb10
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb8
-rw-r--r--activerecord/lib/active_record/nested_attributes.rb17
-rw-r--r--activerecord/lib/active_record/relation.rb2
-rw-r--r--activerecord/lib/active_record/schema_dumper.rb6
-rw-r--r--activerecord/lib/active_record/transactions.rb4
-rw-r--r--activerecord/test/cases/base_test.rb5
-rw-r--r--activerecord/test/cases/nested_attributes_test.rb26
-rw-r--r--activerecord/test/cases/transactions_test.rb21
-rw-r--r--activeresource/CHANGELOG3
-rw-r--r--activesupport/CHANGELOG5
-rw-r--r--activesupport/bin/generate_tables2
-rw-r--r--activesupport/lib/active_support/core_ext/date/calculations.rb16
-rw-r--r--activesupport/lib/active_support/core_ext/string/output_safety.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/time/calculations.rb12
-rw-r--r--activesupport/lib/active_support/core_ext/time/conversions.rb4
-rw-r--r--activesupport/lib/active_support/dependencies.rb2
-rw-r--r--activesupport/lib/active_support/ordered_hash.rb5
-rw-r--r--activesupport/lib/active_support/secure_random.rb2
-rw-r--r--activesupport/test/core_ext/date_ext_test.rb16
-rw-r--r--activesupport/test/core_ext/date_time_ext_test.rb16
-rw-r--r--activesupport/test/core_ext/time_ext_test.rb18
-rw-r--r--rails.gemspec2
-rw-r--r--railties/CHANGELOG4
-rw-r--r--railties/guides/source/active_support_core_extensions.textile25
-rw-r--r--railties/guides/source/association_basics.textile2
-rw-r--r--railties/guides/source/command_line.textile2
-rw-r--r--railties/guides/source/initialization.textile2
-rw-r--r--railties/lib/rails/application.rb2
-rw-r--r--railties/lib/rails/backtrace_cleaner.rb2
-rw-r--r--railties/lib/rails/engine.rb19
-rw-r--r--railties/lib/rails/generators/rails/app/templates/public/javascripts/jquery.js3265
-rw-r--r--railties/lib/rails/rack/log_tailer.rb2
67 files changed, 2386 insertions, 1408 deletions
diff --git a/Gemfile b/Gemfile
index 13bf277d7a..5e4b2ee1b0 100644
--- a/Gemfile
+++ b/Gemfile
@@ -46,7 +46,8 @@ platforms :ruby do
group :db do
gem "pg", ">= 0.9.0"
gem "mysql", ">= 2.8.1"
- gem "mysql2", ">= 0.2.4"
+ # gem "mysql2", ">= 0.2.4"
+ gem "mysql2", :git => "git://github.com/brianmario/mysql2.git"
end
end
diff --git a/actionmailer/CHANGELOG b/actionmailer/CHANGELOG
index 62c1402346..9c073dce1f 100644
--- a/actionmailer/CHANGELOG
+++ b/actionmailer/CHANGELOG
@@ -2,6 +2,9 @@
* No changes
+*Rails 3.0.1 (October 15, 2010)*
+
+* No Changes, just a version bump.
*Rails 3.0.0 (August 29, 2010)*
diff --git a/actionmailer/lib/action_mailer/old_api.rb b/actionmailer/lib/action_mailer/old_api.rb
index 0396f0775e..a8d7454898 100644
--- a/actionmailer/lib/action_mailer/old_api.rb
+++ b/actionmailer/lib/action_mailer/old_api.rb
@@ -212,7 +212,7 @@ module ActionMailer
# If this is a multipart e-mail add the mime_version if it is not
# already set.
- @mime_version ||= "1.0" if !@parts.empty?
+ @mime_version ||= "1.0" unless @parts.empty?
end
end
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
index 3f8188b1f7..2d133ca0b2 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -1,5 +1,12 @@
*Rails 3.1.0 (unreleased)*
+* Added a convenience idiom to generate HTML5 data-* attributes in tag helpers from a :data hash of options:
+
+ tag("div", :data => {:name => 'Stephen', :city_state => %w(Chicago IL)})
+ # => <div data-name="Stephen" data-city-state="[&quot;Chicago&quot;,&quot;IL&quot;]" />
+
+ Keys are dasherized. Values are JSON-encoded, except for strings and symbols. [Stephen Celis]
+
* Added render :once. You can pass either a string or an array of strings and Rails will ensure they each of them are rendered just once. [José Valim]
* Deprecate old template handler API. The new API simply requires a template handler to respond to call. [José Valim]
@@ -16,6 +23,10 @@
* Add Rack::Cache to the default stack. Create a Rails store that delegates to the Rails cache, so by default, whatever caching layer you are using will be used for HTTP caching. Note that Rack::Cache will be used if you use #expires_in, #fresh_when or #stale with :public => true. Otherwise, the caching rules will apply to the browser only. [Yehuda Katz, Carl Lerche]
+*Rails 3.0.1 (October 15, 2010)*
+
+* No Changes, just a version bump.
+
*Rails 3.0.0 (August 29, 2010)*
* password_field renders with nil value by default making the use of passwords secure by default, if you want to render you should do for instance f.password_field(:password, :value => @user.password) [Santiago Pastorino]
diff --git a/actionpack/lib/action_controller/caching/pages.rb b/actionpack/lib/action_controller/caching/pages.rb
index df4d500069..104157d0b1 100644
--- a/actionpack/lib/action_controller/caching/pages.rb
+++ b/actionpack/lib/action_controller/caching/pages.rb
@@ -134,7 +134,7 @@ module ActionController #:nodoc:
# If no options are provided, the requested url is used. Example:
# cache_page "I'm the cached content", :controller => "lists", :action => "show"
def cache_page(content = nil, options = nil)
- return unless self.class.perform_caching && caching_allowed
+ return unless self.class.perform_caching && caching_allowed?
path = case options
when Hash
@@ -148,10 +148,6 @@ module ActionController #:nodoc:
self.class.cache_page(content || response.body, path)
end
- private
- def caching_allowed
- request.get? && response.status.to_i == 200
- end
end
end
end
diff --git a/actionpack/lib/action_controller/metal/conditional_get.rb b/actionpack/lib/action_controller/metal/conditional_get.rb
index 8930c13a68..a5e37172c9 100644
--- a/actionpack/lib/action_controller/metal/conditional_get.rb
+++ b/actionpack/lib/action_controller/metal/conditional_get.rb
@@ -66,7 +66,7 @@ module ActionController
# Examples:
# expires_in 20.minutes
# expires_in 3.hours, :public => true
- # expires in 3.hours, 'max-stale' => 5.hours, :public => true
+ # expires_in 3.hours, 'max-stale' => 5.hours, :public => true
#
# This method will overwrite an existing Cache-Control header.
# See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html for more possibilities.
diff --git a/actionpack/lib/action_controller/metal/http_authentication.rb b/actionpack/lib/action_controller/metal/http_authentication.rb
index 547cec7081..39c804d707 100644
--- a/actionpack/lib/action_controller/metal/http_authentication.rb
+++ b/actionpack/lib/action_controller/metal/http_authentication.rb
@@ -407,7 +407,7 @@ module ActionController
# Returns nil if no token is found.
def authenticate(controller, &login_procedure)
token, options = token_and_options(controller.request)
- if !token.blank?
+ unless token.blank?
login_procedure.call(token, options)
end
end
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index 6061945622..0c26071379 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -40,6 +40,13 @@ module ActionController
ActiveSupport::Notifications.unsubscribe("!render_template.action_view")
end
+ def process(*args)
+ @partials = Hash.new(0)
+ @templates = Hash.new(0)
+ @layouts = Hash.new(0)
+ super
+ end
+
# Asserts that the request was rendered with the appropriate template file or partials.
#
# ==== Examples
diff --git a/actionpack/lib/action_dispatch/http/cache.rb b/actionpack/lib/action_dispatch/http/cache.rb
index 4061222d11..1d2f7e4f19 100644
--- a/actionpack/lib/action_dispatch/http/cache.rb
+++ b/actionpack/lib/action_dispatch/http/cache.rb
@@ -39,7 +39,8 @@ module ActionDispatch
end
module Response
- attr_reader :cache_control
+ attr_reader :cache_control, :etag
+ alias :etag? :etag
def initialize(*)
status, header, body = super
@@ -69,14 +70,6 @@ module ActionDispatch
headers['Last-Modified'] = utc_time.httpdate
end
- def etag
- @etag
- end
-
- def etag?
- @etag
- end
-
def etag=(etag)
key = ActiveSupport::Cache.expand_cache_key(etag)
@etag = self["ETag"] = %("#{Digest::MD5.hexdigest(key)}")
@@ -99,7 +92,7 @@ module ActionDispatch
if control.empty?
headers["Cache-Control"] = DEFAULT_CACHE_CONTROL
- elsif @cache_control[:no_cache]
+ elsif control[:no_cache]
headers["Cache-Control"] = "no-cache"
else
extras = control[:extras]
diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb
index 72871e328a..8e03a7879f 100644
--- a/actionpack/lib/action_dispatch/http/response.rb
+++ b/actionpack/lib/action_dispatch/http/response.rb
@@ -44,8 +44,8 @@ module ActionDispatch # :nodoc:
@block = nil
@length = 0
- @status, @header = status, header
- self.body = body
+ @header = header
+ self.body, self.status = body, status
@cookie = []
@sending_file = false
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
index d0f91f6b71..a728fde748 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
@@ -4,6 +4,7 @@ require 'action_view/helpers/url_helper'
require 'action_view/helpers/tag_helper'
require 'active_support/core_ext/file'
require 'active_support/core_ext/object/blank'
+require 'active_support/core_ext/string/output_safety'
module ActionView
# = Action View Asset Tag Helpers
@@ -819,7 +820,7 @@ module ActionView
end
def stylesheet_tag(source, options)
- tag("link", { "rel" => "stylesheet", "type" => Mime::CSS, "media" => "screen", "href" => html_escape(path_to_stylesheet(source)) }.merge(options), false, false)
+ tag("link", { "rel" => "stylesheet", "type" => Mime::CSS, "media" => "screen", "href" => ERB::Util.html_escape(path_to_stylesheet(source)) }.merge(options), false, false)
end
def compute_javascript_paths(*args)
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index b34a74788e..d6e175c7e8 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -5,6 +5,7 @@ require 'action_view/helpers/form_tag_helper'
require 'active_support/core_ext/class/inheritable_attributes'
require 'active_support/core_ext/hash/slice'
require 'active_support/core_ext/object/blank'
+require 'active_support/core_ext/string/output_safety'
module ActionView
# = Action View Form Helpers
@@ -907,7 +908,7 @@ module ActionView
end
options["type"] ||= field_type
options["value"] = options.fetch("value"){ value_before_type_cast(object) } unless field_type == "file"
- options["value"] &&= html_escape(options["value"])
+ options["value"] &&= ERB::Util.html_escape(options["value"])
add_default_name_and_id(options)
tag("input", options)
end
@@ -943,7 +944,7 @@ module ActionView
options["cols"], options["rows"] = size.split("x") if size.respond_to?(:split)
end
- content_tag("textarea", html_escape(options.delete('value') || value_before_type_cast(object)), options)
+ content_tag("textarea", ERB::Util.html_escape(options.delete('value') || value_before_type_cast(object)), options)
end
def to_check_box_tag(options = {}, checked_value = "1", unchecked_value = "0")
diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb
index 7d6aca0470..6ac8577785 100644
--- a/actionpack/lib/action_view/helpers/form_options_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_options_helper.rb
@@ -2,6 +2,7 @@ require 'cgi'
require 'erb'
require 'action_view/helpers/form_helper'
require 'active_support/core_ext/object/blank'
+require 'active_support/core_ext/string/output_safety'
module ActionView
# = Action View Form Option Helpers
@@ -100,7 +101,6 @@ module ActionView
#
module FormOptionsHelper
# ERB::Util can mask some helpers like textilize. Make sure to include them.
- include ERB::Util
include TextHelper
# Create a select tag and a series of contained option tags for the provided object and method.
@@ -247,7 +247,7 @@ module ActionView
#
# time_zone_select( "user", 'time_zone', /Australia/)
#
- # time_zone_select( "user", "time_zone", ActiveSupport::Timezone.all.sort, :model => ActiveSupport::Timezone)
+ # time_zone_select( "user", "time_zone", ActiveSupport::TimeZone.all.sort, :model => ActiveSupport::TimeZone)
def time_zone_select(object, method, priority_zones = nil, options = {}, html_options = {})
InstanceTag.new(object, method, self, options.delete(:object)).to_time_zone_select_tag(priority_zones, options, html_options)
end
@@ -306,7 +306,7 @@ module ActionView
text, value = option_text_and_value(element).map(&:to_s)
selected_attribute = ' selected="selected"' if option_value_selected?(value, selected)
disabled_attribute = ' disabled="disabled"' if disabled && option_value_selected?(value, disabled)
- %(<option value="#{html_escape(value)}"#{selected_attribute}#{disabled_attribute}#{html_attributes}>#{html_escape(text)}</option>)
+ %(<option value="#{ERB::Util.html_escape(value)}"#{selected_attribute}#{disabled_attribute}#{html_attributes}>#{ERB::Util.html_escape(text)}</option>)
end.join("\n").html_safe
end
@@ -396,7 +396,7 @@ module ActionView
def option_groups_from_collection_for_select(collection, group_method, group_label_method, option_key_method, option_value_method, selected_key = nil)
collection.map do |group|
group_label_string = eval("group.#{group_label_method}")
- "<optgroup label=\"#{html_escape(group_label_string)}\">" +
+ "<optgroup label=\"#{ERB::Util.html_escape(group_label_string)}\">" +
options_from_collection_for_select(eval("group.#{group_method}"), option_key_method, option_value_method, selected_key) +
'</optgroup>'
end.join.html_safe
@@ -501,7 +501,7 @@ module ActionView
return "" unless Array === element
html_attributes = []
element.select { |e| Hash === e }.reduce({}, :merge).each do |k, v|
- html_attributes << " #{k}=\"#{html_escape(v.to_s)}\""
+ html_attributes << " #{k}=\"#{ERB::Util.html_escape(v.to_s)}\""
end
html_attributes.join
end
@@ -595,11 +595,11 @@ module ActionView
private
def add_options(option_tags, options, value = nil)
if options[:include_blank]
- option_tags = "<option value=\"\">#{html_escape(options[:include_blank]) if options[:include_blank].kind_of?(String)}</option>\n" + option_tags
+ option_tags = "<option value=\"\">#{ERB::Util.html_escape(options[:include_blank]) if options[:include_blank].kind_of?(String)}</option>\n" + option_tags
end
if value.blank? && options[:prompt]
prompt = options[:prompt].kind_of?(String) ? options[:prompt] : I18n.translate('helpers.select.prompt', :default => 'Please select')
- option_tags = "<option value=\"\">#{html_escape(prompt)}</option>\n" + option_tags
+ option_tags = "<option value=\"\">#{ERB::Util.html_escape(prompt)}</option>\n" + option_tags
end
option_tags.html_safe
end
diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb
index ae83b6bf39..92645f5cf9 100644
--- a/actionpack/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -1,6 +1,7 @@
require 'cgi'
require 'action_view/helpers/tag_helper'
require 'active_support/core_ext/object/blank'
+require 'active_support/core_ext/string/output_safety'
module ActionView
# = Action View Form Tag Helpers
@@ -287,7 +288,7 @@ module ActionView
end
escape = options.key?("escape") ? options.delete("escape") : true
- content = html_escape(content) if escape
+ content = ERB::Util.html_escape(content) if escape
content_tag :textarea, content.to_s.html_safe, { "name" => name, "id" => sanitize_to_id(name) }.update(options)
end
diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb
index d1c8064c1b..1488e72c6e 100644
--- a/actionpack/lib/action_view/helpers/number_helper.rb
+++ b/actionpack/lib/action_view/helpers/number_helper.rb
@@ -1,6 +1,7 @@
require 'active_support/core_ext/big_decimal/conversions'
require 'active_support/core_ext/float/rounding'
require 'active_support/core_ext/object/blank'
+require 'active_support/core_ext/string/output_safety'
module ActionView
# = Action View Number Helpers
@@ -47,36 +48,33 @@ module ActionView
# number_to_phone(1235551234, :country_code => 1, :extension => 1343, :delimiter => ".")
# => +1.123.555.1234 x 1343
def number_to_phone(number, options = {})
- return nil if number.nil?
+ return unless number
begin
Float(number)
- is_number_html_safe = true
rescue ArgumentError, TypeError
- if options[:raise]
- raise InvalidNumberError, number
- else
- is_number_html_safe = number.to_s.html_safe?
- end
- end
+ raise InvalidNumberError, number
+ end if options[:raise]
number = number.to_s.strip
options = options.symbolize_keys
- area_code = options[:area_code] || nil
+ area_code = options[:area_code]
delimiter = options[:delimiter] || "-"
- extension = options[:extension].to_s.strip || nil
- country_code = options[:country_code] || nil
+ extension = options[:extension]
+ country_code = options[:country_code]
- str = ""
- str << "+#{country_code}#{delimiter}" unless country_code.blank?
- str << if area_code
- number.gsub!(/([0-9]{1,3})([0-9]{3})([0-9]{4}$)/,"(\\1) \\2#{delimiter}\\3")
+ if area_code
+ number.gsub!(/(\d{1,3})(\d{3})(\d{4}$)/,"(\\1) \\2#{delimiter}\\3")
else
- number.gsub!(/([0-9]{0,3})([0-9]{3})([0-9]{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3")
- number.starts_with?('-') ? number.slice!(1..-1) : number
+ number.gsub!(/(\d{0,3})(\d{3})(\d{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3")
+ number.slice!(0, 1) if number.starts_with?('-')
end
+
+ str = []
+ str << "+#{country_code}#{delimiter}" unless country_code.blank?
+ str << number
str << " x #{extension}" unless extension.blank?
- is_number_html_safe ? str.html_safe : str
+ ERB::Util.html_escape(str.join)
end
# Formats a +number+ into a currency string (e.g., $13.65). You can customize the format
@@ -104,7 +102,7 @@ module ActionView
# number_to_currency(1234567890.50, :unit => "&pound;", :separator => ",", :delimiter => "", :format => "%n %u")
# # => 1234567890,50 &pound;
def number_to_currency(number, options = {})
- return nil if number.nil?
+ return unless number
options.symbolize_keys!
@@ -149,7 +147,7 @@ module ActionView
# number_to_percentage(302.24398923423, :precision => 5) # => 302.24399%
# number_to_percentage(1000, :locale => :fr) # => 1 000,000%
def number_to_percentage(number, options = {})
- return nil if number.nil?
+ return unless number
options.symbolize_keys!
@@ -263,7 +261,7 @@ module ActionView
digits = (Math.log10(number.abs) + 1).floor
rounded_number = BigDecimal.new((number / 10 ** (digits - precision)).to_s).round.to_f * 10 ** (digits - precision)
end
- precision = precision - digits
+ precision -= digits
precision = precision > 0 ? precision : 0 #don't let it be negative
else
rounded_number = BigDecimal.new((number * (10 ** precision)).to_s).round.to_f / 10 ** precision
@@ -447,6 +445,8 @@ module ActionView
#for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files
options[:strip_insignificant_zeros] = true if not options.key?(:strip_insignificant_zeros)
+ inverted_du = DECIMAL_UNITS.invert
+
units = options.delete :units
unit_exponents = case units
when Hash
@@ -457,7 +457,7 @@ module ActionView
I18n.translate(:"number.human.decimal_units.units", :locale => options[:locale], :raise => true)
else
raise ArgumentError, ":units must be a Hash or String translation scope."
- end.keys.map{|e_name| DECIMAL_UNITS.invert[e_name] }.sort_by{|e| -e}
+ end.keys.map{|e_name| inverted_du[e_name] }.sort_by{|e| -e}
number_exponent = number != 0 ? Math.log10(number.abs).floor : 0
display_exponent = unit_exponents.find{|e| number_exponent >= e }
diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb
index 41cd8d5171..f3a429fcce 100644
--- a/actionpack/lib/action_view/helpers/prototype_helper.rb
+++ b/actionpack/lib/action_view/helpers/prototype_helper.rb
@@ -1,6 +1,7 @@
require 'set'
require 'active_support/json'
require 'active_support/core_ext/object/blank'
+require 'active_support/core_ext/string/output_safety'
module ActionView
# = Action View Prototype Helpers
@@ -131,7 +132,7 @@ module ActionView
url_options = options[:url]
url_options = url_options.merge(:escape => false) if url_options.is_a?(Hash)
- function << "'#{html_escape(escape_javascript(url_for(url_options)))}'"
+ function << "'#{ERB::Util.html_escape(escape_javascript(url_for(url_options)))}'"
function << ", #{javascript_options})"
function = "#{options[:before]}; #{function}" if options[:before]
diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionpack/lib/action_view/helpers/tag_helper.rb
index 1b9e152b4d..2f29c8f0e6 100644
--- a/actionpack/lib/action_view/helpers/tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/tag_helper.rb
@@ -1,4 +1,5 @@
require 'active_support/core_ext/object/blank'
+require 'active_support/core_ext/string/output_safety'
require 'set'
module ActionView
@@ -7,8 +8,6 @@ module ActionView
# Provides methods to generate HTML tags programmatically when you can't use
# a Builder. By default, they output XHTML compliant tags.
module TagHelper
- include ERB::Util
-
extend ActiveSupport::Concern
include CaptureHelper
@@ -25,9 +24,20 @@ module ActionView
# escaping.
#
# ==== Options
- # The +options+ hash is used with attributes with no value like (<tt>disabled</tt> and
- # <tt>readonly</tt>), which you can give a value of true in the +options+ hash. You can use
- # symbols or strings for the attribute names.
+ # Use +true+ with boolean attributes that can render with no value, like
+ # +disabled+ and +readonly+.
+ #
+ # HTML5 <tt>data-*</tt> attributes can be set with a single +data+ key
+ # pointing to a hash of sub-attributes.
+ #
+ # Sub-attribute keys may be strings or symbols. To play nicely with
+ # JavaScript conventions +dataset+ they will be dasherized so that a key
+ # +user_id+ would render as <tt>data-user-id</tt> and thus accessed as
+ # <tt>dataset.userId</tt>.
+ #
+ # Values are encoded to JSON, with the exception of strings and symbols.
+ # This may come in handy when using jQuery's HTML5-aware <tt>.data()<tt>
+ # from 1.4.3.
#
# ==== Examples
# tag("br")
@@ -36,14 +46,17 @@ module ActionView
# tag("br", nil, true)
# # => <br>
#
- # tag("input", { :type => 'text', :disabled => true })
+ # tag("input", :type => 'text', :disabled => true)
# # => <input type="text" disabled="disabled" />
#
- # tag("img", { :src => "open & shut.png" })
+ # tag("img", :src => "open & shut.png")
# # => <img src="open &amp; shut.png" />
#
- # tag("img", { :src => "open &amp; shut.png" }, false, false)
+ # tag("img", {:src => "open &amp; shut.png"}, false, false)
# # => <img src="open &amp; shut.png" />
+ #
+ # tag("div", :data => {:name => 'Stephen', :city_state => %w(Chicago IL)})
+ # # => <div data-name="Stephen" data-city-state="[&quot;Chicago&quot;,&quot;IL&quot;]" />
def tag(name, options = nil, open = false, escape = true)
"<#{name}#{tag_options(options, escape) if options}#{open ? ">" : " />"}".html_safe
end
@@ -118,11 +131,19 @@ module ActionView
unless options.blank?
attrs = []
options.each_pair do |key, value|
- if BOOLEAN_ATTRIBUTES.include?(key)
+ if key.to_s == 'data' && value.is_a?(Hash)
+ value.each do |k, v|
+ if !v.is_a?(String) && !v.is_a?(Symbol)
+ v = v.to_json
+ end
+ v = ERB::Util.html_escape(v) if escape
+ attrs << %(data-#{k.to_s.dasherize}="#{v}")
+ end
+ elsif BOOLEAN_ATTRIBUTES.include?(key)
attrs << %(#{key}="#{key}") if value
elsif !value.nil?
final_value = value.is_a?(Array) ? value.join(" ") : value
- final_value = html_escape(final_value) if escape
+ final_value = ERB::Util.html_escape(final_value) if escape
attrs << %(#{key}="#{final_value}")
end
end
diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb
index 94348cf9fa..7c877a0f57 100644
--- a/actionpack/lib/action_view/helpers/text_helper.rb
+++ b/actionpack/lib/action_view/helpers/text_helper.rb
@@ -134,6 +134,8 @@ module ActionView
# excerpt('This is an example', 'an', 5) # => ...s is an exam...
# excerpt('This is also an example', 'an', 8, '<chop> ') # => <chop> is also an example
def excerpt(text, phrase, *args)
+ return unless text && phrase
+
options = args.extract_options!
unless args.empty?
options[:radius] = args[0] || 100
@@ -141,21 +143,16 @@ module ActionView
end
options.reverse_merge!(:radius => 100, :omission => "...")
- if text && phrase
- phrase = Regexp.escape(phrase)
+ phrase = Regexp.escape(phrase)
+ return unless found_pos = text.mb_chars =~ /(#{phrase})/i
- if found_pos = text.mb_chars =~ /(#{phrase})/i
- start_pos = [ found_pos - options[:radius], 0 ].max
- end_pos = [ [ found_pos + phrase.mb_chars.length + options[:radius] - 1, 0].max, text.mb_chars.length ].min
+ start_pos = [ found_pos - options[:radius], 0 ].max
+ end_pos = [ [ found_pos + phrase.mb_chars.length + options[:radius] - 1, 0].max, text.mb_chars.length ].min
- prefix = start_pos > 0 ? options[:omission] : ""
- postfix = end_pos < text.mb_chars.length - 1 ? options[:omission] : ""
+ prefix = start_pos > 0 ? options[:omission] : ""
+ postfix = end_pos < text.mb_chars.length - 1 ? options[:omission] : ""
- prefix + text.mb_chars[start_pos..end_pos].strip + postfix
- else
- nil
- end
- end
+ prefix + text.mb_chars[start_pos..end_pos].strip + postfix
end
# Attempts to pluralize the +singular+ word unless +count+ is 1. If
@@ -345,10 +342,10 @@ module ActionView
values.unshift(first_value)
cycle = get_cycle(name)
- if (cycle.nil? || cycle.values != values)
+ unless cycle && cycle.values == values
cycle = set_cycle(name, Cycle.new(*values))
end
- return cycle.to_s
+ cycle.to_s
end
# Returns the current cycle string after a cycle has been started. Useful
@@ -389,7 +386,7 @@ module ActionView
# </table>
def reset_cycle(name = "default")
cycle = get_cycle(name)
- cycle.reset unless cycle.nil?
+ cycle.reset if cycle
end
class Cycle #:nodoc:
diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb
index c007cac47f..c23315b344 100644
--- a/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/actionpack/lib/action_view/helpers/url_helper.rb
@@ -1,6 +1,7 @@
require 'action_view/helpers/javascript_helper'
require 'active_support/core_ext/array/access'
require 'active_support/core_ext/hash/keys'
+require 'active_support/core_ext/string/output_safety'
require 'action_dispatch'
module ActionView
@@ -240,8 +241,8 @@ module ActionView
href = html_options['href']
tag_options = tag_options(html_options)
- href_attr = "href=\"#{html_escape(url)}\"" unless href
- "<a #{href_attr}#{tag_options}>#{html_escape(name || url)}</a>".html_safe
+ href_attr = "href=\"#{ERB::Util.html_escape(url)}\"" unless href
+ "<a #{href_attr}#{tag_options}>#{ERB::Util.html_escape(name || url)}</a>".html_safe
end
end
@@ -326,7 +327,7 @@ module ActionView
html_options.merge!("type" => "submit", "value" => name)
- ("<form method=\"#{form_method}\" action=\"#{html_escape(url)}\" #{"data-remote=\"true\"" if remote} class=\"button_to\"><div>" +
+ ("<form method=\"#{form_method}\" action=\"#{ERB::Util.html_escape(url)}\" #{"data-remote=\"true\"" if remote} class=\"button_to\"><div>" +
method_tag + tag("input", html_options) + request_token_tag + "</div></form>").html_safe
end
@@ -472,7 +473,7 @@ module ActionView
# :subject => "This is an example email"
# # => <a href="mailto:me@domain.com?cc=ccaddress@domain.com&subject=This%20is%20an%20example%20email">My email</a>
def mail_to(email_address, name = nil, html_options = {})
- email_address = html_escape(email_address)
+ email_address = ERB::Util.html_escape(email_address)
html_options = html_options.stringify_keys
encode = html_options.delete("encode").to_s
@@ -481,7 +482,7 @@ module ActionView
option = html_options.delete(item) || next
"#{item}=#{Rack::Utils.escape(option).gsub("+", "%20")}"
}.compact
- extras = extras.empty? ? '' : '?' + html_escape(extras.join('&'))
+ extras = extras.empty? ? '' : '?' + ERB::Util.html_escape(extras.join('&'))
email_address_obfuscated = email_address.dup
email_address_obfuscated.gsub!(/@/, html_options.delete("replace_at")) if html_options.key?("replace_at")
diff --git a/actionpack/lib/action_view/renderer/abstract_renderer.rb b/actionpack/lib/action_view/renderer/abstract_renderer.rb
index 77cfa51dff..4a52b3172e 100644
--- a/actionpack/lib/action_view/renderer/abstract_renderer.rb
+++ b/actionpack/lib/action_view/renderer/abstract_renderer.rb
@@ -1,9 +1,7 @@
module ActionView
class AbstractRenderer #:nodoc:
- attr_reader :vew, :lookup_context
-
delegate :find_template, :template_exists?, :with_fallbacks, :update_details,
- :with_layout_format, :formats, :to => :lookup_context
+ :with_layout_format, :formats, :freeze_formats, :to => :@lookup_context
def initialize(view)
@view = view
@@ -18,19 +16,22 @@ module ActionView
# the lookup context to take this new format into account.
def wrap_formats(value)
return yield unless value.is_a?(String)
- @@formats_regexp ||= /\.(#{Mime::SET.symbols.join('|')})$/
- if value.sub!(@@formats_regexp, "")
+ if value.sub!(formats_regexp, "")
update_details(:formats => [$1.to_sym]){ yield }
else
yield
end
end
+ def formats_regexp
+ @@formats_regexp ||= /\.(#{Mime::SET.symbols.join('|')})$/
+ end
+
protected
def instrument(name, options={})
ActiveSupport::Notifications.instrument("render_#{name}.action_view", options){ yield }
end
end
-end \ No newline at end of file
+end
diff --git a/actionpack/lib/action_view/renderer/template_renderer.rb b/actionpack/lib/action_view/renderer/template_renderer.rb
index 36beb5c8d0..6912acee31 100644
--- a/actionpack/lib/action_view/renderer/template_renderer.rb
+++ b/actionpack/lib/action_view/renderer/template_renderer.rb
@@ -56,7 +56,7 @@ module ActionView
# Renders the given template. An string representing the layout can be
# supplied as well.
def render_template(template, layout_name = nil, locals = {}) #:nodoc:
- lookup_context.freeze_formats(template.formats, true)
+ freeze_formats(template.formats, true)
view, locals = @view, locals || {}
render_with_layout(layout_name, locals) do |layout|
@@ -95,4 +95,4 @@ module ActionView
end
end
end
-end \ No newline at end of file
+end
diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb
index 7dd8acf37b..dbb1532cd4 100644
--- a/actionpack/lib/action_view/template.rb
+++ b/actionpack/lib/action_view/template.rb
@@ -163,7 +163,7 @@ module ActionView
name = pieces.pop
partial = !!name.sub!(/^_/, "")
lookup.disable_cache do
- lookup.find_template(name, pieces.join, partial, @locals)
+ lookup.find_template(name, pieces.join('/'), partial, @locals)
end
end
diff --git a/actionpack/test/activerecord/controller_runtime_test.rb b/actionpack/test/activerecord/controller_runtime_test.rb
index 16fc901760..7931da3741 100644
--- a/actionpack/test/activerecord/controller_runtime_test.rb
+++ b/actionpack/test/activerecord/controller_runtime_test.rb
@@ -37,6 +37,6 @@ class ControllerRuntimeLogSubscriberTest < ActionController::TestCase
wait
assert_equal 2, @logger.logged(:info).size
- assert_match(/\(Views: [\d\.]+ms | ActiveRecord: [\d\.]+ms\)/, @logger.logged(:info)[1])
+ assert_match(/\(Views: [\d.]+ms | ActiveRecord: [\d.]+ms\)/, @logger.logged(:info)[1])
end
end
diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb
index 5a8b763717..5a210aa9ec 100644
--- a/actionpack/test/controller/action_pack_assertions_test.rb
+++ b/actionpack/test/controller/action_pack_assertions_test.rb
@@ -465,6 +465,14 @@ class AssertTemplateTest < ActionController::TestCase
assert_template :hello_planet
end
end
+
+ def test_assert_template_reset_between_requests
+ get :hello_world
+ assert_template 'test/hello_world'
+
+ get :nothing
+ assert_template nil
+ end
end
class ActionPackHeaderTest < ActionController::TestCase
diff --git a/actionpack/test/controller/log_subscriber_test.rb b/actionpack/test/controller/log_subscriber_test.rb
index 90c944d890..e6fe0b1f04 100644
--- a/actionpack/test/controller/log_subscriber_test.rb
+++ b/actionpack/test/controller/log_subscriber_test.rb
@@ -93,7 +93,7 @@ class ACLogSubscriberTest < ActionController::TestCase
def test_process_action_with_view_runtime
get :show
wait
- assert_match(/\(Views: [\d\.]+ms\)/, logs[1])
+ assert_match(/\(Views: [\d.]+ms\)/, logs[1])
end
def test_process_action_with_filter_parameters
diff --git a/actionpack/test/dispatch/response_test.rb b/actionpack/test/dispatch/response_test.rb
index be6398fead..ab26d1a645 100644
--- a/actionpack/test/dispatch/response_test.rb
+++ b/actionpack/test/dispatch/response_test.rb
@@ -18,6 +18,10 @@ class ResponseTest < ActiveSupport::TestCase
body.each { |part| parts << part }
assert_equal ["Hello, World!"], parts
end
+
+ test "status handled properly in initialize" do
+ assert_equal 200, ActionDispatch::Response.new('200 OK').status
+ end
test "utf8 output" do
@response.body = [1090, 1077, 1089, 1090].pack("U*")
diff --git a/actionpack/test/template/number_helper_test.rb b/actionpack/test/template/number_helper_test.rb
index c14dfb250f..dcdf28ddd5 100644
--- a/actionpack/test/template/number_helper_test.rb
+++ b/actionpack/test/template/number_helper_test.rb
@@ -289,7 +289,8 @@ class NumberHelperTest < ActionView::TestCase
assert number_to_percentage("asdf".html_safe).html_safe?
assert number_to_phone(1).html_safe?
- assert !number_to_phone("<script></script>").html_safe?
+ assert_equal "&lt;script&gt;&lt;/script&gt;", number_to_phone("<script></script>")
+ assert number_to_phone("<script></script>").html_safe?
assert number_to_phone("asdf".html_safe).html_safe?
assert number_with_delimiter(1).html_safe?
diff --git a/actionpack/test/template/tag_helper_test.rb b/actionpack/test/template/tag_helper_test.rb
index c742683821..60b466a9ff 100644
--- a/actionpack/test/template/tag_helper_test.rb
+++ b/actionpack/test/template/tag_helper_test.rb
@@ -110,4 +110,11 @@ class TagHelperTest < ActionView::TestCase
def test_disable_escaping
assert_equal '<a href="&amp;" />', tag('a', { :href => '&amp;' }, false, false)
end
+
+ def test_data_attributes
+ ['data', :data].each { |data|
+ assert_dom_equal '<a data-a-number="1" data-array="[1,2,3]" data-hash="{&quot;key&quot;:&quot;value&quot;}" data-string="hello" data-symbol="foo" />',
+ tag('a', { data => { :a_number => 1, :string => 'hello', :symbol => :foo, :array => [1, 2, 3], :hash => { :key => 'value'} } })
+ }
+ end
end
diff --git a/actionpack/test/template/template_test.rb b/actionpack/test/template/template_test.rb
index 63f792d328..2ec640c84c 100644
--- a/actionpack/test/template/template_test.rb
+++ b/actionpack/test/template/template_test.rb
@@ -93,9 +93,9 @@ class TestERBTemplate < ActiveSupport::TestCase
end
def test_refresh_with_templates
- @template = new_template("Hello", :virtual_path => "test/foo")
+ @template = new_template("Hello", :virtual_path => "test/foo/bar")
@template.locals = [:key]
- @context.lookup_context.expects(:find_template).with("foo", "test", false, [:key]).returns("template")
+ @context.lookup_context.expects(:find_template).with("bar", "test/foo", false, [:key]).returns("template")
assert_equal "template", @template.refresh(@context)
end
diff --git a/activemodel/CHANGELOG b/activemodel/CHANGELOG
index 9c65778b59..e93d84ab59 100644
--- a/activemodel/CHANGELOG
+++ b/activemodel/CHANGELOG
@@ -2,6 +2,9 @@
* No changes
+*Rails 3.0.1 (October 15, 2010)*
+
+* No Changes, just a version bump.
*Rails 3.0.0 (August 29, 2010)*
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG
index 8f283e1117..75657cb6ee 100644
--- a/activerecord/CHANGELOG
+++ b/activerecord/CHANGELOG
@@ -15,6 +15,10 @@
[Aaron Patterson]
+*Rails 3.0.1 (October 15, 2010)*
+
+* Introduce a fix for CVE-2010-3993
+
*Rails 3.0.0 (August 29, 2010)*
* Changed update_attribute to not run callbacks and update the record directly in the database [Neeraj Singh]
diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb
index 7297af9f79..67f70c434e 100644
--- a/activerecord/lib/active_record/attribute_methods.rb
+++ b/activerecord/lib/active_record/attribute_methods.rb
@@ -18,7 +18,7 @@ module ActiveRecord
# method is defined by Active Record though.
def instance_method_already_implemented?(method_name)
method_name = method_name.to_s
- @_defined_class_methods ||= ancestors.first(ancestors.index(ActiveRecord::Base)).sum([]) { |m| m.public_instance_methods(false) | m.private_instance_methods(false) | m.protected_instance_methods(false) }.map {|m| m.to_s }.to_set
+ @_defined_class_methods ||= ancestors.first(ancestors.index(ActiveRecord::Base)).sum([]) { |m| m.instance_methods(false) | m.private_instance_methods(false) }.map {|m| m.to_s }.to_set
@@_defined_activerecord_methods ||= defined_activerecord_methods
raise DangerousAttributeError, "#{method_name} is defined by ActiveRecord" if @@_defined_activerecord_methods.include?(method_name)
@_defined_class_methods.include?(method_name)
diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb
index 01699746d8..ad5a3e7562 100644
--- a/activerecord/lib/active_record/attribute_methods/read.rb
+++ b/activerecord/lib/active_record/attribute_methods/read.rb
@@ -85,7 +85,7 @@ module ActiveRecord
def _read_attribute(attr_name)
attr_name = attr_name.to_s
attr_name = self.class.primary_key if attr_name == 'id'
- if !(value = @attributes[attr_name]).nil?
+ if value = @attributes[attr_name]
if column = column_for_attribute(attr_name)
if unserializable_attribute?(attr_name, column)
unserialize_attribute(attr_name)
diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb
index 49671a1042..47428cfd0f 100644
--- a/activerecord/lib/active_record/callbacks.rb
+++ b/activerecord/lib/active_record/callbacks.rb
@@ -218,16 +218,6 @@ module ActiveRecord
# needs to be aware of it because an ordinary +save+ will raise such exception
# instead of quietly returning +false+.
#
- # == Debugging callbacks
- #
- # To list the methods and procs registered with a particular callback, append <tt>_callback_chain</tt> to
- # the callback name that you wish to list and send that to your class from the Rails console:
- #
- # >> Topic.after_save_callback_chain
- # => [#<ActiveSupport::Callbacks::Callback:0x3f6a448
- # @method=#<Proc:0x03f9a42c@/Users/foo/bar/app/models/topic.rb:43>, kind:after_save, identifiernil,
- # options{}]
- #
module Callbacks
extend ActiveSupport::Concern
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb
index ec7035e540..3716937689 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb
@@ -72,7 +72,7 @@ module ActiveRecord
end
adapter_method = "#{spec[:adapter]}_connection"
- if !respond_to?(adapter_method)
+ unless respond_to?(adapter_method)
raise AdapterNotFound, "database configuration specifies nonexistent #{spec[:adapter]} adapter"
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index dce9e99d27..5949985e4d 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -465,8 +465,8 @@ module ActiveRecord
# (2) $12.345.678,12
case data
when /^-?\D+[\d,]+\.\d{2}$/ # (1)
- data.gsub!(/[^-\d\.]/, '')
- when /^-?\D+[\d\.]+,\d{2}$/ # (2)
+ data.gsub!(/[^-\d.]/, '')
+ when /^-?\D+[\d.]+,\d{2}$/ # (2)
data.gsub!(/[^-\d,]/, '').sub!(/,/, '.')
end
end
@@ -849,6 +849,10 @@ module ActiveRecord
execute "DROP INDEX #{quote_table_name(index_name)}"
end
+ def rename_index(table_name, old_name, new_name)
+ execute "ALTER INDEX #{quote_column_name(old_name)} RENAME TO #{quote_table_name(new_name)}"
+ end
+
def index_name_length
63
end
diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb
index bdd940f3ee..aca91c907d 100644
--- a/activerecord/lib/active_record/nested_attributes.rb
+++ b/activerecord/lib/active_record/nested_attributes.rb
@@ -324,9 +324,7 @@ module ActiveRecord
assign_to_or_mark_for_destruction(record, attributes, options[:allow_destroy]) unless call_reject_if(association_name, attributes)
elsif attributes['id']
- existing_record = self.class.reflect_on_association(association_name).klass.find(attributes['id'])
- assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
- self.send(association_name.to_s+'=', existing_record)
+ raise_nested_attributes_record_not_found(association_name, attributes['id'])
elsif !reject_new_record?(association_name, attributes)
method = "build_#{association_name}"
@@ -402,15 +400,12 @@ module ActiveRecord
association.build(attributes.except(*UNASSIGNABLE_KEYS))
end
- elsif existing_records.count == 0 #Existing record but not yet associated
- existing_record = self.class.reflect_on_association(association_name).klass.find(attributes['id'])
- association.send(:add_record_to_target_with_callbacks, existing_record) if !association.loaded? && !call_reject_if(association_name, attributes)
- assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
-
elsif existing_record = existing_records.detect { |record| record.id.to_s == attributes['id'].to_s }
association.send(:add_record_to_target_with_callbacks, existing_record) if !association.loaded? && !call_reject_if(association_name, attributes)
assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
+ else
+ raise_nested_attributes_record_not_found(association_name, attributes['id'])
end
end
end
@@ -430,7 +425,7 @@ module ActiveRecord
ConnectionAdapters::Column.value_to_boolean(hash['_destroy'])
end
- # Determines if a new record should be built by checking for
+ # Determines if a new record should be build by checking for
# has_destroy_flag? or if a <tt>:reject_if</tt> proc exists for this
# association and evaluates to +true+.
def reject_new_record?(association_name, attributes)
@@ -446,5 +441,9 @@ module ActiveRecord
end
end
+ def raise_nested_attributes_record_not_found(association_name, record_id)
+ reflection = self.class.reflect_on_association(association_name)
+ raise RecordNotFound, "Couldn't find #{reflection.klass.name} with ID=#{record_id} for #{self.class.name} with ID=#{id}"
+ end
end
end
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 04ba5b291e..f129b54f9a 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -379,7 +379,7 @@ module ActiveRecord
return [] if string.blank?
# always convert table names to downcase as in Oracle quoted table names are in uppercase
# ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
- string.scan(/([a-zA-Z_][\.\w]+).?\./).flatten.map{ |s| s.downcase }.uniq - ['raw_sql_']
+ string.scan(/([a-zA-Z_][.\w]+).?\./).flatten.map{ |s| s.downcase }.uniq - ['raw_sql_']
end
end
diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb
index f5331bb8a9..e30b481fe1 100644
--- a/activerecord/lib/active_record/schema_dumper.rb
+++ b/activerecord/lib/active_record/schema_dumper.rb
@@ -114,9 +114,9 @@ HEADER
column.type.to_s
end
spec[:limit] = column.limit.inspect if column.limit != @types[column.type][:limit] && spec[:type] != 'decimal'
- spec[:precision] = column.precision.inspect if !column.precision.nil?
- spec[:scale] = column.scale.inspect if !column.scale.nil?
- spec[:null] = 'false' if !column.null
+ spec[:precision] = column.precision.inspect if column.precision
+ spec[:scale] = column.scale.inspect if column.scale
+ spec[:null] = 'false' unless column.null
spec[:default] = default_string(column.default) if column.has_default?
(spec.keys - [:name, :type]).each{ |k| spec[k].insert(0, "#{k.inspect} => ")}
spec
diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb
index a7709b9489..ab737f0f88 100644
--- a/activerecord/lib/active_record/transactions.rb
+++ b/activerecord/lib/active_record/transactions.rb
@@ -224,8 +224,8 @@ module ActiveRecord
end
# See ActiveRecord::Transactions::ClassMethods for detailed documentation.
- def transaction(&block)
- self.class.transaction(&block)
+ def transaction(options = {}, &block)
+ self.class.transaction(options, &block)
end
def destroy #:nodoc:
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index 16fd9a7465..8acee9ac71 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -48,6 +48,11 @@ class Boolean < ActiveRecord::Base; end
class BasicsTest < ActiveRecord::TestCase
fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse-things', :authors, :categorizations, :categories, :posts
+ def test_select_symbol
+ topic_ids = Topic.select(:id).map(&:id).sort
+ assert_equal Topic.find(:all).map(&:id).sort, topic_ids
+ end
+
def test_table_exists
assert !NonExistentTable.table_exists?
assert Topic.table_exists?
diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb
index 8382ca048b..60f89da95e 100644
--- a/activerecord/test/cases/nested_attributes_test.rb
+++ b/activerecord/test/cases/nested_attributes_test.rb
@@ -203,6 +203,12 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase
assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name
end
+ def test_should_raise_RecordNotFound_if_an_id_is_given_but_doesnt_return_a_record
+ assert_raise_with_message ActiveRecord::RecordNotFound, "Couldn't find Ship with ID=1234567890 for Pirate with ID=#{@pirate.id}" do
+ @pirate.ship_attributes = { :id => 1234567890 }
+ end
+ end
+
def test_should_take_a_hash_with_string_keys_and_update_the_associated_model
@pirate.reload.ship_attributes = { 'id' => @ship.id, 'name' => 'Davy Jones Gold Dagger' }
@@ -382,13 +388,10 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase
assert_equal 'Arr', @ship.pirate.catchphrase
end
- def test_should_associate_with_record_if_parent_record_is_not_saved
- @ship.destroy
- @pirate = Pirate.create(:catchphrase => 'Arr')
- @ship = Ship.new(:name => 'Nights Dirty Lightning', :pirate_attributes => { :id => @pirate.id, :catchphrase => @pirate.catchphrase})
-
- assert_equal @ship.name, 'Nights Dirty Lightning'
- assert_equal @pirate, @ship.pirate
+ def test_should_raise_RecordNotFound_if_an_id_is_given_but_doesnt_return_a_record
+ assert_raise_with_message ActiveRecord::RecordNotFound, "Couldn't find Pirate with ID=1234567890 for Ship with ID=#{@ship.id}" do
+ @ship.pirate_attributes = { :id => 1234567890 }
+ end
end
def test_should_take_a_hash_with_string_keys_and_update_the_associated_model
@@ -518,11 +521,6 @@ module NestedAttributesOnACollectionAssociationTests
assert_equal ['Grace OMalley', 'Privateers Greed'], [@child_1.reload.name, @child_2.reload.name]
end
- def test_should_assign_existing_children_if_parent_is_new
- @pirate = Pirate.new({:catchphrase => "Don' botharr talkin' like one, savvy?"}.merge(@alternate_params))
- assert_equal ['Grace OMalley', 'Privateers Greed'], [@pirate.send(@association_name)[0].name, @pirate.send(@association_name)[1].name]
- end
-
def test_should_also_work_with_a_HashWithIndifferentAccess
@pirate.send(association_setter, HashWithIndifferentAccess.new('foo' => HashWithIndifferentAccess.new(:id => @child_1.id, :name => 'Grace OMalley')))
@pirate.save
@@ -586,8 +584,8 @@ module NestedAttributesOnACollectionAssociationTests
assert_equal ['Grace OMalley', 'Privateers Greed'], [@child_1.name, @child_2.name]
end
- def test_should_not_raise_RecordNotFound_if_an_id_is_given_but_doesnt_return_a_record
- assert_nothing_raised ActiveRecord::RecordNotFound do
+ def test_should_raise_RecordNotFound_if_an_id_is_given_but_doesnt_return_a_record
+ assert_raise_with_message ActiveRecord::RecordNotFound, "Couldn't find #{@child_1.class.name} with ID=1234567890 for Pirate with ID=#{@pirate.id}" do
@pirate.attributes = { association_getter => [{ :id => 1234567890 }] }
end
end
diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb
index 8385286fd0..44af54b143 100644
--- a/activerecord/test/cases/transactions_test.rb
+++ b/activerecord/test/cases/transactions_test.rb
@@ -263,6 +263,27 @@ class TransactionTest < ActiveRecord::TestCase
assert !@second.reload.approved?
end if Topic.connection.supports_savepoints?
+ def test_force_savepoint_on_instance
+ @first.transaction do
+ @first.approved = true
+ @second.approved = false
+ @first.save!
+ @second.save!
+
+ begin
+ @second.transaction :requires_new => true do
+ @first.happy = false
+ @first.save!
+ raise
+ end
+ rescue
+ end
+ end
+
+ assert @first.reload.approved?
+ assert !@second.reload.approved?
+ end if Topic.connection.supports_savepoints?
+
def test_no_savepoint_in_nested_transaction_without_force
Topic.transaction do
@first.approved = true
diff --git a/activeresource/CHANGELOG b/activeresource/CHANGELOG
index 37da2a711c..24fe3072e0 100644
--- a/activeresource/CHANGELOG
+++ b/activeresource/CHANGELOG
@@ -2,6 +2,9 @@
* No changes
+*Rails 3.0.1 (October 15, 2010)*
+
+* No Changes, just a version bump.
*Rails 3.0.0 (August 29, 2010)*
diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG
index 383cdbb52f..3b6a29f7d6 100644
--- a/activesupport/CHANGELOG
+++ b/activesupport/CHANGELOG
@@ -1,7 +1,12 @@
*Rails 3.1.0 (unreleased)*
+* Added weeks_ago and prev_week to Date/DateTime/Time. [Rob Zolkos, fxn]
+
* Added before_remove_const callback to ActiveSupport::Dependencies.remove_unloadable_constants! [Andrew White]
+*Rails 3.0.1 (October 15, 2010)*
+
+* No Changes, just a version bump.
*Rails 3.0.0 (August 29, 2010)*
diff --git a/activesupport/bin/generate_tables b/activesupport/bin/generate_tables
index 51edb59c77..7a4f840226 100644
--- a/activesupport/bin/generate_tables
+++ b/activesupport/bin/generate_tables
@@ -70,7 +70,7 @@ module ActiveSupport
end
def parse_grapheme_break_property(line)
- if line =~ /^([0-9A-F\.]+)\s*;\s*([\w]+)\s*#/
+ if line =~ /^([0-9A-F.]+)\s*;\s*([\w]+)\s*#/
type = $2.downcase.intern
@ucd.boundary[type] ||= []
if $1.include? '..'
diff --git a/activesupport/lib/active_support/core_ext/date/calculations.rb b/activesupport/lib/active_support/core_ext/date/calculations.rb
index 1856b4dd8b..f34185f22c 100644
--- a/activesupport/lib/active_support/core_ext/date/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date/calculations.rb
@@ -5,6 +5,8 @@ require 'active_support/core_ext/date/zones'
require 'active_support/core_ext/time/zones'
class Date
+ DAYS_INTO_WEEK = { :monday => 0, :tuesday => 1, :wednesday => 2, :thursday => 3, :friday => 4, :saturday => 5, :sunday => 6 }
+
if RUBY_VERSION < '1.9'
undef :>>
@@ -127,6 +129,11 @@ class Date
)
end
+ # Returns a new Date/DateTime representing the time a number of specified weeks ago.
+ def weeks_ago(weeks)
+ advance(:weeks => -weeks)
+ end
+
# Returns a new Date/DateTime representing the time a number of specified months ago.
def months_ago(months)
advance(:months => -months)
@@ -185,10 +192,15 @@ class Date
alias :sunday :end_of_week
alias :at_end_of_week :end_of_week
+ # Returns a new Date/DateTime representing the start of the given day in the previous week (default is Monday).
+ def prev_week(day = :monday)
+ result = (self - 7).beginning_of_week + DAYS_INTO_WEEK[day]
+ self.acts_like?(:time) ? result.change(:hour => 0) : result
+ end
+
# Returns a new Date/DateTime representing the start of the given day in next week (default is Monday).
def next_week(day = :monday)
- days_into_week = { :monday => 0, :tuesday => 1, :wednesday => 2, :thursday => 3, :friday => 4, :saturday => 5, :sunday => 6}
- result = (self + 7).beginning_of_week + days_into_week[day]
+ result = (self + 7).beginning_of_week + DAYS_INTO_WEEK[day]
self.acts_like?(:time) ? result.change(:hour => 0) : result
end
diff --git a/activesupport/lib/active_support/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb
index b53929c2a3..af7539881a 100644
--- a/activesupport/lib/active_support/core_ext/string/output_safety.rb
+++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb
@@ -24,6 +24,7 @@ class ERB
end
end
+ # Aliasing twice issues a warning "dicarding old...". Remove first to avoid it.
remove_method(:h)
alias h html_escape
diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb
index d430751623..fa052fa86b 100644
--- a/activesupport/lib/active_support/core_ext/time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/time/calculations.rb
@@ -22,7 +22,7 @@ class Time
# Returns a new Time if requested year can be accommodated by Ruby's Time class
# (i.e., if year is within either 1970..2038 or 1902..2038, depending on system architecture);
- # otherwise returns a DateTime
+ # otherwise returns a DateTime.
def time_with_datetime_fallback(utc_or_local, year, month=1, day=1, hour=0, min=0, sec=0, usec=0)
time = ::Time.send(utc_or_local, year, month, day, hour, min, sec, usec)
# This check is needed because Time.utc(y) returns a time object in the 2000s for 0 <= y <= 138.
@@ -117,6 +117,11 @@ class Time
end
alias :in :since
+ # Returns a new Time representing the time a number of specified weeks ago.
+ def weeks_ago(weeks)
+ advance(:weeks => -weeks)
+ end
+
# Returns a new Time representing the time a number of specified months ago
def months_ago(months)
advance(:months => -months)
@@ -172,6 +177,11 @@ class Time
end
alias :at_end_of_week :end_of_week
+ # Returns a new Time representing the start of the given day in the previous week (default is Monday).
+ def prev_week(day = :monday)
+ ago(1.week).beginning_of_week.since(DAYS_INTO_WEEK[day].day).change(:hour => 0)
+ end
+
# Returns a new Time representing the start of the given day in next week (default is Monday).
def next_week(day = :monday)
since(1.week).beginning_of_week.since(DAYS_INTO_WEEK[day].day).change(:hour => 0)
diff --git a/activesupport/lib/active_support/core_ext/time/conversions.rb b/activesupport/lib/active_support/core_ext/time/conversions.rb
index 025c619783..d4ae3131ec 100644
--- a/activesupport/lib/active_support/core_ext/time/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/time/conversions.rb
@@ -19,8 +19,8 @@ class Time
#
# time = Time.now # => Thu Jan 18 06:10:17 CST 2007
#
- # time.to_formatted_s(:time) # => "06:10:17"
- # time.to_s(:time) # => "06:10:17"
+ # time.to_formatted_s(:time) # => "06:10"
+ # time.to_s(:time) # => "06:10"
#
# time.to_formatted_s(:db) # => "2007-01-18 06:10:17"
# time.to_formatted_s(:number) # => "20070118061017"
diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb
index 09bdb577ad..787437c49a 100644
--- a/activesupport/lib/active_support/dependencies.rb
+++ b/activesupport/lib/active_support/dependencies.rb
@@ -166,7 +166,7 @@ module ActiveSupport #:nodoc:
def const_missing(const_name, nesting = nil)
klass_name = name.presence || "Object"
- if !nesting
+ unless nesting
# We'll assume that the nesting of Foo::Bar is ["Foo::Bar", "Foo"]
# even though it might not be, such as in the case of
# class Foo::Bar; Baz; end
diff --git a/activesupport/lib/active_support/ordered_hash.rb b/activesupport/lib/active_support/ordered_hash.rb
index 4adfaecd4a..7f148dc853 100644
--- a/activesupport/lib/active_support/ordered_hash.rb
+++ b/activesupport/lib/active_support/ordered_hash.rb
@@ -84,7 +84,10 @@ module ActiveSupport
end
def delete(key)
- @keys.delete key if has_key? key
+ if has_key? key
+ index = @keys.index(key)
+ @keys.delete_at index
+ end
super
end
diff --git a/activesupport/lib/active_support/secure_random.rb b/activesupport/lib/active_support/secure_random.rb
index 488a7e14a7..368954907f 100644
--- a/activesupport/lib/active_support/secure_random.rb
+++ b/activesupport/lib/active_support/secure_random.rb
@@ -95,7 +95,7 @@ module ActiveSupport
end
end
- if !defined?(@has_win32)
+ unless defined?(@has_win32)
begin
require 'Win32API'
diff --git a/activesupport/test/core_ext/date_ext_test.rb b/activesupport/test/core_ext/date_ext_test.rb
index 3141e895e6..342a31cdef 100644
--- a/activesupport/test/core_ext/date_ext_test.rb
+++ b/activesupport/test/core_ext/date_ext_test.rb
@@ -110,6 +110,14 @@ class DateExtCalculationsTest < ActiveSupport::TestCase
assert_equal Date.new(2005,1,1).to_s, Date.new(2005,2,22).beginning_of_year.to_s
end
+ def test_weeks_ago
+ assert_equal Date.new(2005,5,10), Date.new(2005,5,17).weeks_ago(1)
+ assert_equal Date.new(2005,5,10), Date.new(2005,5,24).weeks_ago(2)
+ assert_equal Date.new(2005,5,10), Date.new(2005,5,31).weeks_ago(3)
+ assert_equal Date.new(2005,5,10), Date.new(2005,6,7).weeks_ago(4)
+ assert_equal Date.new(2006,12,31), Date.new(2007,2,4).weeks_ago(5)
+ end
+
def test_months_ago
assert_equal Date.new(2005,5,5), Date.new(2005,6,5).months_ago(1)
assert_equal Date.new(2004,11,5), Date.new(2005,6,5).months_ago(7)
@@ -219,6 +227,14 @@ class DateExtCalculationsTest < ActiveSupport::TestCase
end
end
+ def test_prev_week
+ assert_equal Date.new(2005,5,9), Date.new(2005,5,17).prev_week
+ assert_equal Date.new(2006,12,25), Date.new(2007,1,7).prev_week
+ assert_equal Date.new(2010,2,12), Date.new(2010,2,19).prev_week(:friday)
+ assert_equal Date.new(2010,2,13), Date.new(2010,2,19).prev_week(:saturday)
+ assert_equal Date.new(2010,2,27), Date.new(2010,3,4).prev_week(:saturday)
+ end
+
def test_next_week
assert_equal Date.new(2005,2,28), Date.new(2005,2,22).next_week
assert_equal Date.new(2005,3,4), Date.new(2005,2,22).next_week(:friday)
diff --git a/activesupport/test/core_ext/date_time_ext_test.rb b/activesupport/test/core_ext/date_time_ext_test.rb
index cb290c541b..7d993d84e2 100644
--- a/activesupport/test/core_ext/date_time_ext_test.rb
+++ b/activesupport/test/core_ext/date_time_ext_test.rb
@@ -92,6 +92,14 @@ class DateTimeExtCalculationsTest < Test::Unit::TestCase
assert_equal DateTime.civil(2005,1,1,0,0,0), DateTime.civil(2005,2,22,10,10,10).beginning_of_year
end
+ def test_weeks_ago
+ assert_equal DateTime.civil(2005,5,29,10), DateTime.civil(2005,6,5,10,0,0).weeks_ago(1)
+ assert_equal DateTime.civil(2005,5,1,10), DateTime.civil(2005,6,5,10,0,0).weeks_ago(5)
+ assert_equal DateTime.civil(2005,4,24,10), DateTime.civil(2005,6,5,10,0,0).weeks_ago(6)
+ assert_equal DateTime.civil(2005,2,27,10), DateTime.civil(2005,6,5,10,0,0).weeks_ago(14)
+ assert_equal DateTime.civil(2004,12,25,10), DateTime.civil(2005,1,1,10,0,0).weeks_ago(1)
+ end
+
def test_months_ago
assert_equal DateTime.civil(2005,5,5,10), DateTime.civil(2005,6,5,10,0,0).months_ago(1)
assert_equal DateTime.civil(2004,11,5,10), DateTime.civil(2005,6,5,10,0,0).months_ago(7)
@@ -196,6 +204,14 @@ class DateTimeExtCalculationsTest < Test::Unit::TestCase
assert_equal DateTime.civil(2010, 3, 29), DateTime.civil(2010, 2, 28, 22, 58, 59).advance(:months => 1, :hours => 1, :minutes => 1, :seconds => 1)
end
+ def test_prev_week
+ assert_equal DateTime.civil(2005,2,21), DateTime.civil(2005,3,1,15,15,10).prev_week
+ assert_equal DateTime.civil(2005,2,22), DateTime.civil(2005,3,1,15,15,10).prev_week(:tuesday)
+ assert_equal DateTime.civil(2005,2,25), DateTime.civil(2005,3,1,15,15,10).prev_week(:friday)
+ assert_equal DateTime.civil(2006,10,30), DateTime.civil(2006,11,6,0,0,0).prev_week
+ assert_equal DateTime.civil(2006,11,15), DateTime.civil(2006,11,23,0,0,0).prev_week(:wednesday)
+ end
+
def test_next_week
assert_equal DateTime.civil(2005,2,28), DateTime.civil(2005,2,22,15,15,10).next_week
assert_equal DateTime.civil(2005,3,4), DateTime.civil(2005,2,22,15,15,10).next_week(:friday)
diff --git a/activesupport/test/core_ext/time_ext_test.rb b/activesupport/test/core_ext/time_ext_test.rb
index c43b3eb358..53d497013a 100644
--- a/activesupport/test/core_ext/time_ext_test.rb
+++ b/activesupport/test/core_ext/time_ext_test.rb
@@ -130,6 +130,14 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
assert_equal Time.local(2005,1,1,0,0,0), Time.local(2005,2,22,10,10,10).beginning_of_year
end
+ def test_weeks_ago
+ assert_equal Time.local(2005,5,29,10), Time.local(2005,6,5,10,0,0).weeks_ago(1)
+ assert_equal Time.local(2005,5,1,10), Time.local(2005,6,5,10,0,0).weeks_ago(5)
+ assert_equal Time.local(2005,4,24,10), Time.local(2005,6,5,10,0,0).weeks_ago(6)
+ assert_equal Time.local(2005,2,27,10), Time.local(2005,6,5,10,0,0).weeks_ago(14)
+ assert_equal Time.local(2004,12,25,10), Time.local(2005,1,1,10,0,0).weeks_ago(1)
+ end
+
def test_months_ago
assert_equal Time.local(2005,5,5,10), Time.local(2005,6,5,10,0,0).months_ago(1)
assert_equal Time.local(2004,11,5,10), Time.local(2005,6,5,10,0,0).months_ago(7)
@@ -463,6 +471,16 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
assert_equal Time.utc(2013,10,17,20,22,19), Time.utc(2005,2,28,15,15,10).advance(:years => 7, :months => 19, :weeks => 2, :days => 5, :hours => 5, :minutes => 7, :seconds => 9)
end
+ def test_prev_week
+ with_env_tz 'US/Eastern' do
+ assert_equal Time.local(2005,2,21), Time.local(2005,3,1,15,15,10).prev_week
+ assert_equal Time.local(2005,2,22), Time.local(2005,3,1,15,15,10).prev_week(:tuesday)
+ assert_equal Time.local(2005,2,25), Time.local(2005,3,1,15,15,10).prev_week(:friday)
+ assert_equal Time.local(2006,10,30), Time.local(2006,11,6,0,0,0).prev_week
+ assert_equal Time.local(2006,11,15), Time.local(2006,11,23,0,0,0).prev_week(:wednesday)
+ end
+ end
+
def test_next_week
with_env_tz 'US/Eastern' do
assert_equal Time.local(2005,2,28), Time.local(2005,2,22,15,15,10).next_week
diff --git a/rails.gemspec b/rails.gemspec
index 2af30163a0..d791e21ec2 100644
--- a/rails.gemspec
+++ b/rails.gemspec
@@ -25,5 +25,5 @@ Gem::Specification.new do |s|
s.add_dependency('activeresource', version)
s.add_dependency('actionmailer', version)
s.add_dependency('railties', version)
- s.add_dependency('bundler', '~> 1.0.0')
+ s.add_dependency('bundler', '~> 1.0.3')
end
diff --git a/railties/CHANGELOG b/railties/CHANGELOG
index 5dd3a5108c..fdfdb5eef5 100644
--- a/railties/CHANGELOG
+++ b/railties/CHANGELOG
@@ -24,6 +24,10 @@
* Include all helpers from plugins and shared engines in application [Piotr Sarnacki]
+*Rails 3.0.1 (October 15, 2010)*
+
+* No Changes, just a version bump.
+
*Rails 3.0.0 (August 29, 2010)*
* Application generation: --skip-testunit and --skip-activerecord become --skip-test-unit and --skip-active-record respectively. [fxn]
diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile
index dfc4d38112..9b1d264d2c 100644
--- a/railties/guides/source/active_support_core_extensions.textile
+++ b/railties/guides/source/active_support_core_extensions.textile
@@ -2859,9 +2859,9 @@ d.end_of_week # => Sun, 09 May 2010
+beginning_of_week+ is aliased to +monday+ and +at_beginning_of_week+. +end_of_week+ is aliased to +sunday+ and +at_end_of_week+.
-h6. +next_week+
+h6. +prev_week+, +next_week+
-+next_week+ receives a symbol with a day name in English (in lowercase, default is +:monday+) and it returns the date corresponding to that day in the next week:
+The method +next_week+ receives a symbol with a day name in English (in lowercase, default is +:monday+) and it returns the date corresponding to that day:
<ruby>
d = Date.new(2010, 5, 9) # => Sun, 09 May 2010
@@ -2869,6 +2869,14 @@ d.next_week # => Mon, 10 May 2010
d.next_week(:saturday) # => Sat, 15 May 2010
</ruby>
+The method +prev_week+ is analogous:
+
+<ruby>
+d.prev_week # => Mon, 26 Apr 2010
+d.prev_week(:saturday) # => Sat, 01 May 2010
+d.prev_week(:friday) # => Fri, 30 Apr 2010
+</ruby>
+
h6. +beginning_of_month+, +end_of_month+
The methods +beginning_of_month+ and +end_of_month+ return the dates for the beginning and end of the month:
@@ -2946,6 +2954,15 @@ Date.new(2010, 4, 30).months_ago(2) # => Sun, 28 Feb 2010
Date.new(2009, 12, 31).months_since(2) # => Sun, 28 Feb 2010
</ruby>
+h6. +weeks_ago+
+
+The method +weeks_ago+ works analogously for weeks:
+
+<ruby>
+Date.new(2010, 5, 24).weeks_ago(1) # => Mon, 17 May 2010
+Date.new(2010, 5, 24).weeks_ago(2) # => Mon, 10 May 2010
+</ruby>
+
h6. +advance+
The most generic way to jump to other days is +advance+. This method receives a hash with keys +:years+, +:months+, +:weeks+, +:days+, and returns a date advanced as much as the present keys indicate:
@@ -3067,6 +3084,8 @@ yesterday
tomorrow
beginning_of_week (monday, at_beginning_of_week)
end_on_week (at_end_of_week)
+weeks_ago
+prev_week
next_week
months_ago
months_since
@@ -3239,6 +3258,8 @@ beginning_of_day (midnight, at_midnight, at_beginning_of_day)
end_of_day
beginning_of_week (monday, at_beginning_of_week)
end_on_week (at_end_of_week)
+weeks_ago
+prev_week
next_week
months_ago
months_since
diff --git a/railties/guides/source/association_basics.textile b/railties/guides/source/association_basics.textile
index 6996dab8c5..f6d61373e1 100644
--- a/railties/guides/source/association_basics.textile
+++ b/railties/guides/source/association_basics.textile
@@ -550,7 +550,7 @@ build_customer
create_customer
</ruby>
-h6(#belongs_to-association). <tt>_association_(force_reload = false)</tt>
+h6(#belongs_to-association). <tt><em>association</em>(force_reload = false)</tt>
The <tt><em>association</em></tt> method returns the associated object, if any. If no associated object is found, it returns +nil+.
diff --git a/railties/guides/source/command_line.textile b/railties/guides/source/command_line.textile
index cbdfda9215..752b5926f7 100644
--- a/railties/guides/source/command_line.textile
+++ b/railties/guides/source/command_line.textile
@@ -145,7 +145,7 @@ $ rails generate controller Greetings hello
What all did this generate? It made sure a bunch of directories were in our application, and created a controller file, a functional test file, a helper for the view, and a view file.
-Check out the controller and modify it a little (in +app/controllers/greetings_controller.rb+):ma
+Check out the controller and modify it a little (in +app/controllers/greetings_controller.rb+):
<ruby>
class GreetingsController < ApplicationController
diff --git a/railties/guides/source/initialization.textile b/railties/guides/source/initialization.textile
index 3e02bc0158..77c20c8bb0 100644
--- a/railties/guides/source/initialization.textile
+++ b/railties/guides/source/initialization.textile
@@ -141,7 +141,7 @@ Here the only two gems we need are +rails+ and +sqlite3-ruby+, so it seems. This
* activesupport-3.0.0.gem
* arel-0.4.0.gem
* builder-2.1.2.gem
-* bundler-1.0.0.gem
+* bundler-1.0.3.gem
* erubis-2.6.6.gem
* i18n-0.4.1.gem
* mail-2.2.5.gem
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index d13356ab4d..d84373cddf 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -147,7 +147,7 @@ module Rails
middleware.use ::Rack::Cache, rack_cache if rack_cache
middleware.use ::ActionDispatch::Static, config.static_asset_paths if config.serve_static_assets
- middleware.use ::Rack::Lock if !config.allow_concurrency
+ middleware.use ::Rack::Lock unless config.allow_concurrency
middleware.use ::Rack::Runtime
middleware.use ::Rails::Rack::Logger
middleware.use ::ActionDispatch::ShowExceptions, config.consider_all_requests_local if config.action_dispatch.show_exceptions
diff --git a/railties/lib/rails/backtrace_cleaner.rb b/railties/lib/rails/backtrace_cleaner.rb
index bedefaa51c..36fd9aea19 100644
--- a/railties/lib/rails/backtrace_cleaner.rb
+++ b/railties/lib/rails/backtrace_cleaner.rb
@@ -22,7 +22,7 @@ module Rails
gems_paths = (Gem.path + [Gem.default_dir]).uniq.map!{ |p| Regexp.escape(p) }
return if gems_paths.empty?
- gems_regexp = %r{(#{gems_paths.join('|')})/gems/([^/]+)-([\w\.]+)/(.*)}
+ gems_regexp = %r{(#{gems_paths.join('|')})/gems/([^/]+)-([\w.]+)/(.*)}
add_filter { |line| line.sub(gems_regexp, '\2 (\3) \4') }
end
end
diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb
index 25ca8c4758..72bfe207d7 100644
--- a/railties/lib/rails/engine.rb
+++ b/railties/lib/rails/engine.rb
@@ -335,29 +335,14 @@ module Rails
unless base.abstract_railtie?
base.called_from = begin
# Remove the line number from backtraces making sure we don't leave anything behind
- call_stack = caller.map { |p| p.split(':')[0..-2].join(':') }
- File.dirname(call_stack.detect { |p| p !~ %r[railties[\w\-\.]*/lib/rails|rack[\w\-\.]*/lib/rack] })
+ call_stack = caller.map { |p| p.sub(/:\d+.*/, '') }
+ File.dirname(call_stack.detect { |p| p !~ %r[railties[\w.-]*/lib/rails|rack[\w.-]*/lib/rack] })
end
end
super
end
- def find_root_with_flag(flag, default=nil)
- root_path = self.called_from
-
- while root_path && File.directory?(root_path) && !File.exist?("#{root_path}/#{flag}")
- parent = File.dirname(root_path)
- root_path = parent != root_path && parent
- end
-
- root = File.exist?("#{root_path}/#{flag}") ? root_path : default
- raise "Could not find root path for #{self}" unless root
-
- RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ ?
- Pathname.new(root).expand_path : Pathname.new(root).realpath
- end
-
def endpoint(endpoint = nil)
@endpoint = endpoint if endpoint
@endpoint
diff --git a/railties/lib/rails/generators/rails/app/templates/public/javascripts/jquery.js b/railties/lib/rails/generators/rails/app/templates/public/javascripts/jquery.js
index 109701084e..ad9a79c433 100644
--- a/railties/lib/rails/generators/rails/app/templates/public/javascripts/jquery.js
+++ b/railties/lib/rails/generators/rails/app/templates/public/javascripts/jquery.js
@@ -1,5 +1,5 @@
/*!
- * jQuery JavaScript Library v1.4.1
+ * jQuery JavaScript Library v1.4.3
* http://jquery.com/
*
* Copyright 2010, John Resig
@@ -11,10 +11,14 @@
* Copyright 2010, The Dojo Foundation
* Released under the MIT, BSD, and GPL Licenses.
*
- * Date: Mon Jan 25 19:43:33 2010 -0500
+ * Date: Thu Oct 14 23:10:06 2010 -0400
*/
(function( window, undefined ) {
+// Use the correct document accordingly with window argument (sandbox)
+var document = window.document;
+var jQuery = (function() {
+
// Define a local copy of jQuery
var jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
@@ -27,28 +31,45 @@ var jQuery = function( selector, context ) {
// Map over the $ in case of overwrite
_$ = window.$,
- // Use the correct document accordingly with window argument (sandbox)
- document = window.document,
-
// A central reference to the root jQuery(document)
rootjQuery,
// A simple way to check for HTML strings or ID strings
// (both of which we optimize for)
- quickExpr = /^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,
+ quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,
// Is it a simple selector
isSimple = /^.[^:#\[\.,]*$/,
// Check if a string has a non-whitespace character in it
rnotwhite = /\S/,
+ rwhite = /\s/,
// Used for trimming whitespace
- rtrim = /^(\s|\u00A0)+|(\s|\u00A0)+$/g,
+ trimLeft = /^\s+/,
+ trimRight = /\s+$/,
+
+ // Check for non-word characters
+ rnonword = /\W/,
+
+ // Check for digits
+ rdigit = /\d/,
// Match a standalone tag
rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,
+ // JSON RegExp
+ rvalidchars = /^[\],:{}\s]*$/,
+ rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
+ rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
+ rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
+
+ // Useragent RegExp
+ rwebkit = /(webkit)[ \/]([\w.]+)/,
+ ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/,
+ rmsie = /(msie) ([\w.]+)/,
+ rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/,
+
// Keep a UserAgent string for use with jQuery.browser
userAgent = navigator.userAgent,
@@ -66,10 +87,14 @@ var jQuery = function( selector, context ) {
// Save a reference to some core methods
toString = Object.prototype.toString,
- hasOwnProperty = Object.prototype.hasOwnProperty,
+ hasOwn = Object.prototype.hasOwnProperty,
push = Array.prototype.push,
slice = Array.prototype.slice,
- indexOf = Array.prototype.indexOf;
+ trim = String.prototype.trim,
+ indexOf = Array.prototype.indexOf,
+
+ // [[Class]] -> type pairs
+ class2type = {};
jQuery.fn = jQuery.prototype = {
init: function( selector, context ) {
@@ -86,6 +111,15 @@ jQuery.fn = jQuery.prototype = {
this.length = 1;
return this;
}
+
+ // The body element only exists once, optimize finding it
+ if ( selector === "body" && !context && document.body ) {
+ this.context = document;
+ this[0] = document.body;
+ this.selector = "body";
+ this.length = 1;
+ return this;
+ }
// Handle HTML strings
if ( typeof selector === "string" ) {
@@ -113,15 +147,19 @@ jQuery.fn = jQuery.prototype = {
}
} else {
- ret = buildFragment( [ match[1] ], [ doc ] );
+ ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
selector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes;
}
-
+
+ return jQuery.merge( this, selector );
+
// HANDLE: $("#id")
} else {
elem = document.getElementById( match[2] );
- if ( elem ) {
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ if ( elem && elem.parentNode ) {
// Handle the case where IE and Opera return items
// by name instead of ID
if ( elem.id !== match[2] ) {
@@ -139,10 +177,11 @@ jQuery.fn = jQuery.prototype = {
}
// HANDLE: $("TAG")
- } else if ( !context && /^\w+$/.test( selector ) ) {
+ } else if ( !context && !rnonword.test( selector ) ) {
this.selector = selector;
this.context = document;
selector = document.getElementsByTagName( selector );
+ return jQuery.merge( this, selector );
// HANDLE: $(expr, $(...))
} else if ( !context || context.jquery ) {
@@ -165,16 +204,14 @@ jQuery.fn = jQuery.prototype = {
this.context = selector.context;
}
- return jQuery.isArray( selector ) ?
- this.setArray( selector ) :
- jQuery.makeArray( selector, this );
+ return jQuery.makeArray( selector, this );
},
// Start with an empty selector
selector: "",
// The current version of jQuery being used
- jquery: "1.4.1",
+ jquery: "1.4.3",
// The default length of a jQuery object is 0
length: 0,
@@ -204,7 +241,14 @@ jQuery.fn = jQuery.prototype = {
// (returning the new matched element set)
pushStack: function( elems, name, selector ) {
// Build a new jQuery matched element set
- var ret = jQuery( elems || null );
+ var ret = jQuery();
+
+ if ( jQuery.isArray( elems ) ) {
+ push.apply( ret, elems );
+
+ } else {
+ jQuery.merge( ret, elems );
+ }
// Add the old object onto the stack (as a reference)
ret.prevObject = this;
@@ -221,18 +265,6 @@ jQuery.fn = jQuery.prototype = {
return ret;
},
- // Force the current matched set of elements to become
- // the specified array of elements (destroying the stack in the process)
- // You should use pushStack() in order to do this, but maintain the stack
- setArray: function( elems ) {
- // Resetting the length to 0, then using the native Array push
- // is a super-fast way to populate an object with array-like properties
- this.length = 0;
- push.apply( this, elems );
-
- return this;
- },
-
// Execute a callback for every element in the matched set.
// (You can seed the arguments with an array of args, but this is
// only used internally.)
@@ -299,7 +331,7 @@ jQuery.fn.init.prototype = jQuery.fn;
jQuery.extend = jQuery.fn.extend = function() {
// copy reference to target object
- var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options, name, src, copy;
+ var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options, name, src, copy, copyIsArray;
// Handle a deep copy situation
if ( typeof target === "boolean" ) {
@@ -333,10 +365,15 @@ jQuery.extend = jQuery.fn.extend = function() {
continue;
}
- // Recurse if we're merging object literal values or arrays
- if ( deep && copy && ( jQuery.isPlainObject(copy) || jQuery.isArray(copy) ) ) {
- var clone = src && ( jQuery.isPlainObject(src) || jQuery.isArray(src) ) ? src
- : jQuery.isArray(copy) ? [] : {};
+ // Recurse if we're merging plain objects or arrays
+ if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
+ if ( copyIsArray ) {
+ copyIsArray = false;
+ clone = src && jQuery.isArray(src) ? src : [];
+
+ } else {
+ clone = src && jQuery.isPlainObject(src) ? src : {};
+ }
// Never move original objects, clone them
target[ name ] = jQuery.extend( deep, clone, copy );
@@ -366,19 +403,33 @@ jQuery.extend({
// Is the DOM ready to be used? Set to true once it occurs.
isReady: false,
+
+ // A counter to track how many items to wait for before
+ // the ready event fires. See #6781
+ readyWait: 1,
// Handle when the DOM is ready
- ready: function() {
+ ready: function( wait ) {
+ // A third-party is pushing the ready event forwards
+ if ( wait === true ) {
+ jQuery.readyWait--;
+ }
+
// Make sure that the DOM is not already loaded
- if ( !jQuery.isReady ) {
+ if ( !jQuery.readyWait || (wait !== true && !jQuery.isReady) ) {
// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
if ( !document.body ) {
- return setTimeout( jQuery.ready, 13 );
+ return setTimeout( jQuery.ready, 1 );
}
// Remember that the DOM is ready
jQuery.isReady = true;
+ // If a normal DOM Ready event fired, decrement, and wait if need be
+ if ( wait !== true && --jQuery.readyWait > 0 ) {
+ return;
+ }
+
// If there are functions bound, to execute
if ( readyList ) {
// Execute all of them
@@ -408,7 +459,8 @@ jQuery.extend({
// Catch cases where $(document).ready() is called after the
// browser event has already occurred.
if ( document.readyState === "complete" ) {
- return jQuery.ready();
+ // Handle it asynchronously to allow scripts the opportunity to delay ready
+ return setTimeout( jQuery.ready, 1 );
}
// Mozilla, Opera and webkit nightlies currently support this event
@@ -446,25 +498,40 @@ jQuery.extend({
// Since version 1.3, DOM methods and functions like alert
// aren't supported. They return false on IE (#2968).
isFunction: function( obj ) {
- return toString.call(obj) === "[object Function]";
+ return jQuery.type(obj) === "function";
+ },
+
+ isArray: Array.isArray || function( obj ) {
+ return jQuery.type(obj) === "array";
+ },
+
+ // A crude way of determining if an object is a window
+ isWindow: function( obj ) {
+ return obj && typeof obj === "object" && "setInterval" in obj;
+ },
+
+ isNaN: function( obj ) {
+ return obj == null || !rdigit.test( obj ) || isNaN( obj );
},
- isArray: function( obj ) {
- return toString.call(obj) === "[object Array]";
+ type: function( obj ) {
+ return obj == null ?
+ String( obj ) :
+ class2type[ toString.call(obj) ] || "object";
},
isPlainObject: function( obj ) {
// Must be an Object.
// Because of IE, we also have to check the presence of the constructor property.
// Make sure that DOM nodes and window objects don't pass through, as well
- if ( !obj || toString.call(obj) !== "[object Object]" || obj.nodeType || obj.setInterval ) {
+ if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
return false;
}
// Not own constructor property must be Object
- if ( obj.constructor
- && !hasOwnProperty.call(obj, "constructor")
- && !hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf") ) {
+ if ( obj.constructor &&
+ !hasOwn.call(obj, "constructor") &&
+ !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
return false;
}
@@ -474,7 +541,7 @@ jQuery.extend({
var key;
for ( key in obj ) {}
- return key === undefined || hasOwnProperty.call( obj, key );
+ return key === undefined || hasOwn.call( obj, key );
},
isEmptyObject: function( obj ) {
@@ -492,12 +559,15 @@ jQuery.extend({
if ( typeof data !== "string" || !data ) {
return null;
}
+
+ // Make sure leading/trailing whitespace is removed (IE can't handle it)
+ data = jQuery.trim( data );
// Make sure the incoming data is actual JSON
// Logic borrowed from http://json.org/json2.js
- if ( /^[\],:{}\s]*$/.test(data.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, "@")
- .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, "]")
- .replace(/(?:^|:|,)(?:\s*\[)+/g, "")) ) {
+ if ( rvalidchars.test(data.replace(rvalidescape, "@")
+ .replace(rvalidtokens, "]")
+ .replace(rvalidbraces, "")) ) {
// Try to use the native JSON parser first
return window.JSON && window.JSON.parse ?
@@ -576,9 +646,20 @@ jQuery.extend({
return object;
},
- trim: function( text ) {
- return (text || "").replace( rtrim, "" );
- },
+ // Use native String.trim function wherever possible
+ trim: trim ?
+ function( text ) {
+ return text == null ?
+ "" :
+ trim.call( text );
+ } :
+
+ // Otherwise use our own trimming functionality
+ function( text ) {
+ return text == null ?
+ "" :
+ text.toString().replace( trimLeft, "" ).replace( trimRight, "" );
+ },
// results is for internal usage only
makeArray: function( array, results ) {
@@ -588,7 +669,10 @@ jQuery.extend({
// The window, strings (and functions) also have 'length'
// The extra typeof function check is to prevent crashes
// in Safari 2 (See: #3039)
- if ( array.length == null || typeof array === "string" || jQuery.isFunction(array) || (typeof array !== "function" && array.setInterval) ) {
+ // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
+ var type = jQuery.type(array);
+
+ if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) {
push.call( ret, array );
} else {
jQuery.merge( ret, array );
@@ -619,6 +703,7 @@ jQuery.extend({
for ( var l = second.length; j < l; j++ ) {
first[ i++ ] = second[ j ];
}
+
} else {
while ( second[j] !== undefined ) {
first[ i++ ] = second[ j++ ];
@@ -631,12 +716,14 @@ jQuery.extend({
},
grep: function( elems, callback, inv ) {
- var ret = [];
+ var ret = [], retVal;
+ inv = !!inv;
// Go through the array, only saving the items
// that pass the validator function
for ( var i = 0, length = elems.length; i < length; i++ ) {
- if ( !inv !== !callback( elems[ i ], i ) ) {
+ retVal = !!callback( elems[ i ], i );
+ if ( inv !== retVal ) {
ret.push( elems[ i ] );
}
}
@@ -692,16 +779,49 @@ jQuery.extend({
return proxy;
},
+ // Mutifunctional method to get and set values to a collection
+ // The value/s can be optionally by executed if its a function
+ access: function( elems, key, value, exec, fn, pass ) {
+ var length = elems.length;
+
+ // Setting many attributes
+ if ( typeof key === "object" ) {
+ for ( var k in key ) {
+ jQuery.access( elems, k, key[k], exec, fn, value );
+ }
+ return elems;
+ }
+
+ // Setting one attribute
+ if ( value !== undefined ) {
+ // Optionally, function values get executed if exec is true
+ exec = !pass && exec && jQuery.isFunction(value);
+
+ for ( var i = 0; i < length; i++ ) {
+ fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
+ }
+
+ return elems;
+ }
+
+ // Getting an attribute
+ return length ? fn( elems[0], key ) : undefined;
+ },
+
+ now: function() {
+ return (new Date()).getTime();
+ },
+
// Use of jQuery.browser is frowned upon.
// More details: http://docs.jquery.com/Utilities/jQuery.browser
uaMatch: function( ua ) {
ua = ua.toLowerCase();
- var match = /(webkit)[ \/]([\w.]+)/.exec( ua ) ||
- /(opera)(?:.*version)?[ \/]([\w.]+)/.exec( ua ) ||
- /(msie) ([\w.]+)/.exec( ua ) ||
- !/compatible/.test( ua ) && /(mozilla)(?:.*? rv:([\w.]+))?/.exec( ua ) ||
- [];
+ var match = rwebkit.exec( ua ) ||
+ ropera.exec( ua ) ||
+ rmsie.exec( ua ) ||
+ ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
+ [];
return { browser: match[1] || "", version: match[2] || "0" };
},
@@ -709,6 +829,11 @@ jQuery.extend({
browser: {}
});
+// Populate the class2type map
+jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
+ class2type[ "[object " + name + "]" ] = name.toLowerCase();
+});
+
browserMatch = jQuery.uaMatch( userAgent );
if ( browserMatch.browser ) {
jQuery.browser[ browserMatch.browser ] = true;
@@ -726,6 +851,13 @@ if ( indexOf ) {
};
}
+// Verify that \s matches non-breaking spaces
+// (IE fails on this test)
+if ( !rwhite.test( "\xA0" ) ) {
+ trimLeft = /^[\s\xA0]+/;
+ trimRight = /[\s\xA0]+$/;
+}
+
// All jQuery objects should point back to these
rootjQuery = jQuery(document);
@@ -756,7 +888,7 @@ function doScrollCheck() {
// If IE is used, use the trick by Diego Perini
// http://javascript.nwbox.com/IEContentLoaded/
document.documentElement.doScroll("left");
- } catch( error ) {
+ } catch(e) {
setTimeout( doScrollCheck, 1 );
return;
}
@@ -765,54 +897,12 @@ function doScrollCheck() {
jQuery.ready();
}
-function evalScript( i, elem ) {
- if ( elem.src ) {
- jQuery.ajax({
- url: elem.src,
- async: false,
- dataType: "script"
- });
- } else {
- jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );
- }
+// Expose jQuery to the global object
+return (window.jQuery = window.$ = jQuery);
- if ( elem.parentNode ) {
- elem.parentNode.removeChild( elem );
- }
-}
+})();
-// Mutifunctional method to get and set values to a collection
-// The value/s can be optionally by executed if its a function
-function access( elems, key, value, exec, fn, pass ) {
- var length = elems.length;
-
- // Setting many attributes
- if ( typeof key === "object" ) {
- for ( var k in key ) {
- access( elems, k, key[k], exec, fn, value );
- }
- return elems;
- }
-
- // Setting one attribute
- if ( value !== undefined ) {
- // Optionally, function values get executed if exec is true
- exec = !pass && exec && jQuery.isFunction(value);
-
- for ( var i = 0; i < length; i++ ) {
- fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
- }
-
- return elems;
- }
-
- // Getting an attribute
- return length ? fn( elems[0], key ) : null;
-}
-function now() {
- return (new Date).getTime();
-}
(function() {
jQuery.support = {};
@@ -820,13 +910,15 @@ function now() {
var root = document.documentElement,
script = document.createElement("script"),
div = document.createElement("div"),
- id = "script" + now();
+ id = "script" + jQuery.now();
div.style.display = "none";
div.innerHTML = " <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
var all = div.getElementsByTagName("*"),
- a = div.getElementsByTagName("a")[0];
+ a = div.getElementsByTagName("a")[0],
+ select = document.createElement("select"),
+ opt = select.appendChild( document.createElement("option") );
// Can't get basic test support
if ( !all || !all.length || !a ) {
@@ -869,15 +961,24 @@ function now() {
// Make sure that a selected-by-default option has a working selected property.
// (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
- optSelected: document.createElement("select").appendChild( document.createElement("option") ).selected,
+ optSelected: opt.selected,
// Will be defined later
+ optDisabled: false,
checkClone: false,
scriptEval: false,
noCloneEvent: true,
- boxModel: null
+ boxModel: null,
+ inlineBlockNeedsLayout: false,
+ shrinkWrapBlocks: false,
+ reliableHiddenOffsets: true
};
+ // Make sure that the options inside disabled selects aren't marked as disabled
+ // (WebKit marks them as diabled)
+ select.disabled = true;
+ jQuery.support.optDisabled = !opt.disabled;
+
script.type = "text/javascript";
try {
script.appendChild( document.createTextNode( "window." + id + "=1;" ) );
@@ -922,26 +1023,63 @@ function now() {
document.body.appendChild( div );
jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2;
- document.body.removeChild( div ).style.display = 'none';
- div = null;
+
+ if ( "zoom" in div.style ) {
+ // Check if natively block-level elements act like inline-block
+ // elements when setting their display to 'inline' and giving
+ // them layout
+ // (IE < 8 does this)
+ div.style.display = "inline";
+ div.style.zoom = 1;
+ jQuery.support.inlineBlockNeedsLayout = div.offsetWidth === 2;
+
+ // Check if elements with layout shrink-wrap their children
+ // (IE 6 does this)
+ div.style.display = "";
+ div.innerHTML = "<div style='width:4px;'></div>";
+ jQuery.support.shrinkWrapBlocks = div.offsetWidth !== 2;
+ }
+
+ div.innerHTML = "<table><tr><td style='padding:0;display:none'></td><td>t</td></tr></table>";
+ var tds = div.getElementsByTagName("td");
+
+ // Check if table cells still have offsetWidth/Height when they are set
+ // to display:none and there are still other visible table cells in a
+ // table row; if so, offsetWidth/Height are not reliable for use when
+ // determining if an element has been hidden directly using
+ // display:none (it is still safe to use offsets if a parent element is
+ // hidden; don safety goggles and see bug #4512 for more information).
+ // (only IE 8 fails this test)
+ jQuery.support.reliableHiddenOffsets = tds[0].offsetHeight === 0;
+
+ tds[0].style.display = "";
+ tds[1].style.display = "none";
+
+ // Check if empty table cells still have offsetWidth/Height
+ // (IE < 8 fail this test)
+ jQuery.support.reliableHiddenOffsets = jQuery.support.reliableHiddenOffsets && tds[0].offsetHeight === 0;
+ div.innerHTML = "";
+
+ document.body.removeChild( div ).style.display = "none";
+ div = tds = null;
});
// Technique from Juriy Zaytsev
// http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
- var eventSupported = function( eventName ) {
- var el = document.createElement("div");
- eventName = "on" + eventName;
-
- var isSupported = (eventName in el);
- if ( !isSupported ) {
- el.setAttribute(eventName, "return;");
- isSupported = typeof el[eventName] === "function";
- }
- el = null;
-
- return isSupported;
+ var eventSupported = function( eventName ) {
+ var el = document.createElement("div");
+ eventName = "on" + eventName;
+
+ var isSupported = (eventName in el);
+ if ( !isSupported ) {
+ el.setAttribute(eventName, "return;");
+ isSupported = typeof el[eventName] === "function";
+ }
+ el = null;
+
+ return isSupported;
};
-
+
jQuery.support.submitBubbles = eventSupported("submit");
jQuery.support.changeBubbles = eventSupported("change");
@@ -961,24 +1099,33 @@ jQuery.props = {
usemap: "useMap",
frameborder: "frameBorder"
};
-var expando = "jQuery" + now(), uuid = 0, windowData = {};
-var emptyObject = {};
+
+
+
+
+var windowData = {},
+ rbrace = /^(?:\{.*\}|\[.*\])$/;
jQuery.extend({
cache: {},
-
- expando:expando,
+
+ // Please use with caution
+ uuid: 0,
+
+ // Unique for each copy of jQuery on the page
+ expando: "jQuery" + jQuery.now(),
// The following elements throw uncatchable exceptions if you
// attempt to add expando properties to them.
noData: {
"embed": true,
- "object": true,
+ // Ban all objects except for Flash (which handle expandos)
+ "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
"applet": true
},
data: function( elem, name, data ) {
- if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
+ if ( !jQuery.acceptData( elem ) ) {
return;
}
@@ -986,34 +1133,41 @@ jQuery.extend({
windowData :
elem;
- var id = elem[ expando ], cache = jQuery.cache, thisCache;
+ var isNode = elem.nodeType,
+ id = isNode ? elem[ jQuery.expando ] : null,
+ cache = jQuery.cache, thisCache;
- // Handle the case where there's no name immediately
- if ( !name && !id ) {
- return null;
+ if ( isNode && !id && typeof name === "string" && data === undefined ) {
+ return;
}
+ // Get the data from the object directly
+ if ( !isNode ) {
+ cache = elem;
+
// Compute a unique ID for the element
- if ( !id ) {
- id = ++uuid;
+ } else if ( !id ) {
+ elem[ jQuery.expando ] = id = ++jQuery.uuid;
}
// Avoid generating a new cache unless none exists and we
// want to manipulate it.
if ( typeof name === "object" ) {
- elem[ expando ] = id;
- thisCache = cache[ id ] = jQuery.extend(true, {}, name);
- } else if ( cache[ id ] ) {
- thisCache = cache[ id ];
- } else if ( typeof data === "undefined" ) {
- thisCache = emptyObject;
- } else {
- thisCache = cache[ id ] = {};
+ if ( isNode ) {
+ cache[ id ] = jQuery.extend(cache[ id ], name);
+
+ } else {
+ jQuery.extend( cache, name );
+ }
+
+ } else if ( isNode && !cache[ id ] ) {
+ cache[ id ] = {};
}
+ thisCache = isNode ? cache[ id ] : cache;
+
// Prevent overriding the named cache with undefined values
if ( data !== undefined ) {
- elem[ expando ] = id;
thisCache[ name ] = data;
}
@@ -1021,7 +1175,7 @@ jQuery.extend({
},
removeData: function( elem, name ) {
- if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
+ if ( !jQuery.acceptData( elem ) ) {
return;
}
@@ -1029,7 +1183,10 @@ jQuery.extend({
windowData :
elem;
- var id = elem[ expando ], cache = jQuery.cache, thisCache = cache[ id ];
+ var isNode = elem.nodeType,
+ id = isNode ? elem[ jQuery.expando ] : elem,
+ cache = jQuery.cache,
+ thisCache = isNode ? cache[ id ] : id;
// If we want to remove a specific section of the element's data
if ( name ) {
@@ -1038,34 +1195,50 @@ jQuery.extend({
delete thisCache[ name ];
// If we've removed all the data, remove the element's cache
- if ( jQuery.isEmptyObject(thisCache) ) {
+ if ( isNode && jQuery.isEmptyObject(thisCache) ) {
jQuery.removeData( elem );
}
}
// Otherwise, we want to remove all of the element's data
} else {
- // Clean up the element expando
- try {
- delete elem[ expando ];
- } catch( e ) {
- // IE has trouble directly removing the expando
- // but it's ok with using removeAttribute
- if ( elem.removeAttribute ) {
- elem.removeAttribute( expando );
+ if ( isNode && jQuery.support.deleteExpando ) {
+ delete elem[ jQuery.expando ];
+
+ } else if ( elem.removeAttribute ) {
+ elem.removeAttribute( jQuery.expando );
+
+ // Completely remove the data cache
+ } else if ( isNode ) {
+ delete cache[ id ];
+
+ // Remove all fields from the object
+ } else {
+ for ( var n in elem ) {
+ delete elem[ n ];
}
}
+ }
+ },
- // Completely remove the data cache
- delete cache[ id ];
+ // A method for determining if a DOM node can handle the data expando
+ acceptData: function( elem ) {
+ if ( elem.nodeName ) {
+ var match = jQuery.noData[ elem.nodeName.toLowerCase() ];
+
+ if ( match ) {
+ return !(match === true || elem.getAttribute("classid") !== match);
+ }
}
+
+ return true;
}
});
jQuery.fn.extend({
data: function( key, value ) {
- if ( typeof key === "undefined" && this.length ) {
- return jQuery.data( this[0] );
+ if ( typeof key === "undefined" ) {
+ return this.length ? jQuery.data( this[0] ) : null;
} else if ( typeof key === "object" ) {
return this.each(function() {
@@ -1079,15 +1252,42 @@ jQuery.fn.extend({
if ( value === undefined ) {
var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
+ // Try to fetch any internally stored data first
if ( data === undefined && this.length ) {
data = jQuery.data( this[0], key );
+
+ // If nothing was found internally, try to fetch any
+ // data from the HTML5 data-* attribute
+ if ( data === undefined && this[0].nodeType === 1 ) {
+ data = this[0].getAttribute( "data-" + key );
+
+ if ( typeof data === "string" ) {
+ try {
+ data = data === "true" ? true :
+ data === "false" ? false :
+ data === "null" ? null :
+ !jQuery.isNaN( data ) ? parseFloat( data ) :
+ rbrace.test( data ) ? jQuery.parseJSON( data ) :
+ data;
+ } catch( e ) {}
+
+ } else {
+ data = undefined;
+ }
+ }
}
+
return data === undefined && parts[1] ?
this.data( parts[0] ) :
data;
+
} else {
- return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function() {
+ return this.each(function() {
+ var $this = jQuery( this ), args = [ parts[0], value ];
+
+ $this.triggerHandler( "setData" + parts[1] + "!", args );
jQuery.data( this, key, value );
+ $this.triggerHandler( "changeData" + parts[1] + "!", args );
});
}
},
@@ -1098,6 +1298,10 @@ jQuery.fn.extend({
});
}
});
+
+
+
+
jQuery.extend({
queue: function( elem, type, data ) {
if ( !elem ) {
@@ -1156,7 +1360,7 @@ jQuery.fn.extend({
if ( data === undefined ) {
return jQuery.queue( this[0], type );
}
- return this.each(function( i, elem ) {
+ return this.each(function( i ) {
var queue = jQuery.queue( this, type, data );
if ( type === "fx" && queue[0] !== "inprogress" ) {
@@ -1188,18 +1392,22 @@ jQuery.fn.extend({
return this.queue( type || "fx", [] );
}
});
+
+
+
+
var rclass = /[\n\t]/g,
- rspace = /\s+/,
+ rspaces = /\s+/,
rreturn = /\r/g,
- rspecialurl = /href|src|style/,
- rtype = /(button|input)/i,
- rfocusable = /(button|input|object|select|textarea)/i,
- rclickable = /^(a|area)$/i,
- rradiocheck = /radio|checkbox/;
+ rspecialurl = /^(?:href|src|style)$/,
+ rtype = /^(?:button|input)$/i,
+ rfocusable = /^(?:button|input|object|select|textarea)$/i,
+ rclickable = /^a(?:rea)?$/i,
+ rradiocheck = /^(?:radio|checkbox)$/i;
jQuery.fn.extend({
attr: function( name, value ) {
- return access( this, name, value, true, jQuery.attr );
+ return jQuery.access( this, name, value, true, jQuery.attr );
},
removeAttr: function( name, fn ) {
@@ -1220,7 +1428,7 @@ jQuery.fn.extend({
}
if ( value && typeof value === "string" ) {
- var classNames = (value || "").split( rspace );
+ var classNames = (value || "").split( rspaces );
for ( var i = 0, l = this.length; i < l; i++ ) {
var elem = this[i];
@@ -1230,12 +1438,13 @@ jQuery.fn.extend({
elem.className = value;
} else {
- var className = " " + elem.className + " ";
+ var className = " " + elem.className + " ", setClass = elem.className;
for ( var c = 0, cl = classNames.length; c < cl; c++ ) {
if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) {
- elem.className += " " + classNames[c];
+ setClass += " " + classNames[c];
}
}
+ elem.className = jQuery.trim( setClass );
}
}
}
@@ -1253,7 +1462,7 @@ jQuery.fn.extend({
}
if ( (value && typeof value === "string") || value === undefined ) {
- var classNames = (value || "").split(rspace);
+ var classNames = (value || "").split( rspaces );
for ( var i = 0, l = this.length; i < l; i++ ) {
var elem = this[i];
@@ -1264,7 +1473,7 @@ jQuery.fn.extend({
for ( var c = 0, cl = classNames.length; c < cl; c++ ) {
className = className.replace(" " + classNames[c] + " ", " ");
}
- elem.className = className.substring(1, className.length - 1);
+ elem.className = jQuery.trim( className );
} else {
elem.className = "";
@@ -1291,7 +1500,7 @@ jQuery.fn.extend({
// toggle individual class names
var className, i = 0, self = jQuery(this),
state = stateVal,
- classNames = value.split( rspace );
+ classNames = value.split( rspaces );
while ( (className = classNames[ i++ ]) ) {
// check each className given, space seperated list
@@ -1323,12 +1532,15 @@ jQuery.fn.extend({
},
val: function( value ) {
- if ( value === undefined ) {
+ if ( !arguments.length ) {
var elem = this[0];
if ( elem ) {
if ( jQuery.nodeName( elem, "option" ) ) {
- return (elem.attributes.value || {}).specified ? elem.value : elem.text;
+ // attributes.value is undefined in Blackberry 4.7 but
+ // uses .value. See #6932
+ var val = elem.attributes.value;
+ return !val || val.specified ? elem.value : elem.text;
}
// We need to handle select boxes special
@@ -1347,8 +1559,11 @@ jQuery.fn.extend({
for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
var option = options[ i ];
- if ( option.selected ) {
- // Get the specifc value for the option
+ // Don't return options that are disabled or in a disabled optgroup
+ if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) &&
+ (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) {
+
+ // Get the specific value for the option
value = jQuery(option).val();
// We don't need an array for one selects
@@ -1391,10 +1606,15 @@ jQuery.fn.extend({
val = value.call(this, i, self.val());
}
- // Typecast each time if the value is a Function and the appended
- // value is therefore different each time.
- if ( typeof val === "number" ) {
+ // Treat null/undefined as ""; convert numbers to string
+ if ( val == null ) {
+ val = "";
+ } else if ( typeof val === "number" ) {
val += "";
+ } else if ( jQuery.isArray(val) ) {
+ val = jQuery.map(val, function (value) {
+ return value == null ? "" : value + "";
+ });
}
if ( jQuery.isArray(val) && rradiocheck.test( this.type ) ) {
@@ -1467,14 +1687,22 @@ jQuery.extend({
}
// If applicable, access the attribute via the DOM 0 way
- if ( name in elem && notxml && !special ) {
+ // 'in' checks fail in Blackberry 4.7 #6931
+ if ( (name in elem || elem[ name ] !== undefined) && notxml && !special ) {
if ( set ) {
// We can't allow the type property to be changed (since it causes problems in IE)
if ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) {
jQuery.error( "type property can't be changed" );
}
- elem[ name ] = value;
+ if ( value === null ) {
+ if ( elem.nodeType === 1 ) {
+ elem.removeAttribute( name );
+ }
+
+ } else {
+ elem[ name ] = value;
+ }
}
// browsers index elements by id/name on forms, give priority to attributes.
@@ -1510,6 +1738,12 @@ jQuery.extend({
elem.setAttribute( name, "" + value );
}
+ // Ensure that missing attributes return undefined
+ // Blackberry 4.7 returns "" from getAttribute #6938
+ if ( !elem.attributes[ name ] && (elem.hasAttribute && !elem.hasAttribute( name )) ) {
+ return undefined;
+ }
+
var attr = !jQuery.support.hrefNormalized && notxml && special ?
// Some attributes require a special call on IE
elem.getAttribute( name, 2 ) :
@@ -1518,17 +1752,21 @@ jQuery.extend({
// Non-existent attributes return null, we normalize to undefined
return attr === null ? undefined : attr;
}
-
- // elem is actually elem.style ... set the style
- // Using attr for specific style information is now deprecated. Use style insead.
- return jQuery.style( elem, name, value );
}
});
-var fcleanup = function( nm ) {
- return nm.replace(/[^\w\s\.\|`]/g, function( ch ) {
- return "\\" + ch;
- });
-};
+
+
+
+
+var rnamespaces = /\.(.*)$/,
+ rformElems = /^(?:textarea|input|select)$/i,
+ rperiod = /\./g,
+ rspace = / /g,
+ rescape = /[^\w\s.|`]/g,
+ fcleanup = function( nm ) {
+ return nm.replace(rescape, "\\$&");
+ },
+ focusCounts = { focusin: 0, focusout: 0 };
/*
* A number of helper functions used for managing events.
@@ -1546,111 +1784,134 @@ jQuery.event = {
// For whatever reason, IE has trouble passing the window object
// around, causing it to be cloned in the process
- if ( elem.setInterval && ( elem !== window && !elem.frameElement ) ) {
+ if ( jQuery.isWindow( elem ) && ( elem !== window && !elem.frameElement ) ) {
elem = window;
}
+ if ( handler === false ) {
+ handler = returnFalse;
+ }
+
+ var handleObjIn, handleObj;
+
+ if ( handler.handler ) {
+ handleObjIn = handler;
+ handler = handleObjIn.handler;
+ }
+
// Make sure that the function being executed has a unique ID
if ( !handler.guid ) {
handler.guid = jQuery.guid++;
}
- // if data is passed, bind to handler
- if ( data !== undefined ) {
- // Create temporary function pointer to original handler
- var fn = handler;
-
- // Create unique handler function, wrapped around original handler
- handler = jQuery.proxy( fn );
+ // Init the element's event structure
+ var elemData = jQuery.data( elem );
- // Store data in unique handler
- handler.data = data;
+ // If no elemData is found then we must be trying to bind to one of the
+ // banned noData elements
+ if ( !elemData ) {
+ return;
}
- // Init the element's event structure
- var events = jQuery.data( elem, "events" ) || jQuery.data( elem, "events", {} ),
- handle = jQuery.data( elem, "handle" ), eventHandle;
+ // Use a key less likely to result in collisions for plain JS objects.
+ // Fixes bug #7150.
+ var eventKey = elem.nodeType ? "events" : "__events__",
+ events = elemData[ eventKey ],
+ eventHandle = elemData.handle;
+
+ if ( typeof events === "function" ) {
+ // On plain objects events is a fn that holds the the data
+ // which prevents this data from being JSON serialized
+ // the function does not need to be called, it just contains the data
+ eventHandle = events.handle;
+ events = events.events;
- if ( !handle ) {
- eventHandle = function() {
+ } else if ( !events ) {
+ if ( !elem.nodeType ) {
+ // On plain objects, create a fn that acts as the holder
+ // of the values to avoid JSON serialization of event data
+ elemData[ eventKey ] = elemData = function(){};
+ }
+
+ elemData.events = events = {};
+ }
+
+ if ( !eventHandle ) {
+ elemData.handle = eventHandle = function() {
// Handle the second event of a trigger and when
// an event is called after a page has unloaded
return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
jQuery.event.handle.apply( eventHandle.elem, arguments ) :
undefined;
};
-
- handle = jQuery.data( elem, "handle", eventHandle );
- }
-
- // If no handle is found then we must be trying to bind to one of the
- // banned noData elements
- if ( !handle ) {
- return;
}
// Add elem as a property of the handle function
- // This is to prevent a memory leak with non-native
- // event in IE.
- handle.elem = elem;
+ // This is to prevent a memory leak with non-native events in IE.
+ eventHandle.elem = elem;
// Handle multiple events separated by a space
// jQuery(...).bind("mouseover mouseout", fn);
- types = types.split( /\s+/ );
+ types = types.split(" ");
- var type, i = 0;
+ var type, i = 0, namespaces;
while ( (type = types[ i++ ]) ) {
- // Namespaced event handlers
- var namespaces = type.split(".");
- type = namespaces.shift();
+ handleObj = handleObjIn ?
+ jQuery.extend({}, handleObjIn) :
+ { handler: handler, data: data };
- if ( i > 1 ) {
- handler = jQuery.proxy( handler );
+ // Namespaced event handlers
+ if ( type.indexOf(".") > -1 ) {
+ namespaces = type.split(".");
+ type = namespaces.shift();
+ handleObj.namespace = namespaces.slice(0).sort().join(".");
- if ( data !== undefined ) {
- handler.data = data;
- }
+ } else {
+ namespaces = [];
+ handleObj.namespace = "";
}
- handler.type = namespaces.slice(0).sort().join(".");
+ handleObj.type = type;
+ if ( !handleObj.guid ) {
+ handleObj.guid = handler.guid;
+ }
// Get the current list of functions bound to this event
var handlers = events[ type ],
- special = this.special[ type ] || {};
+ special = jQuery.event.special[ type ] || {};
// Init the event handler queue
if ( !handlers ) {
- handlers = events[ type ] = {};
+ handlers = events[ type ] = [];
// Check for a special event handler
// Only use addEventListener/attachEvent if the special
// events handler returns false
- if ( !special.setup || special.setup.call( elem, data, namespaces, handler) === false ) {
+ if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
// Bind the global event handler to the element
if ( elem.addEventListener ) {
- elem.addEventListener( type, handle, false );
+ elem.addEventListener( type, eventHandle, false );
+
} else if ( elem.attachEvent ) {
- elem.attachEvent( "on" + type, handle );
+ elem.attachEvent( "on" + type, eventHandle );
}
}
}
if ( special.add ) {
- var modifiedHandler = special.add.call( elem, handler, data, namespaces, handlers );
- if ( modifiedHandler && jQuery.isFunction( modifiedHandler ) ) {
- modifiedHandler.guid = modifiedHandler.guid || handler.guid;
- modifiedHandler.data = modifiedHandler.data || handler.data;
- modifiedHandler.type = modifiedHandler.type || handler.type;
- handler = modifiedHandler;
- }
- }
-
+ special.add.call( elem, handleObj );
+
+ if ( !handleObj.handler.guid ) {
+ handleObj.handler.guid = handler.guid;
+ }
+ }
+
// Add the function to the element's handler list
- handlers[ handler.guid ] = handler;
+ handlers.push( handleObj );
// Keep track of which events have been used, for global triggering
- this.global[ type ] = true;
+ jQuery.event.global[ type ] = true;
}
// Nullify elem to prevent memory leaks in IE
@@ -1660,90 +1921,134 @@ jQuery.event = {
global: {},
// Detach an event or set of events from an element
- remove: function( elem, types, handler ) {
+ remove: function( elem, types, handler, pos ) {
// don't do events on text and comment nodes
if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
return;
}
- var events = jQuery.data( elem, "events" ), ret, type, fn;
+ if ( handler === false ) {
+ handler = returnFalse;
+ }
+
+ var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
+ eventKey = elem.nodeType ? "events" : "__events__",
+ elemData = jQuery.data( elem ),
+ events = elemData && elemData[ eventKey ];
- if ( events ) {
- // Unbind all events for the element
- if ( types === undefined || (typeof types === "string" && types.charAt(0) === ".") ) {
- for ( type in events ) {
- this.remove( elem, type + (types || "") );
- }
- } else {
- // types is actually an event object here
- if ( types.type ) {
- handler = types.handler;
- types = types.type;
+ if ( !elemData || !events ) {
+ return;
+ }
+
+ if ( typeof events === "function" ) {
+ elemData = events;
+ events = events.events;
+ }
+
+ // types is actually an event object here
+ if ( types && types.type ) {
+ handler = types.handler;
+ types = types.type;
+ }
+
+ // Unbind all events for the element
+ if ( !types || typeof types === "string" && types.charAt(0) === "." ) {
+ types = types || "";
+
+ for ( type in events ) {
+ jQuery.event.remove( elem, type + types );
+ }
+
+ return;
+ }
+
+ // Handle multiple events separated by a space
+ // jQuery(...).unbind("mouseover mouseout", fn);
+ types = types.split(" ");
+
+ while ( (type = types[ i++ ]) ) {
+ origType = type;
+ handleObj = null;
+ all = type.indexOf(".") < 0;
+ namespaces = [];
+
+ if ( !all ) {
+ // Namespaced event handlers
+ namespaces = type.split(".");
+ type = namespaces.shift();
+
+ namespace = new RegExp("(^|\\.)" +
+ jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)");
+ }
+
+ eventType = events[ type ];
+
+ if ( !eventType ) {
+ continue;
+ }
+
+ if ( !handler ) {
+ for ( j = 0; j < eventType.length; j++ ) {
+ handleObj = eventType[ j ];
+
+ if ( all || namespace.test( handleObj.namespace ) ) {
+ jQuery.event.remove( elem, origType, handleObj.handler, j );
+ eventType.splice( j--, 1 );
+ }
}
- // Handle multiple events separated by a space
- // jQuery(...).unbind("mouseover mouseout", fn);
- types = types.split(/\s+/);
- var i = 0;
- while ( (type = types[ i++ ]) ) {
- // Namespaced event handlers
- var namespaces = type.split(".");
- type = namespaces.shift();
- var all = !namespaces.length,
- cleaned = jQuery.map( namespaces.slice(0).sort(), fcleanup ),
- namespace = new RegExp("(^|\\.)" + cleaned.join("\\.(?:.*\\.)?") + "(\\.|$)"),
- special = this.special[ type ] || {};
-
- if ( events[ type ] ) {
- // remove the given handler for the given type
- if ( handler ) {
- fn = events[ type ][ handler.guid ];
- delete events[ type ][ handler.guid ];
-
- // remove all handlers for the given type
- } else {
- for ( var handle in events[ type ] ) {
- // Handle the removal of namespaced events
- if ( all || namespace.test( events[ type ][ handle ].type ) ) {
- delete events[ type ][ handle ];
- }
- }
+ continue;
+ }
+
+ special = jQuery.event.special[ type ] || {};
+
+ for ( j = pos || 0; j < eventType.length; j++ ) {
+ handleObj = eventType[ j ];
+
+ if ( handler.guid === handleObj.guid ) {
+ // remove the given handler for the given type
+ if ( all || namespace.test( handleObj.namespace ) ) {
+ if ( pos == null ) {
+ eventType.splice( j--, 1 );
}
if ( special.remove ) {
- special.remove.call( elem, namespaces, fn);
+ special.remove.call( elem, handleObj );
}
+ }
- // remove generic event handler if no more handlers exist
- for ( ret in events[ type ] ) {
- break;
- }
- if ( !ret ) {
- if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
- if ( elem.removeEventListener ) {
- elem.removeEventListener( type, jQuery.data( elem, "handle" ), false );
- } else if ( elem.detachEvent ) {
- elem.detachEvent( "on" + type, jQuery.data( elem, "handle" ) );
- }
- }
- ret = null;
- delete events[ type ];
- }
+ if ( pos != null ) {
+ break;
}
}
}
- // Remove the expando if it's no longer used
- for ( ret in events ) {
- break;
- }
- if ( !ret ) {
- var handle = jQuery.data( elem, "handle" );
- if ( handle ) {
- handle.elem = null;
+ // remove generic event handler if no more handlers exist
+ if ( eventType.length === 0 || pos != null && eventType.length === 1 ) {
+ if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
+ jQuery.removeEvent( elem, type, elemData.handle );
}
- jQuery.removeData( elem, "events" );
- jQuery.removeData( elem, "handle" );
+
+ ret = null;
+ delete events[ type ];
+ }
+ }
+
+ // Remove the expando if it's no longer used
+ if ( jQuery.isEmptyObject( events ) ) {
+ var handle = elemData.handle;
+ if ( handle ) {
+ handle.elem = null;
+ }
+
+ delete elemData.events;
+ delete elemData.handle;
+
+ if ( typeof elemData === "function" ) {
+ jQuery.removeData( elem, eventKey );
+
+ } else if ( jQuery.isEmptyObject( elemData ) ) {
+ jQuery.removeData( elem );
}
}
},
@@ -1757,7 +2062,7 @@ jQuery.event = {
if ( !bubbling ) {
event = typeof event === "object" ?
// jQuery.Event object
- event[expando] ? event :
+ event[ jQuery.expando ] ? event :
// Object literal
jQuery.extend( jQuery.Event(type), event ) :
// Just the event type (string)
@@ -1774,7 +2079,7 @@ jQuery.event = {
event.stopPropagation();
// Only trigger if we've ever bound an event for it
- if ( this.global[ type ] ) {
+ if ( jQuery.event.global[ type ] ) {
jQuery.each( jQuery.cache, function() {
if ( this.events && this.events[type] ) {
jQuery.event.trigger( event, data, this.handle.elem );
@@ -1802,7 +2107,10 @@ jQuery.event = {
event.currentTarget = elem;
// Trigger the event, it is assumed that "handle" is a function
- var handle = jQuery.data( elem, "handle" );
+ var handle = elem.nodeType ?
+ jQuery.data( elem, "handle" ) :
+ (jQuery.data( elem, "__events__" ) || {}).handle;
+
if ( handle ) {
handle.apply( elem, data );
}
@@ -1814,97 +2122,114 @@ jQuery.event = {
if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {
if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) {
event.result = false;
+ event.preventDefault();
}
}
// prevent IE from throwing an error for some elements with some event types, see #3533
- } catch (e) {}
+ } catch (inlineError) {}
if ( !event.isPropagationStopped() && parent ) {
jQuery.event.trigger( event, data, parent, true );
} else if ( !event.isDefaultPrevented() ) {
- var target = event.target, old,
- isClick = jQuery.nodeName(target, "a") && type === "click";
+ var target = event.target, old, targetType = type.replace(rnamespaces, ""),
+ isClick = jQuery.nodeName(target, "a") && targetType === "click",
+ special = jQuery.event.special[ targetType ] || {};
+
+ if ( (!special._default || special._default.call( elem, event ) === false) &&
+ !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {
- if ( !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {
try {
- if ( target[ type ] ) {
+ if ( target[ targetType ] ) {
// Make sure that we don't accidentally re-trigger the onFOO events
- old = target[ "on" + type ];
+ old = target[ "on" + targetType ];
if ( old ) {
- target[ "on" + type ] = null;
+ target[ "on" + targetType ] = null;
}
- this.triggered = true;
- target[ type ]();
+ jQuery.event.triggered = true;
+ target[ targetType ]();
}
// prevent IE from throwing an error for some elements with some event types, see #3533
- } catch (e) {}
+ } catch (triggerError) {}
if ( old ) {
- target[ "on" + type ] = old;
+ target[ "on" + targetType ] = old;
}
- this.triggered = false;
+ jQuery.event.triggered = false;
}
}
},
handle: function( event ) {
- // returned undefined or false
- var all, handlers;
+ var all, handlers, namespaces, namespace_sort = [], namespace_re, events, args = jQuery.makeArray( arguments );
- event = arguments[0] = jQuery.event.fix( event || window.event );
+ event = args[0] = jQuery.event.fix( event || window.event );
event.currentTarget = this;
// Namespaced event handlers
- var namespaces = event.type.split(".");
- event.type = namespaces.shift();
+ all = event.type.indexOf(".") < 0 && !event.exclusive;
+
+ if ( !all ) {
+ namespaces = event.type.split(".");
+ event.type = namespaces.shift();
+ namespace_sort = namespaces.slice(0).sort();
+ namespace_re = new RegExp("(^|\\.)" + namespace_sort.join("\\.(?:.*\\.)?") + "(\\.|$)");
+ }
- // Cache this now, all = true means, any handler
- all = !namespaces.length && !event.exclusive;
+ event.namespace = event.namespace || namespace_sort.join(".");
- var namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join("\\.(?:.*\\.)?") + "(\\.|$)");
+ events = jQuery.data(this, this.nodeType ? "events" : "__events__");
- handlers = ( jQuery.data(this, "events") || {} )[ event.type ];
+ if ( typeof events === "function" ) {
+ events = events.events;
+ }
+
+ handlers = (events || {})[ event.type ];
- for ( var j in handlers ) {
- var handler = handlers[ j ];
+ if ( events && handlers ) {
+ // Clone the handlers to prevent manipulation
+ handlers = handlers.slice(0);
- // Filter the functions by class
- if ( all || namespace.test(handler.type) ) {
- // Pass in a reference to the handler function itself
- // So that we can later remove it
- event.handler = handler;
- event.data = handler.data;
+ for ( var j = 0, l = handlers.length; j < l; j++ ) {
+ var handleObj = handlers[ j ];
- var ret = handler.apply( this, arguments );
+ // Filter the functions by class
+ if ( all || namespace_re.test( handleObj.namespace ) ) {
+ // Pass in a reference to the handler function itself
+ // So that we can later remove it
+ event.handler = handleObj.handler;
+ event.data = handleObj.data;
+ event.handleObj = handleObj;
+
+ var ret = handleObj.handler.apply( this, args );
- if ( ret !== undefined ) {
- event.result = ret;
- if ( ret === false ) {
- event.preventDefault();
- event.stopPropagation();
+ if ( ret !== undefined ) {
+ event.result = ret;
+ if ( ret === false ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
}
- }
- if ( event.isImmediatePropagationStopped() ) {
- break;
+ if ( event.isImmediatePropagationStopped() ) {
+ break;
+ }
}
-
}
}
return event.result;
},
- props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
+ props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
fix: function( event ) {
- if ( event[ expando ] ) {
+ if ( event[ jQuery.expando ] ) {
return event;
}
@@ -1941,8 +2266,8 @@ jQuery.event = {
}
// Add which for key events
- if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) ) {
- event.which = event.charCode || event.keyCode;
+ if ( event.which == null && (event.charCode != null || event.keyCode != null) ) {
+ event.which = event.charCode != null ? event.charCode : event.keyCode;
}
// Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
@@ -1973,44 +2298,27 @@ jQuery.event = {
},
live: {
- add: function( proxy, data, namespaces, live ) {
- jQuery.extend( proxy, data || {} );
-
- proxy.guid += data.selector + data.live;
- data.liveProxy = proxy;
-
- jQuery.event.add( this, data.live, liveHandler, data );
-
+ add: function( handleObj ) {
+ jQuery.event.add( this,
+ liveConvert( handleObj.origType, handleObj.selector ),
+ jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );
},
- remove: function( namespaces ) {
- if ( namespaces.length ) {
- var remove = 0, name = new RegExp("(^|\\.)" + namespaces[0] + "(\\.|$)");
-
- jQuery.each( (jQuery.data(this, "events").live || {}), function() {
- if ( name.test(this.type) ) {
- remove++;
- }
- });
-
- if ( remove < 1 ) {
- jQuery.event.remove( this, namespaces[0], liveHandler );
- }
- }
- },
- special: {}
+ remove: function( handleObj ) {
+ jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj );
+ }
},
+
beforeunload: {
- setup: function( data, namespaces, fn ) {
+ setup: function( data, namespaces, eventHandle ) {
// We only want to do this special case on windows
- if ( this.setInterval ) {
- this.onbeforeunload = fn;
+ if ( jQuery.isWindow( this ) ) {
+ this.onbeforeunload = eventHandle;
}
-
- return false;
},
- teardown: function( namespaces, fn ) {
- if ( this.onbeforeunload === fn ) {
+
+ teardown: function( namespaces, eventHandle ) {
+ if ( this.onbeforeunload === eventHandle ) {
this.onbeforeunload = null;
}
}
@@ -2018,6 +2326,18 @@ jQuery.event = {
}
};
+jQuery.removeEvent = document.removeEventListener ?
+ function( elem, type, handle ) {
+ if ( elem.removeEventListener ) {
+ elem.removeEventListener( type, handle, false );
+ }
+ } :
+ function( elem, type, handle ) {
+ if ( elem.detachEvent ) {
+ elem.detachEvent( "on" + type, handle );
+ }
+ };
+
jQuery.Event = function( src ) {
// Allow instantiation without the 'new' keyword
if ( !this.preventDefault ) {
@@ -2035,10 +2355,10 @@ jQuery.Event = function( src ) {
// timeStamp is buggy for some events on Firefox(#3843)
// So we won't rely on the native value
- this.timeStamp = now();
+ this.timeStamp = jQuery.now();
// Mark it as fixed
- this[ expando ] = true;
+ this[ jQuery.expando ] = true;
};
function returnFalse() {
@@ -2062,9 +2382,11 @@ jQuery.Event.prototype = {
// if preventDefault exists run it on the original event
if ( e.preventDefault ) {
e.preventDefault();
- }
+
// otherwise set the returnValue property of the original event to false (IE)
- e.returnValue = false;
+ } else {
+ e.returnValue = false;
+ }
},
stopPropagation: function() {
this.isPropagationStopped = returnTrue;
@@ -2095,27 +2417,24 @@ var withinElement = function( event ) {
// Check if mouse(over|out) are still within the same parent element
var parent = event.relatedTarget;
- // Traverse up the tree
- while ( parent && parent !== this ) {
- // Firefox sometimes assigns relatedTarget a XUL element
- // which we cannot access the parentNode property of
- try {
+ // Firefox sometimes assigns relatedTarget a XUL element
+ // which we cannot access the parentNode property of
+ try {
+ // Traverse up the tree
+ while ( parent && parent !== this ) {
parent = parent.parentNode;
-
- // assuming we've left the element since we most likely mousedover a xul element
- } catch(e) {
- break;
}
- }
- if ( parent !== this ) {
- // set the correct event type
- event.type = event.data;
+ if ( parent !== this ) {
+ // set the correct event type
+ event.type = event.data;
- // handle event if we actually just moused on to a non sub-element
- jQuery.event.handle.apply( this, arguments );
- }
+ // handle event if we actually just moused on to a non sub-element
+ jQuery.event.handle.apply( this, arguments );
+ }
+ // assuming we've left the element since we most likely mousedover a xul element
+ } catch(e) { }
},
// In case of event delegation, we only need to rename the event.type,
@@ -2143,67 +2462,68 @@ jQuery.each({
// submit delegation
if ( !jQuery.support.submitBubbles ) {
-jQuery.event.special.submit = {
- setup: function( data, namespaces, fn ) {
- if ( this.nodeName.toLowerCase() !== "form" ) {
- jQuery.event.add(this, "click.specialSubmit." + fn.guid, function( e ) {
- var elem = e.target, type = elem.type;
+ jQuery.event.special.submit = {
+ setup: function( data, namespaces ) {
+ if ( this.nodeName.toLowerCase() !== "form" ) {
+ jQuery.event.add(this, "click.specialSubmit", function( e ) {
+ var elem = e.target, type = elem.type;
- if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
- return trigger( "submit", this, arguments );
- }
- });
+ if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
+ e.liveFired = undefined;
+ return trigger( "submit", this, arguments );
+ }
+ });
- jQuery.event.add(this, "keypress.specialSubmit." + fn.guid, function( e ) {
- var elem = e.target, type = elem.type;
+ jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
+ var elem = e.target, type = elem.type;
- if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
- return trigger( "submit", this, arguments );
- }
- });
+ if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
+ e.liveFired = undefined;
+ return trigger( "submit", this, arguments );
+ }
+ });
- } else {
- return false;
- }
- },
+ } else {
+ return false;
+ }
+ },
- remove: function( namespaces, fn ) {
- jQuery.event.remove( this, "click.specialSubmit" + (fn ? "."+fn.guid : "") );
- jQuery.event.remove( this, "keypress.specialSubmit" + (fn ? "."+fn.guid : "") );
- }
-};
+ teardown: function( namespaces ) {
+ jQuery.event.remove( this, ".specialSubmit" );
+ }
+ };
}
// change delegation, happens here so we have bind.
if ( !jQuery.support.changeBubbles ) {
-var formElems = /textarea|input|select/i;
+ var changeFilters,
-function getVal( elem ) {
- var type = elem.type, val = elem.value;
+ getVal = function( elem ) {
+ var type = elem.type, val = elem.value;
- if ( type === "radio" || type === "checkbox" ) {
- val = elem.checked;
+ if ( type === "radio" || type === "checkbox" ) {
+ val = elem.checked;
- } else if ( type === "select-multiple" ) {
- val = elem.selectedIndex > -1 ?
- jQuery.map( elem.options, function( elem ) {
- return elem.selected;
- }).join("-") :
- "";
+ } else if ( type === "select-multiple" ) {
+ val = elem.selectedIndex > -1 ?
+ jQuery.map( elem.options, function( elem ) {
+ return elem.selected;
+ }).join("-") :
+ "";
- } else if ( elem.nodeName.toLowerCase() === "select" ) {
- val = elem.selectedIndex;
- }
+ } else if ( elem.nodeName.toLowerCase() === "select" ) {
+ val = elem.selectedIndex;
+ }
- return val;
-}
+ return val;
+ },
-function testChange( e ) {
+ testChange = function testChange( e ) {
var elem = e.target, data, val;
- if ( !formElems.test( elem.nodeName ) || elem.readOnly ) {
+ if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) {
return;
}
@@ -2221,63 +2541,69 @@ function testChange( e ) {
if ( data != null || val ) {
e.type = "change";
+ e.liveFired = undefined;
return jQuery.event.trigger( e, arguments[1], elem );
}
-}
+ };
-jQuery.event.special.change = {
- filters: {
- focusout: testChange,
+ jQuery.event.special.change = {
+ filters: {
+ focusout: testChange,
- click: function( e ) {
- var elem = e.target, type = elem.type;
+ beforedeactivate: testChange,
- if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
- return testChange.call( this, e );
- }
- },
+ click: function( e ) {
+ var elem = e.target, type = elem.type;
+
+ if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
+ return testChange.call( this, e );
+ }
+ },
- // Change has to be called before submit
- // Keydown will be called before keypress, which is used in submit-event delegation
- keydown: function( e ) {
- var elem = e.target, type = elem.type;
+ // Change has to be called before submit
+ // Keydown will be called before keypress, which is used in submit-event delegation
+ keydown: function( e ) {
+ var elem = e.target, type = elem.type;
- if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
- (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
- type === "select-multiple" ) {
- return testChange.call( this, e );
+ if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
+ (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
+ type === "select-multiple" ) {
+ return testChange.call( this, e );
+ }
+ },
+
+ // Beforeactivate happens also before the previous element is blurred
+ // with this event you can't trigger a change event, but you can store
+ // information
+ beforeactivate: function( e ) {
+ var elem = e.target;
+ jQuery.data( elem, "_change_data", getVal(elem) );
}
},
- // Beforeactivate happens also before the previous element is blurred
- // with this event you can't trigger a change event, but you can store
- // information/focus[in] is not needed anymore
- beforeactivate: function( e ) {
- var elem = e.target;
+ setup: function( data, namespaces ) {
+ if ( this.type === "file" ) {
+ return false;
+ }
- if ( elem.nodeName.toLowerCase() === "input" && elem.type === "radio" ) {
- jQuery.data( elem, "_change_data", getVal(elem) );
+ for ( var type in changeFilters ) {
+ jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
}
- }
- },
- setup: function( data, namespaces, fn ) {
- for ( var type in changeFilters ) {
- jQuery.event.add( this, type + ".specialChange." + fn.guid, changeFilters[type] );
- }
- return formElems.test( this.nodeName );
- },
- remove: function( namespaces, fn ) {
- for ( var type in changeFilters ) {
- jQuery.event.remove( this, type + ".specialChange" + (fn ? "."+fn.guid : ""), changeFilters[type] );
- }
+ return rformElems.test( this.nodeName );
+ },
- return formElems.test( this.nodeName );
- }
-};
+ teardown: function( namespaces ) {
+ jQuery.event.remove( this, ".specialChange" );
+
+ return rformElems.test( this.nodeName );
+ }
+ };
-var changeFilters = jQuery.event.special.change.filters;
+ changeFilters = jQuery.event.special.change.filters;
+ // Handle when the input is .focus()'d
+ changeFilters.focus = changeFilters.beforeactivate;
}
function trigger( type, elem, args ) {
@@ -2290,17 +2616,21 @@ if ( document.addEventListener ) {
jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
jQuery.event.special[ fix ] = {
setup: function() {
- this.addEventListener( orig, handler, true );
+ if ( focusCounts[fix]++ === 0 ) {
+ document.addEventListener( orig, handler, true );
+ }
},
teardown: function() {
- this.removeEventListener( orig, handler, true );
+ if ( --focusCounts[fix] === 0 ) {
+ document.removeEventListener( orig, handler, true );
+ }
}
};
function handler( e ) {
e = jQuery.event.fix( e );
e.type = fix;
- return jQuery.event.handle.call( this, e );
+ return jQuery.event.trigger( e, null, e.target );
}
});
}
@@ -2315,7 +2645,7 @@ jQuery.each(["bind", "one"], function( i, name ) {
return this;
}
- if ( jQuery.isFunction( data ) ) {
+ if ( jQuery.isFunction( data ) || data === false ) {
fn = data;
data = undefined;
}
@@ -2325,11 +2655,16 @@ jQuery.each(["bind", "one"], function( i, name ) {
return fn.apply( this, arguments );
}) : fn;
- return type === "unload" && name !== "one" ?
- this.one( type, data, fn ) :
- this.each(function() {
- jQuery.event.add( this, type, handler, data );
- });
+ if ( type === "unload" && name !== "one" ) {
+ this.one( type, data, fn );
+
+ } else {
+ for ( var i = 0, l = this.length; i < l; i++ ) {
+ jQuery.event.add( this[i], type, handler, data );
+ }
+ }
+
+ return this;
};
});
@@ -2340,13 +2675,29 @@ jQuery.fn.extend({
for ( var key in type ) {
this.unbind(key, type[key]);
}
- return this;
+
+ } else {
+ for ( var i = 0, l = this.length; i < l; i++ ) {
+ jQuery.event.remove( this[i], type, fn );
+ }
}
- return this.each(function() {
- jQuery.event.remove( this, type, fn );
- });
+ return this;
+ },
+
+ delegate: function( selector, types, data, fn ) {
+ return this.live( types, data, fn, selector );
+ },
+
+ undelegate: function( selector, types, fn ) {
+ if ( arguments.length === 0 ) {
+ return this.unbind( "live" );
+
+ } else {
+ return this.die( types, null, fn, selector );
+ }
},
+
trigger: function( type, data ) {
return this.each(function() {
jQuery.event.trigger( type, data, this );
@@ -2390,80 +2741,128 @@ jQuery.fn.extend({
}
});
+var liveMap = {
+ focus: "focusin",
+ blur: "focusout",
+ mouseenter: "mouseover",
+ mouseleave: "mouseout"
+};
+
jQuery.each(["live", "die"], function( i, name ) {
- jQuery.fn[ name ] = function( types, data, fn ) {
- var type, i = 0;
+ jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
+ var type, i = 0, match, namespaces, preType,
+ selector = origSelector || this.selector,
+ context = origSelector ? this : jQuery( this.context );
+
+ if ( typeof types === "object" && !types.preventDefault ) {
+ for ( var key in types ) {
+ context[ name ]( key, data, types[key], selector );
+ }
+
+ return this;
+ }
if ( jQuery.isFunction( data ) ) {
fn = data;
data = undefined;
}
- types = (types || "").split( /\s+/ );
+ types = (types || "").split(" ");
while ( (type = types[ i++ ]) != null ) {
- type = type === "focus" ? "focusin" : // focus --> focusin
- type === "blur" ? "focusout" : // blur --> focusout
- type === "hover" ? types.push("mouseleave") && "mouseenter" : // hover support
- type;
-
+ match = rnamespaces.exec( type );
+ namespaces = "";
+
+ if ( match ) {
+ namespaces = match[0];
+ type = type.replace( rnamespaces, "" );
+ }
+
+ if ( type === "hover" ) {
+ types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
+ continue;
+ }
+
+ preType = type;
+
+ if ( type === "focus" || type === "blur" ) {
+ types.push( liveMap[ type ] + namespaces );
+ type = type + namespaces;
+
+ } else {
+ type = (liveMap[ type ] || type) + namespaces;
+ }
+
if ( name === "live" ) {
// bind live handler
- jQuery( this.context ).bind( liveConvert( type, this.selector ), {
- data: data, selector: this.selector, live: type
- }, fn );
+ for ( var j = 0, l = context.length; j < l; j++ ) {
+ jQuery.event.add( context[j], "live." + liveConvert( type, selector ),
+ { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
+ }
} else {
// unbind live handler
- jQuery( this.context ).unbind( liveConvert( type, this.selector ), fn ? { guid: fn.guid + this.selector + type } : null );
+ context.unbind( "live." + liveConvert( type, selector ), fn );
}
}
return this;
- }
+ };
});
function liveHandler( event ) {
- var stop, elems = [], selectors = [], args = arguments,
- related, match, fn, elem, j, i, l, data,
- live = jQuery.extend({}, jQuery.data( this, "events" ).live);
+ var stop, maxLevel, elems = [], selectors = [],
+ related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
+ events = jQuery.data( this, this.nodeType ? "events" : "__events__" );
+
+ if ( typeof events === "function" ) {
+ events = events.events;
+ }
// Make sure we avoid non-left-click bubbling in Firefox (#3861)
- if ( event.button && event.type === "click" ) {
+ if ( event.liveFired === this || !events || !events.live || event.button && event.type === "click" ) {
return;
}
- for ( j in live ) {
- fn = live[j];
- if ( fn.live === event.type ||
- fn.altLive && jQuery.inArray(event.type, fn.altLive) > -1 ) {
+ if ( event.namespace ) {
+ namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)");
+ }
+
+ event.liveFired = this;
+
+ var live = events.live.slice(0);
+
+ for ( j = 0; j < live.length; j++ ) {
+ handleObj = live[j];
+
+ if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
+ selectors.push( handleObj.selector );
- data = fn.data;
- if ( !(data.beforeFilter && data.beforeFilter[event.type] &&
- !data.beforeFilter[event.type](event)) ) {
- selectors.push( fn.selector );
- }
} else {
- delete live[j];
+ live.splice( j--, 1 );
}
}
match = jQuery( event.target ).closest( selectors, event.currentTarget );
for ( i = 0, l = match.length; i < l; i++ ) {
- for ( j in live ) {
- fn = live[j];
- elem = match[i].elem;
- related = null;
+ close = match[i];
+
+ for ( j = 0; j < live.length; j++ ) {
+ handleObj = live[j];
+
+ if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) ) {
+ elem = close.elem;
+ related = null;
- if ( match[i].selector === fn.selector ) {
// Those two events require additional checking
- if ( fn.live === "mouseenter" || fn.live === "mouseleave" ) {
- related = jQuery( event.relatedTarget ).closest( fn.selector )[0];
+ if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
+ event.type = handleObj.preType;
+ related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
}
if ( !related || related !== elem ) {
- elems.push({ elem: elem, fn: fn });
+ elems.push({ elem: elem, handleObj: handleObj, level: close.level });
}
}
}
@@ -2471,19 +2870,31 @@ function liveHandler( event ) {
for ( i = 0, l = elems.length; i < l; i++ ) {
match = elems[i];
- event.currentTarget = match.elem;
- event.data = match.fn.data;
- if ( match.fn.apply( match.elem, args ) === false ) {
- stop = false;
+
+ if ( maxLevel && match.level > maxLevel ) {
break;
}
+
+ event.currentTarget = match.elem;
+ event.data = match.handleObj.data;
+ event.handleObj = match.handleObj;
+
+ ret = match.handleObj.origHandler.apply( match.elem, arguments );
+
+ if ( ret === false || event.isPropagationStopped() ) {
+ maxLevel = match.level;
+
+ if ( ret === false ) {
+ stop = false;
+ }
+ }
}
return stop;
}
function liveConvert( type, selector ) {
- return "live." + (type ? type + "." : "") + selector.replace(/\./g, "`").replace(/ /g, "&");
+ return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspace, "&");
}
jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
@@ -2491,8 +2902,15 @@ jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblcl
"change select submit keydown keypress keyup error").split(" "), function( i, name ) {
// Handle event binding
- jQuery.fn[ name ] = function( fn ) {
- return fn ? this.bind( name, fn ) : this.trigger( name );
+ jQuery.fn[ name ] = function( data, fn ) {
+ if ( fn == null ) {
+ fn = data;
+ data = null;
+ }
+
+ return arguments.length > 0 ?
+ this.bind( name, data, fn ) :
+ this.trigger( name );
};
if ( jQuery.attrFn ) {
@@ -2505,7 +2923,7 @@ jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblcl
// More info:
// - http://isaacschlueter.com/2006/10/msie-memory-leaks/
if ( window.attachEvent && !window.addEventListener ) {
- window.attachEvent("onunload", function() {
+ jQuery(window).bind("unload", function() {
for ( var id in jQuery.cache ) {
if ( jQuery.cache[ id ].handle ) {
// Try/Catch is to handle iframes being unloaded, see #4280
@@ -2516,6 +2934,8 @@ if ( window.attachEvent && !window.addEventListener ) {
}
});
}
+
+
/*!
* Sizzle CSS Selector Engine - v1.0
* Copyright 2009, The Dojo Foundation
@@ -2524,7 +2944,7 @@ if ( window.attachEvent && !window.addEventListener ) {
*/
(function(){
-var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
+var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
done = 0,
toString = Object.prototype.toString,
hasDuplicate = false,
@@ -2541,7 +2961,9 @@ var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^
var Sizzle = function(selector, context, results, seed) {
results = results || [];
- var origContext = context = context || document;
+ context = context || document;
+
+ var origContext = context;
if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
return [];
@@ -2551,20 +2973,25 @@ var Sizzle = function(selector, context, results, seed) {
return results;
}
- var parts = [], m, set, checkSet, extra, prune = true, contextXML = isXML(context),
- soFar = selector;
+ var parts = [], m, set, checkSet, extra, prune = true, contextXML = Sizzle.isXML(context),
+ soFar = selector, ret, cur, pop, i;
// Reset the position of the chunker regexp (start from head)
- while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) {
- soFar = m[3];
+ do {
+ chunker.exec("");
+ m = chunker.exec(soFar);
+
+ if ( m ) {
+ soFar = m[3];
- parts.push( m[1] );
+ parts.push( m[1] );
- if ( m[2] ) {
- extra = m[3];
- break;
+ if ( m[2] ) {
+ extra = m[3];
+ break;
+ }
}
- }
+ } while ( m );
if ( parts.length > 1 && origPOS.exec( selector ) ) {
if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
@@ -2589,12 +3016,12 @@ var Sizzle = function(selector, context, results, seed) {
// (but not if it'll be faster if the inner selector is an ID)
if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
- var ret = Sizzle.find( parts.shift(), context, contextXML );
+ ret = Sizzle.find( parts.shift(), context, contextXML );
context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0];
}
if ( context ) {
- var ret = seed ?
+ ret = seed ?
{ expr: parts.pop(), set: makeArray(seed) } :
Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set;
@@ -2606,7 +3033,8 @@ var Sizzle = function(selector, context, results, seed) {
}
while ( parts.length ) {
- var cur = parts.pop(), pop = cur;
+ cur = parts.pop();
+ pop = cur;
if ( !Expr.relative[ cur ] ) {
cur = "";
@@ -2637,13 +3065,13 @@ var Sizzle = function(selector, context, results, seed) {
if ( !prune ) {
results.push.apply( results, checkSet );
} else if ( context && context.nodeType === 1 ) {
- for ( var i = 0; checkSet[i] != null; i++ ) {
- if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) {
+ for ( i = 0; checkSet[i] != null; i++ ) {
+ if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {
results.push( set[i] );
}
}
} else {
- for ( var i = 0; checkSet[i] != null; i++ ) {
+ for ( i = 0; checkSet[i] != null; i++ ) {
if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
results.push( set[i] );
}
@@ -2682,8 +3110,12 @@ Sizzle.matches = function(expr, set){
return Sizzle(expr, null, null, set);
};
+Sizzle.matchesSelector = function(node, expr){
+ return Sizzle(expr, null, null, [node]).length > 0;
+};
+
Sizzle.find = function(expr, context, isXML){
- var set, match;
+ var set;
if ( !expr ) {
return [];
@@ -2716,7 +3148,7 @@ Sizzle.find = function(expr, context, isXML){
Sizzle.filter = function(expr, set, inplace, not){
var old = expr, result = [], curLoop = set, match, anyFound,
- isXMLFilter = set && set[0] && isXML(set[0]);
+ isXMLFilter = set && set[0] && Sizzle.isXML(set[0]);
while ( expr && set.length ) {
for ( var type in Expr.filter ) {
@@ -2802,14 +3234,14 @@ Sizzle.error = function( msg ) {
var Expr = Sizzle.selectors = {
order: [ "ID", "NAME", "TAG" ],
match: {
- ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
- CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
- NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,
- ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
- TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,
- CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
- POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
- PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
+ ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
+ CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
+ NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,
+ ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
+ TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,
+ CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+\-]*)\))?/,
+ POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
+ PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
},
leftMatch: {},
attrMap: {
@@ -2846,21 +3278,22 @@ var Expr = Sizzle.selectors = {
}
},
">": function(checkSet, part){
- var isPartStr = typeof part === "string";
+ var isPartStr = typeof part === "string",
+ elem, i = 0, l = checkSet.length;
if ( isPartStr && !/\W/.test(part) ) {
part = part.toLowerCase();
- for ( var i = 0, l = checkSet.length; i < l; i++ ) {
- var elem = checkSet[i];
+ for ( ; i < l; i++ ) {
+ elem = checkSet[i];
if ( elem ) {
var parent = elem.parentNode;
checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
}
}
} else {
- for ( var i = 0, l = checkSet.length; i < l; i++ ) {
- var elem = checkSet[i];
+ for ( ; i < l; i++ ) {
+ elem = checkSet[i];
if ( elem ) {
checkSet[i] = isPartStr ?
elem.parentNode :
@@ -2874,20 +3307,22 @@ var Expr = Sizzle.selectors = {
}
},
"": function(checkSet, part, isXML){
- var doneName = done++, checkFn = dirCheck;
+ var doneName = done++, checkFn = dirCheck, nodeCheck;
if ( typeof part === "string" && !/\W/.test(part) ) {
- var nodeCheck = part = part.toLowerCase();
+ part = part.toLowerCase();
+ nodeCheck = part;
checkFn = dirNodeCheck;
}
checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
},
"~": function(checkSet, part, isXML){
- var doneName = done++, checkFn = dirCheck;
+ var doneName = done++, checkFn = dirCheck, nodeCheck;
if ( typeof part === "string" && !/\W/.test(part) ) {
- var nodeCheck = part = part.toLowerCase();
+ part = part.toLowerCase();
+ nodeCheck = part;
checkFn = dirNodeCheck;
}
@@ -2898,7 +3333,9 @@ var Expr = Sizzle.selectors = {
ID: function(match, context, isXML){
if ( typeof context.getElementById !== "undefined" && !isXML ) {
var m = context.getElementById(match[1]);
- return m ? [m] : [];
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ return m && m.parentNode ? [m] : [];
}
},
NAME: function(match, context){
@@ -3025,7 +3462,7 @@ var Expr = Sizzle.selectors = {
return !!Sizzle( match[3], elem ).length;
},
header: function(elem){
- return /h\d/i.test( elem.nodeName );
+ return (/h\d/i).test( elem.nodeName );
},
text: function(elem){
return "text" === elem.type;
@@ -3055,7 +3492,7 @@ var Expr = Sizzle.selectors = {
return "button" === elem.type || elem.nodeName.toLowerCase() === "button";
},
input: function(elem){
- return /input|select|textarea|button/i.test(elem.nodeName);
+ return (/input|select|textarea|button/i).test(elem.nodeName);
}
},
setFilters: {
@@ -3091,12 +3528,12 @@ var Expr = Sizzle.selectors = {
if ( filter ) {
return filter( elem, i, match, array );
} else if ( name === "contains" ) {
- return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0;
+ return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0;
} else if ( name === "not" ) {
var not = match[3];
- for ( var i = 0, l = not.length; i < l; i++ ) {
- if ( not[i] === elem ) {
+ for ( var j = 0, l = not.length; j < l; j++ ) {
+ if ( not[j] === elem ) {
return false;
}
}
@@ -3206,13 +3643,14 @@ var Expr = Sizzle.selectors = {
}
};
-var origPOS = Expr.match.POS;
+var origPOS = Expr.match.POS,
+ fescape = function(all, num){
+ return "\\" + (num - 0 + 1);
+ };
for ( var type in Expr.match ) {
- Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source );
- Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, function(all, num){
- return "\\" + (num - 0 + 1);
- }));
+ Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) );
+ Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) );
}
var makeArray = function(array, results) {
@@ -3228,23 +3666,25 @@ var makeArray = function(array, results) {
// Perform a simple check to determine if the browser is capable of
// converting a NodeList to an array using builtin methods.
+// Also verifies that the returned array holds DOM nodes
+// (which is not the case in the Blackberry browser)
try {
- Array.prototype.slice.call( document.documentElement.childNodes, 0 );
+ Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;
// Provide a fallback method if it does not work
} catch(e){
makeArray = function(array, results) {
- var ret = results || [];
+ var ret = results || [], i = 0;
if ( toString.call(array) === "[object Array]" ) {
Array.prototype.push.apply( ret, array );
} else {
if ( typeof array.length === "number" ) {
- for ( var i = 0, l = array.length; i < l; i++ ) {
+ for ( var l = array.length; i < l; i++ ) {
ret.push( array[i] );
}
} else {
- for ( var i = 0; array[i]; i++ ) {
+ for ( ; array[i]; i++ ) {
ret.push( array[i] );
}
}
@@ -3254,62 +3694,94 @@ try {
};
}
-var sortOrder;
+var sortOrder, siblingCheck;
if ( document.documentElement.compareDocumentPosition ) {
sortOrder = function( a, b ) {
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
- if ( a == b ) {
- hasDuplicate = true;
- }
return a.compareDocumentPosition ? -1 : 1;
}
- var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
- if ( ret === 0 ) {
- hasDuplicate = true;
- }
- return ret;
+ return a.compareDocumentPosition(b) & 4 ? -1 : 1;
};
-} else if ( "sourceIndex" in document.documentElement ) {
+} else {
sortOrder = function( a, b ) {
- if ( !a.sourceIndex || !b.sourceIndex ) {
- if ( a == b ) {
- hasDuplicate = true;
- }
- return a.sourceIndex ? -1 : 1;
- }
+ var ap = [], bp = [], aup = a.parentNode, bup = b.parentNode,
+ cur = aup, al, bl;
- var ret = a.sourceIndex - b.sourceIndex;
- if ( ret === 0 ) {
+ // The nodes are identical, we can exit early
+ if ( a === b ) {
hasDuplicate = true;
+ return 0;
+
+ // If the nodes are siblings (or identical) we can do a quick check
+ } else if ( aup === bup ) {
+ return siblingCheck( a, b );
+
+ // If no parents were found then the nodes are disconnected
+ } else if ( !aup ) {
+ return -1;
+
+ } else if ( !bup ) {
+ return 1;
}
- return ret;
- };
-} else if ( document.createRange ) {
- sortOrder = function( a, b ) {
- if ( !a.ownerDocument || !b.ownerDocument ) {
- if ( a == b ) {
- hasDuplicate = true;
+
+ // Otherwise they're somewhere else in the tree so we need
+ // to build up a full list of the parentNodes for comparison
+ while ( cur ) {
+ ap.unshift( cur );
+ cur = cur.parentNode;
+ }
+
+ cur = bup;
+
+ while ( cur ) {
+ bp.unshift( cur );
+ cur = cur.parentNode;
+ }
+
+ al = ap.length;
+ bl = bp.length;
+
+ // Start walking down the tree looking for a discrepancy
+ for ( var i = 0; i < al && i < bl; i++ ) {
+ if ( ap[i] !== bp[i] ) {
+ return siblingCheck( ap[i], bp[i] );
}
- return a.ownerDocument ? -1 : 1;
}
- var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
- aRange.setStart(a, 0);
- aRange.setEnd(a, 0);
- bRange.setStart(b, 0);
- bRange.setEnd(b, 0);
- var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
- if ( ret === 0 ) {
- hasDuplicate = true;
+ // We ended someplace up the tree so do a sibling check
+ return i === al ?
+ siblingCheck( a, bp[i], -1 ) :
+ siblingCheck( ap[i], b, 1 );
+ };
+
+ siblingCheck = function( a, b, ret ) {
+ if ( a === b ) {
+ return ret;
}
- return ret;
+
+ var cur = a.nextSibling;
+
+ while ( cur ) {
+ if ( cur === b ) {
+ return -1;
+ }
+
+ cur = cur.nextSibling;
+ }
+
+ return 1;
};
}
// Utility function for retreiving the text value of an array of DOM nodes
-function getText( elems ) {
+Sizzle.getText = function( elems ) {
var ret = "", elem;
for ( var i = 0; elems[i]; i++ ) {
@@ -3321,19 +3793,19 @@ function getText( elems ) {
// Traverse everything else, except comment nodes
} else if ( elem.nodeType !== 8 ) {
- ret += getText( elem.childNodes );
+ ret += Sizzle.getText( elem.childNodes );
}
}
return ret;
-}
+};
// Check to see if the browser returns elements by name when
// querying by getElementById (and provide a workaround)
(function(){
// We're going to inject a fake input element with a specified name
var form = document.createElement("div"),
- id = "script" + (new Date).getTime();
+ id = "script" + (new Date()).getTime();
form.innerHTML = "<a name='" + id + "'/>";
// Inject it into the root element, check its status, and remove it quickly
@@ -3418,10 +3890,32 @@ if ( document.querySelectorAll ) {
// Only use querySelectorAll on non-XML documents
// (ID selectors don't work in non-HTML documents)
- if ( !seed && context.nodeType === 9 && !isXML(context) ) {
- try {
- return makeArray( context.querySelectorAll(query), extra );
- } catch(e){}
+ if ( !seed && !Sizzle.isXML(context) ) {
+ if ( context.nodeType === 9 ) {
+ try {
+ return makeArray( context.querySelectorAll(query), extra );
+ } catch(qsaError) {}
+
+ // qSA works strangely on Element-rooted queries
+ // We can work around this by specifying an extra ID on the root
+ // and working up from there (Thanks to Andrew Dupont for the technique)
+ // IE 8 doesn't work on object elements
+ } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
+ var old = context.id, id = context.id = "__sizzle__";
+
+ try {
+ return makeArray( context.querySelectorAll( "#" + id + " " + query ), extra );
+
+ } catch(pseudoError) {
+ } finally {
+ if ( old ) {
+ context.id = old;
+
+ } else {
+ context.removeAttribute( "id" );
+ }
+ }
+ }
}
return oldSizzle(query, context, extra, seed);
@@ -3436,6 +3930,33 @@ if ( document.querySelectorAll ) {
}
(function(){
+ var html = document.documentElement,
+ matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector,
+ pseudoWorks = false;
+
+ try {
+ // This should fail with an exception
+ // Gecko does not error, returns false instead
+ matches.call( document.documentElement, ":sizzle" );
+
+ } catch( pseudoError ) {
+ pseudoWorks = true;
+ }
+
+ if ( matches ) {
+ Sizzle.matchesSelector = function( node, expr ) {
+ try {
+ if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) ) {
+ return matches.call( node, expr );
+ }
+ } catch(e) {}
+
+ return Sizzle(expr, null, null, [node]).length > 0;
+ };
+ }
+})();
+
+(function(){
var div = document.createElement("div");
div.innerHTML = "<div class='test e'></div><div class='test'></div>";
@@ -3532,13 +4053,13 @@ function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
}
}
-var contains = document.compareDocumentPosition ? function(a, b){
- return a.compareDocumentPosition(b) & 16;
-} : function(a, b){
+Sizzle.contains = document.documentElement.contains ? function(a, b){
return a !== b && (a.contains ? a.contains(b) : true);
+} : function(a, b){
+ return !!(a.compareDocumentPosition(b) & 16);
};
-var isXML = function(elem){
+Sizzle.isXML = function(elem){
// documentElement is verified for cases where it doesn't yet exist
// (such as loading iframes in IE - #4833)
var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
@@ -3570,49 +4091,21 @@ jQuery.find = Sizzle;
jQuery.expr = Sizzle.selectors;
jQuery.expr[":"] = jQuery.expr.filters;
jQuery.unique = Sizzle.uniqueSort;
-jQuery.getText = getText;
-jQuery.isXMLDoc = isXML;
-jQuery.contains = contains;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
-return;
-
-window.Sizzle = Sizzle;
})();
+
+
var runtil = /Until$/,
rparentsprev = /^(?:parents|prevUntil|prevAll)/,
// Note: This RegExp should be improved, or likely pulled from Sizzle
rmultiselector = /,/,
- slice = Array.prototype.slice;
-
-// Implement the identical functionality for filter and not
-var winnow = function( elements, qualifier, keep ) {
- if ( jQuery.isFunction( qualifier ) ) {
- return jQuery.grep(elements, function( elem, i ) {
- return !!qualifier.call( elem, i, elem ) === keep;
- });
-
- } else if ( qualifier.nodeType ) {
- return jQuery.grep(elements, function( elem, i ) {
- return (elem === qualifier) === keep;
- });
-
- } else if ( typeof qualifier === "string" ) {
- var filtered = jQuery.grep(elements, function( elem ) {
- return elem.nodeType === 1;
- });
-
- if ( isSimple.test( qualifier ) ) {
- return jQuery.filter(qualifier, filtered, !keep);
- } else {
- qualifier = jQuery.filter( qualifier, filtered );
- }
- }
-
- return jQuery.grep(elements, function( elem, i ) {
- return (jQuery.inArray( elem, qualifier ) >= 0) === keep;
- });
-};
+ isSimple = /^.[^:#\[\.,]*$/,
+ slice = Array.prototype.slice,
+ POS = jQuery.expr.match.POS;
jQuery.fn.extend({
find: function( selector ) {
@@ -3662,11 +4155,13 @@ jQuery.fn.extend({
},
closest: function( selectors, context ) {
+ var ret = [], i, l, cur = this[0];
+
if ( jQuery.isArray( selectors ) ) {
- var ret = [], cur = this[0], match, matches = {}, selector;
+ var match, matches = {}, selector, level = 1;
if ( cur && selectors.length ) {
- for ( var i = 0, l = selectors.length; i < l; i++ ) {
+ for ( i = 0, l = selectors.length; i < l; i++ ) {
selector = selectors[i];
if ( !matches[selector] ) {
@@ -3681,29 +4176,41 @@ jQuery.fn.extend({
match = matches[selector];
if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) {
- ret.push({ selector: selector, elem: cur });
- delete matches[selector];
+ ret.push({ selector: selector, elem: cur, level: level });
}
}
+
cur = cur.parentNode;
+ level++;
}
}
return ret;
}
- var pos = jQuery.expr.match.POS.test( selectors ) ?
+ var pos = POS.test( selectors ) ?
jQuery( selectors, context || this.context ) : null;
- return this.map(function( i, cur ) {
- while ( cur && cur.ownerDocument && cur !== context ) {
- if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selectors) ) {
- return cur;
+ for ( i = 0, l = this.length; i < l; i++ ) {
+ cur = this[i];
+
+ while ( cur ) {
+ if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
+ ret.push( cur );
+ break;
+
+ } else {
+ cur = cur.parentNode;
+ if ( !cur || !cur.ownerDocument || cur === context ) {
+ break;
+ }
}
- cur = cur.parentNode;
}
- return null;
- });
+ }
+
+ ret = ret.length > 1 ? jQuery.unique(ret) : ret;
+
+ return this.pushStack( ret, "closest", selectors );
},
// Determine the position of an element within
@@ -3811,7 +4318,9 @@ jQuery.extend({
expr = ":not(" + expr + ")";
}
- return jQuery.find.matches(expr, elems);
+ return elems.length === 1 ?
+ jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
+ jQuery.find.matches(expr, elems);
},
dir: function( elem, dir, until ) {
@@ -3850,19 +4359,49 @@ jQuery.extend({
return r;
}
});
+
+// Implement the identical functionality for filter and not
+function winnow( elements, qualifier, keep ) {
+ if ( jQuery.isFunction( qualifier ) ) {
+ return jQuery.grep(elements, function( elem, i ) {
+ var retVal = !!qualifier.call( elem, i, elem );
+ return retVal === keep;
+ });
+
+ } else if ( qualifier.nodeType ) {
+ return jQuery.grep(elements, function( elem, i ) {
+ return (elem === qualifier) === keep;
+ });
+
+ } else if ( typeof qualifier === "string" ) {
+ var filtered = jQuery.grep(elements, function( elem ) {
+ return elem.nodeType === 1;
+ });
+
+ if ( isSimple.test( qualifier ) ) {
+ return jQuery.filter(qualifier, filtered, !keep);
+ } else {
+ qualifier = jQuery.filter( qualifier, filtered );
+ }
+ }
+
+ return jQuery.grep(elements, function( elem, i ) {
+ return (jQuery.inArray( elem, qualifier ) >= 0) === keep;
+ });
+}
+
+
+
+
var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
rleadingWhitespace = /^\s+/,
- rxhtmlTag = /(<([\w:]+)[^>]*?)\/>/g,
- rselfClosing = /^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,
+ rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
rtagName = /<([\w:]+)/,
rtbody = /<tbody/i,
- rhtml = /<|&\w+;/,
+ rhtml = /<|&#?\w+;/,
+ rnocache = /<(?:script|object|embed|option|style)/i,
rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, // checked="checked" or checked (html5)
- fcloseTag = function( all, front, tag ) {
- return rselfClosing.test( tag ) ?
- all :
- front + "></" + tag + ">";
- },
+ raction = /\=([^="'>\s]+\/)>/g,
wrapMap = {
option: [ 1, "<select multiple='multiple'>", "</select>" ],
legend: [ 1, "<fieldset>", "</fieldset>" ],
@@ -3896,7 +4435,7 @@ jQuery.fn.extend({
return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
}
- return jQuery.getText( this );
+ return jQuery.text( this );
},
wrapAll: function( html ) {
@@ -4000,6 +4539,40 @@ jQuery.fn.extend({
return set;
}
},
+
+ // keepData is for internal use only--do not document
+ remove: function( selector, keepData ) {
+ for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
+ if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
+ if ( !keepData && elem.nodeType === 1 ) {
+ jQuery.cleanData( elem.getElementsByTagName("*") );
+ jQuery.cleanData( [ elem ] );
+ }
+
+ if ( elem.parentNode ) {
+ elem.parentNode.removeChild( elem );
+ }
+ }
+ }
+
+ return this;
+ },
+
+ empty: function() {
+ for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( elem.getElementsByTagName("*") );
+ }
+
+ // Remove any remaining nodes
+ while ( elem.firstChild ) {
+ elem.removeChild( elem.firstChild );
+ }
+ }
+
+ return this;
+ },
clone: function( events ) {
// Do the clone
@@ -4021,6 +4594,8 @@ jQuery.fn.extend({
}
return jQuery.clean([html.replace(rinlinejQuery, "")
+ // Handle the case in IE 8 where action=/test/> self-closes a tag
+ .replace(raction, '="$1">')
.replace(rleadingWhitespace, "")], ownerDocument)[0];
} else {
return this.cloneNode(true);
@@ -4044,11 +4619,11 @@ jQuery.fn.extend({
null;
// See if we can take a shortcut and just use innerHTML
- } else if ( typeof value === "string" && !/<script/i.test( value ) &&
+ } else if ( typeof value === "string" && !rnocache.test( value ) &&
(jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
!wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {
- value = value.replace(rxhtmlTag, fcloseTag);
+ value = value.replace(rxhtmlTag, "<$1></$2>");
try {
for ( var i = 0, l = this.length; i < l; i++ ) {
@@ -4066,10 +4641,8 @@ jQuery.fn.extend({
} else if ( jQuery.isFunction( value ) ) {
this.each(function(i){
- var self = jQuery(this), old = self.html();
- self.empty().append(function(){
- return value.call( this, i, old );
- });
+ var self = jQuery(this);
+ self.html( value.call(this, i, self.html()) );
});
} else {
@@ -4083,16 +4656,17 @@ jQuery.fn.extend({
if ( this[0] && this[0].parentNode ) {
// Make sure that the elements are removed from the DOM before they are inserted
// this can help fix replacing a parent with child elements
- if ( !jQuery.isFunction( value ) ) {
- value = jQuery( value ).detach();
-
- } else {
+ if ( jQuery.isFunction( value ) ) {
return this.each(function(i) {
var self = jQuery(this), old = self.html();
self.replaceWith( value.call( this, i, old ) );
});
}
+ if ( typeof value !== "string" ) {
+ value = jQuery(value).detach();
+ }
+
return this.each(function() {
var next = this.nextSibling, parent = this.parentNode;
@@ -4114,7 +4688,7 @@ jQuery.fn.extend({
},
domManip: function( args, table, callback ) {
- var results, first, value = args[0], scripts = [];
+ var results, first, value = args[0], scripts = [], fragment, parent;
// We can't cloneNode fragments that contain checked, in WebKit
if ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test( value ) ) {
@@ -4132,14 +4706,23 @@ jQuery.fn.extend({
}
if ( this[0] ) {
+ parent = value && value.parentNode;
+
// If we're in a fragment, just use that instead of building a new one
- if ( args[0] && args[0].parentNode && args[0].parentNode.nodeType === 11 ) {
- results = { fragment: args[0].parentNode };
+ if ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) {
+ results = { fragment: parent };
+
} else {
- results = buildFragment( args, this, scripts );
+ results = jQuery.buildFragment( args, this, scripts );
+ }
+
+ fragment = results.fragment;
+
+ if ( fragment.childNodes.length === 1 ) {
+ first = fragment = fragment.firstChild;
+ } else {
+ first = fragment.firstChild;
}
-
- first = results.fragment.firstChild;
if ( first ) {
table = table && jQuery.nodeName( first, "tr" );
@@ -4149,29 +4732,29 @@ jQuery.fn.extend({
table ?
root(this[i], first) :
this[i],
- results.cacheable || this.length > 1 || i > 0 ?
- results.fragment.cloneNode(true) :
- results.fragment
+ i > 0 || results.cacheable || this.length > 1 ?
+ fragment.cloneNode(true) :
+ fragment
);
}
}
- if ( scripts ) {
+ if ( scripts.length ) {
jQuery.each( scripts, evalScript );
}
}
return this;
-
- function root( elem, cur ) {
- return jQuery.nodeName(elem, "table") ?
- (elem.getElementsByTagName("tbody")[0] ||
- elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
- elem;
- }
}
});
+function root( elem, cur ) {
+ return jQuery.nodeName(elem, "table") ?
+ (elem.getElementsByTagName("tbody")[0] ||
+ elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
+ elem;
+}
+
function cloneCopyEvent(orig, ret) {
var i = 0;
@@ -4195,11 +4778,17 @@ function cloneCopyEvent(orig, ret) {
});
}
-function buildFragment( args, nodes, scripts ) {
- var fragment, cacheable, cacheresults, doc;
+jQuery.buildFragment = function( args, nodes, scripts ) {
+ var fragment, cacheable, cacheresults,
+ doc = (nodes && nodes[0] ? nodes[0].ownerDocument || nodes[0] : document);
+
+ // Only cache "small" (1/2 KB) strings that are associated with the main document
+ // Cloning options loses the selected state, so don't cache them
+ // IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
+ // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
+ if ( args.length === 1 && typeof args[0] === "string" && args[0].length < 512 && doc === document &&
+ !rnocache.test( args[0] ) && (jQuery.support.checkClone || !rchecked.test( args[0] )) ) {
- // webkit does not clone 'checked' attribute of radio inputs on cloneNode, so don't cache if string has a checked
- if ( args.length === 1 && typeof args[0] === "string" && args[0].length < 512 && args[0].indexOf("<option") < 0 && (jQuery.support.checkClone || !rchecked.test( args[0] )) ) {
cacheable = true;
cacheresults = jQuery.fragments[ args[0] ];
if ( cacheresults ) {
@@ -4210,7 +4799,6 @@ function buildFragment( args, nodes, scripts ) {
}
if ( !fragment ) {
- doc = (nodes && nodes[0] ? nodes[0].ownerDocument || nodes[0] : document);
fragment = doc.createDocumentFragment();
jQuery.clean( args, doc, fragment, scripts );
}
@@ -4220,7 +4808,7 @@ function buildFragment( args, nodes, scripts ) {
}
return { fragment: fragment, cacheable: cacheable };
-}
+};
jQuery.fragments = {};
@@ -4232,46 +4820,22 @@ jQuery.each({
replaceAll: "replaceWith"
}, function( name, original ) {
jQuery.fn[ name ] = function( selector ) {
- var ret = [], insert = jQuery( selector );
-
- for ( var i = 0, l = insert.length; i < l; i++ ) {
- var elems = (i > 0 ? this.clone(true) : this).get();
- jQuery.fn[ original ].apply( jQuery(insert[i]), elems );
- ret = ret.concat( elems );
- }
- return this.pushStack( ret, name, insert.selector );
- };
-});
-
-jQuery.each({
- // keepData is for internal use only--do not document
- remove: function( selector, keepData ) {
- if ( !selector || jQuery.filter( selector, [ this ] ).length ) {
- if ( !keepData && this.nodeType === 1 ) {
- jQuery.cleanData( this.getElementsByTagName("*") );
- jQuery.cleanData( [ this ] );
- }
-
- if ( this.parentNode ) {
- this.parentNode.removeChild( this );
+ var ret = [], insert = jQuery( selector ),
+ parent = this.length === 1 && this[0].parentNode;
+
+ if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {
+ insert[ original ]( this[0] );
+ return this;
+
+ } else {
+ for ( var i = 0, l = insert.length; i < l; i++ ) {
+ var elems = (i > 0 ? this.clone(true) : this).get();
+ jQuery( insert[i] )[ original ]( elems );
+ ret = ret.concat( elems );
}
+
+ return this.pushStack( ret, name, insert.selector );
}
- },
-
- empty: function() {
- // Remove element nodes and prevent memory leaks
- if ( this.nodeType === 1 ) {
- jQuery.cleanData( this.getElementsByTagName("*") );
- }
-
- // Remove any remaining nodes
- while ( this.firstChild ) {
- this.removeChild( this.firstChild );
- }
- }
-}, function( name, fn ) {
- jQuery.fn[ name ] = function() {
- return this.each( fn, arguments );
};
});
@@ -4286,13 +4850,13 @@ jQuery.extend({
var ret = [];
- jQuery.each(elems, function( i, elem ) {
+ for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
if ( typeof elem === "number" ) {
elem += "";
}
if ( !elem ) {
- return;
+ continue;
}
// Convert html string into DOM nodes
@@ -4301,7 +4865,7 @@ jQuery.extend({
} else if ( typeof elem === "string" ) {
// Fix "XHTML"-style tags in all browsers
- elem = elem.replace(rxhtmlTag, fcloseTag);
+ elem = elem.replace(rxhtmlTag, "<$1></$2>");
// Trim whitespace, otherwise indexOf won't work as expected
var tag = (rtagName.exec( elem ) || ["", ""])[1].toLowerCase(),
@@ -4343,7 +4907,7 @@ jQuery.extend({
div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
}
- elem = jQuery.makeArray( div.childNodes );
+ elem = div.childNodes;
}
if ( elem.nodeType ) {
@@ -4351,13 +4915,13 @@ jQuery.extend({
} else {
ret = jQuery.merge( ret, elem );
}
-
- });
+ }
if ( fragment ) {
- for ( var i = 0; ret[i]; i++ ) {
+ for ( i = 0; ret[i]; i++ ) {
if ( scripts && jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );
+
} else {
if ( ret[i].nodeType === 1 ) {
ret.splice.apply( ret, [i + 1, 0].concat(jQuery.makeArray(ret[i].getElementsByTagName("script"))) );
@@ -4371,258 +4935,388 @@ jQuery.extend({
},
cleanData: function( elems ) {
- for ( var i = 0, elem, id; (elem = elems[i]) != null; i++ ) {
- jQuery.event.remove( elem );
- jQuery.removeData( elem );
+ var data, id, cache = jQuery.cache,
+ special = jQuery.event.special,
+ deleteExpando = jQuery.support.deleteExpando;
+
+ for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+ if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
+ continue;
+ }
+
+ id = elem[ jQuery.expando ];
+
+ if ( id ) {
+ data = cache[ id ];
+
+ if ( data && data.events ) {
+ for ( var type in data.events ) {
+ if ( special[ type ] ) {
+ jQuery.event.remove( elem, type );
+
+ } else {
+ jQuery.removeEvent( elem, type, data.handle );
+ }
+ }
+ }
+
+ if ( deleteExpando ) {
+ delete elem[ jQuery.expando ];
+
+ } else if ( elem.removeAttribute ) {
+ elem.removeAttribute( jQuery.expando );
+ }
+
+ delete cache[ id ];
+ }
}
}
});
-// exclude the following css properties to add px
-var rexclude = /z-?index|font-?weight|opacity|zoom|line-?height/i,
- ralpha = /alpha\([^)]*\)/,
+
+function evalScript( i, elem ) {
+ if ( elem.src ) {
+ jQuery.ajax({
+ url: elem.src,
+ async: false,
+ dataType: "script"
+ });
+ } else {
+ jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );
+ }
+
+ if ( elem.parentNode ) {
+ elem.parentNode.removeChild( elem );
+ }
+}
+
+
+
+
+var ralpha = /alpha\([^)]*\)/i,
ropacity = /opacity=([^)]*)/,
- rfloat = /float/i,
rdashAlpha = /-([a-z])/ig,
rupper = /([A-Z])/g,
rnumpx = /^-?\d+(?:px)?$/i,
rnum = /^-?\d/,
- cssShow = { position: "absolute", visibility: "hidden", display:"block" },
+ cssShow = { position: "absolute", visibility: "hidden", display: "block" },
cssWidth = [ "Left", "Right" ],
cssHeight = [ "Top", "Bottom" ],
+ curCSS,
// cache check for defaultView.getComputedStyle
getComputedStyle = document.defaultView && document.defaultView.getComputedStyle,
- // normalize float css property
- styleFloat = jQuery.support.cssFloat ? "cssFloat" : "styleFloat",
+
fcamelCase = function( all, letter ) {
return letter.toUpperCase();
};
jQuery.fn.css = function( name, value ) {
- return access( this, name, value, true, function( elem, name, value ) {
- if ( value === undefined ) {
- return jQuery.curCSS( elem, name );
- }
-
- if ( typeof value === "number" && !rexclude.test(name) ) {
- value += "px";
- }
+ // Setting 'undefined' is a no-op
+ if ( arguments.length === 2 && value === undefined ) {
+ return this;
+ }
- jQuery.style( elem, name, value );
+ return jQuery.access( this, name, value, true, function( elem, name, value ) {
+ return value !== undefined ?
+ jQuery.style( elem, name, value ) :
+ jQuery.css( elem, name );
});
};
jQuery.extend({
- style: function( elem, name, value ) {
- // don't set styles on text and comment nodes
- if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
- return undefined;
+ // Add in style property hooks for overriding the default
+ // behavior of getting and setting a style property
+ cssHooks: {
+ opacity: {
+ get: function( elem, computed ) {
+ if ( computed ) {
+ // We should always get a number back from opacity
+ var ret = curCSS( elem, "opacity", "opacity" );
+ return ret === "" ? "1" : ret;
+
+ } else {
+ return elem.style.opacity;
+ }
+ }
}
+ },
+
+ // Exclude the following css properties to add px
+ cssNumber: {
+ "zIndex": true,
+ "fontWeight": true,
+ "opacity": true,
+ "zoom": true,
+ "lineHeight": true
+ },
+
+ // Add in properties whose names you wish to fix before
+ // setting or getting the value
+ cssProps: {
+ // normalize float css property
+ "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
+ },
- // ignore negative width and height values #1599
- if ( (name === "width" || name === "height") && parseFloat(value) < 0 ) {
- value = undefined;
+ // Get and set the style property on a DOM Node
+ style: function( elem, name, value, extra ) {
+ // Don't set styles on text and comment nodes
+ if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
+ return;
}
- var style = elem.style || elem, set = value !== undefined;
+ // Make sure that we're working with the right name
+ var ret, origName = jQuery.camelCase( name ),
+ style = elem.style, hooks = jQuery.cssHooks[ origName ];
- // IE uses filters for opacity
- if ( !jQuery.support.opacity && name === "opacity" ) {
- if ( set ) {
- // IE has trouble with opacity if it does not have layout
- // Force it by setting the zoom level
- style.zoom = 1;
+ name = jQuery.cssProps[ origName ] || origName;
- // Set the alpha filter to set the opacity
- var opacity = parseInt( value, 10 ) + "" === "NaN" ? "" : "alpha(opacity=" + value * 100 + ")";
- var filter = style.filter || jQuery.curCSS( elem, "filter" ) || "";
- style.filter = ralpha.test(filter) ? filter.replace(ralpha, opacity) : opacity;
+ // Check if we're setting a value
+ if ( value !== undefined ) {
+ // Make sure that NaN and null values aren't set. See: #7116
+ if ( typeof value === "number" && isNaN( value ) || value == null ) {
+ return;
}
- return style.filter && style.filter.indexOf("opacity=") >= 0 ?
- (parseFloat( ropacity.exec(style.filter)[1] ) / 100) + "":
- "";
- }
+ // If a number was passed in, add 'px' to the (except for certain CSS properties)
+ if ( typeof value === "number" && !jQuery.cssNumber[ origName ] ) {
+ value += "px";
+ }
- // Make sure we're using the right name for getting the float value
- if ( rfloat.test( name ) ) {
- name = styleFloat;
- }
+ // If a hook was provided, use that value, otherwise just set the specified value
+ if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value )) !== undefined ) {
+ // Wrapped to prevent IE from throwing errors when 'invalid' values are provided
+ // Fixes bug #5509
+ try {
+ style[ name ] = value;
+ } catch(e) {}
+ }
- name = name.replace(rdashAlpha, fcamelCase);
+ } else {
+ // If a hook was provided get the non-computed value from there
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
+ return ret;
+ }
- if ( set ) {
- style[ name ] = value;
+ // Otherwise just get the value from the style object
+ return style[ name ];
}
-
- return style[ name ];
},
- css: function( elem, name, force, extra ) {
- if ( name === "width" || name === "height" ) {
- var val, props = cssShow, which = name === "width" ? cssWidth : cssHeight;
+ css: function( elem, name, extra ) {
+ // Make sure that we're working with the right name
+ var ret, origName = jQuery.camelCase( name ),
+ hooks = jQuery.cssHooks[ origName ];
- function getWH() {
- val = name === "width" ? elem.offsetWidth : elem.offsetHeight;
-
- if ( extra === "border" ) {
- return;
- }
+ name = jQuery.cssProps[ origName ] || origName;
- jQuery.each( which, function() {
- if ( !extra ) {
- val -= parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0;
- }
+ // If a hook was provided get the computed value from there
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) {
+ return ret;
- if ( extra === "margin" ) {
- val += parseFloat(jQuery.curCSS( elem, "margin" + this, true)) || 0;
- } else {
- val -= parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0;
- }
- });
- }
+ // Otherwise, if a way to get the computed value exists, use that
+ } else if ( curCSS ) {
+ return curCSS( elem, name, origName );
+ }
+ },
- if ( elem.offsetWidth !== 0 ) {
- getWH();
- } else {
- jQuery.swap( elem, props, getWH );
- }
+ // A method for quickly swapping in/out CSS properties to get correct calculations
+ swap: function( elem, options, callback ) {
+ var old = {};
- return Math.max(0, Math.round(val));
+ // Remember the old values, and insert the new ones
+ for ( var name in options ) {
+ old[ name ] = elem.style[ name ];
+ elem.style[ name ] = options[ name ];
}
- return jQuery.curCSS( elem, name, force );
- },
+ callback.call( elem );
- curCSS: function( elem, name, force ) {
- var ret, style = elem.style, filter;
+ // Revert the old values
+ for ( name in options ) {
+ elem.style[ name ] = old[ name ];
+ }
+ },
- // IE uses filters for opacity
- if ( !jQuery.support.opacity && name === "opacity" && elem.currentStyle ) {
- ret = ropacity.test(elem.currentStyle.filter || "") ?
- (parseFloat(RegExp.$1) / 100) + "" :
- "";
+ camelCase: function( string ) {
+ return string.replace( rdashAlpha, fcamelCase );
+ }
+});
- return ret === "" ?
- "1" :
- ret;
- }
+// DEPRECATED, Use jQuery.css() instead
+jQuery.curCSS = jQuery.css;
- // Make sure we're using the right name for getting the float value
- if ( rfloat.test( name ) ) {
- name = styleFloat;
- }
+jQuery.each(["height", "width"], function( i, name ) {
+ jQuery.cssHooks[ name ] = {
+ get: function( elem, computed, extra ) {
+ var val;
- if ( !force && style && style[ name ] ) {
- ret = style[ name ];
+ if ( computed ) {
+ if ( elem.offsetWidth !== 0 ) {
+ val = getWH( elem, name, extra );
- } else if ( getComputedStyle ) {
+ } else {
+ jQuery.swap( elem, cssShow, function() {
+ val = getWH( elem, name, extra );
+ });
+ }
- // Only "float" is needed here
- if ( rfloat.test( name ) ) {
- name = "float";
+ return val + "px";
}
+ },
- name = name.replace( rupper, "-$1" ).toLowerCase();
+ set: function( elem, value ) {
+ if ( rnumpx.test( value ) ) {
+ // ignore negative width and height values #1599
+ value = parseFloat(value);
- var defaultView = elem.ownerDocument.defaultView;
+ if ( value >= 0 ) {
+ return value + "px";
+ }
- if ( !defaultView ) {
- return null;
+ } else {
+ return value;
}
+ }
+ };
+});
- var computedStyle = defaultView.getComputedStyle( elem, null );
+if ( !jQuery.support.opacity ) {
+ jQuery.cssHooks.opacity = {
+ get: function( elem, computed ) {
+ // IE uses filters for opacity
+ return ropacity.test((computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "") ?
+ (parseFloat(RegExp.$1) / 100) + "" :
+ computed ? "1" : "";
+ },
- if ( computedStyle ) {
- ret = computedStyle.getPropertyValue( name );
- }
+ set: function( elem, value ) {
+ var style = elem.style;
- // We should always get a number back from opacity
- if ( name === "opacity" && ret === "" ) {
- ret = "1";
- }
+ // IE has trouble with opacity if it does not have layout
+ // Force it by setting the zoom level
+ style.zoom = 1;
- } else if ( elem.currentStyle ) {
- var camelCase = name.replace(rdashAlpha, fcamelCase);
+ // Set the alpha filter to set the opacity
+ var opacity = jQuery.isNaN(value) ?
+ "" :
+ "alpha(opacity=" + value * 100 + ")",
+ filter = style.filter || "";
- ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ];
+ style.filter = ralpha.test(filter) ?
+ filter.replace(ralpha, opacity) :
+ style.filter + ' ' + opacity;
+ }
+ };
+}
- // From the awesome hack by Dean Edwards
- // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+if ( getComputedStyle ) {
+ curCSS = function( elem, newName, name ) {
+ var ret, defaultView, computedStyle;
- // If we're not dealing with a regular pixel number
- // but a number that has a weird ending, we need to convert it to pixels
- if ( !rnumpx.test( ret ) && rnum.test( ret ) ) {
- // Remember the original values
- var left = style.left, rsLeft = elem.runtimeStyle.left;
+ name = name.replace( rupper, "-$1" ).toLowerCase();
- // Put in the new values to get a computed value out
- elem.runtimeStyle.left = elem.currentStyle.left;
- style.left = camelCase === "fontSize" ? "1em" : (ret || 0);
- ret = style.pixelLeft + "px";
+ if ( !(defaultView = elem.ownerDocument.defaultView) ) {
+ return undefined;
+ }
- // Revert the changed values
- style.left = left;
- elem.runtimeStyle.left = rsLeft;
+ if ( (computedStyle = defaultView.getComputedStyle( elem, null )) ) {
+ ret = computedStyle.getPropertyValue( name );
+ if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
+ ret = jQuery.style( elem, name );
}
}
return ret;
- },
+ };
- // A method for quickly swapping in/out CSS properties to get correct calculations
- swap: function( elem, options, callback ) {
- var old = {};
+} else if ( document.documentElement.currentStyle ) {
+ curCSS = function( elem, name ) {
+ var left, rsLeft, ret = elem.currentStyle && elem.currentStyle[ name ], style = elem.style;
- // Remember the old values, and insert the new ones
- for ( var name in options ) {
- old[ name ] = elem.style[ name ];
- elem.style[ name ] = options[ name ];
- }
+ // From the awesome hack by Dean Edwards
+ // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
- callback.call( elem );
+ // If we're not dealing with a regular pixel number
+ // but a number that has a weird ending, we need to convert it to pixels
+ if ( !rnumpx.test( ret ) && rnum.test( ret ) ) {
+ // Remember the original values
+ left = style.left;
+ rsLeft = elem.runtimeStyle.left;
- // Revert the old values
- for ( var name in options ) {
- elem.style[ name ] = old[ name ];
+ // Put in the new values to get a computed value out
+ elem.runtimeStyle.left = elem.currentStyle.left;
+ style.left = name === "fontSize" ? "1em" : (ret || 0);
+ ret = style.pixelLeft + "px";
+
+ // Revert the changed values
+ style.left = left;
+ elem.runtimeStyle.left = rsLeft;
}
+
+ return ret;
+ };
+}
+
+function getWH( elem, name, extra ) {
+ var which = name === "width" ? cssWidth : cssHeight,
+ val = name === "width" ? elem.offsetWidth : elem.offsetHeight;
+
+ if ( extra === "border" ) {
+ return val;
}
-});
+
+ jQuery.each( which, function() {
+ if ( !extra ) {
+ val -= parseFloat(jQuery.css( elem, "padding" + this )) || 0;
+ }
+
+ if ( extra === "margin" ) {
+ val += parseFloat(jQuery.css( elem, "margin" + this )) || 0;
+
+ } else {
+ val -= parseFloat(jQuery.css( elem, "border" + this + "Width" )) || 0;
+ }
+ });
+
+ return val;
+}
if ( jQuery.expr && jQuery.expr.filters ) {
jQuery.expr.filters.hidden = function( elem ) {
- var width = elem.offsetWidth, height = elem.offsetHeight,
- skip = elem.nodeName.toLowerCase() === "tr";
-
- return width === 0 && height === 0 && !skip ?
- true :
- width > 0 && height > 0 && !skip ?
- false :
- jQuery.curCSS(elem, "display") === "none";
+ var width = elem.offsetWidth, height = elem.offsetHeight;
+
+ return (width === 0 && height === 0) || (!jQuery.support.reliableHiddenOffsets && (elem.style.display || jQuery.css( elem, "display" )) === "none");
};
jQuery.expr.filters.visible = function( elem ) {
return !jQuery.expr.filters.hidden( elem );
};
}
-var jsc = now(),
- rscript = /<script(.|\s)*?\/script>/gi,
- rselectTextarea = /select|textarea/i,
- rinput = /color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,
- jsre = /=\?(&|$)/,
+
+
+
+
+var jsc = jQuery.now(),
+ rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
+ rselectTextarea = /^(?:select|textarea)/i,
+ rinput = /^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
+ rnoContent = /^(?:GET|HEAD|DELETE)$/,
+ rbracket = /\[\]$/,
+ jsre = /\=\?(&|$)/,
rquery = /\?/,
- rts = /(\?|&)_=.*?(&|$)/,
+ rts = /([?&])_=[^&]*/,
rurl = /^(\w+:)?\/\/([^\/?#]+)/,
- r20 = /%20/g;
+ r20 = /%20/g,
+ rhash = /#.*$/,
-jQuery.fn.extend({
- // Keep a copy of the old load
- _load: jQuery.fn.load,
+ // Keep a copy of the old load method
+ _load = jQuery.fn.load;
+jQuery.fn.extend({
load: function( url, params, callback ) {
- if ( typeof url !== "string" ) {
- return this._load( url );
+ if ( typeof url !== "string" && _load ) {
+ return _load.apply( this, arguments );
// Don't do a request if no elements are being requested
} else if ( !this.length ) {
@@ -4667,7 +5361,7 @@ jQuery.fn.extend({
// See if a selector was specified
self.html( selector ?
// Create a dummy div to hold the results
- jQuery("<div />")
+ jQuery("<div>")
// inject the contents of the document in, removing the scripts
// to avoid any 'Permission Denied' errors in IE
.append(res.responseText.replace(rscript, ""))
@@ -4691,6 +5385,7 @@ jQuery.fn.extend({
serialize: function() {
return jQuery.param(this.serializeArray());
},
+
serializeArray: function() {
return this.map(function() {
return this.elements ? jQuery.makeArray(this.elements) : this;
@@ -4722,7 +5417,6 @@ jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".sp
});
jQuery.extend({
-
get: function( url, data, callback, type ) {
// shift arguments if data argument was omited
if ( jQuery.isFunction( data ) ) {
@@ -4783,19 +5477,10 @@ jQuery.extend({
password: null,
traditional: false,
*/
- // Create the request object; Microsoft failed to properly
- // implement the XMLHttpRequest in IE7 (can't request local files),
- // so we use the ActiveXObject when it is available
// This function can be overriden by calling jQuery.ajaxSetup
- xhr: window.XMLHttpRequest && (window.location.protocol !== "file:" || !window.ActiveXObject) ?
- function() {
- return new window.XMLHttpRequest();
- } :
- function() {
- try {
- return new window.ActiveXObject("Microsoft.XMLHTTP");
- } catch(e) {}
- },
+ xhr: function() {
+ return new window.XMLHttpRequest();
+ },
accepts: {
xml: "application/xml, text/xml",
html: "text/html",
@@ -4806,16 +5491,14 @@ jQuery.extend({
}
},
- // Last-Modified header cache for next request
- lastModified: {},
- etag: {},
-
ajax: function( origSettings ) {
- var s = jQuery.extend(true, {}, jQuery.ajaxSettings, origSettings);
-
- var jsonp, status, data,
- callbackContext = origSettings && origSettings.context || s,
- type = s.type.toUpperCase();
+ var s = jQuery.extend(true, {}, jQuery.ajaxSettings, origSettings),
+ jsonp, status, data, type = s.type.toUpperCase(), noContent = rnoContent.test(type);
+
+ s.url = s.url.replace( rhash, "" );
+
+ // Use original (not extended) context object if it was provided
+ s.context = origSettings && origSettings.context != null ? origSettings.context : s;
// convert data if not already a string
if ( s.data && s.processData && typeof s.data !== "string" ) {
@@ -4850,17 +5533,25 @@ jQuery.extend({
s.dataType = "script";
// Handle JSONP-style loading
- window[ jsonp ] = window[ jsonp ] || function( tmp ) {
+ var customJsonp = window[ jsonp ];
+
+ window[ jsonp ] = function( tmp ) {
data = tmp;
- success();
- complete();
- // Garbage collect
- window[ jsonp ] = undefined;
+ jQuery.handleSuccess( s, xhr, status, data );
+ jQuery.handleComplete( s, xhr, status, data );
- try {
- delete window[ jsonp ];
- } catch(e) {}
+ if ( jQuery.isFunction( customJsonp ) ) {
+ customJsonp( tmp );
+
+ } else {
+ // Garbage collect
+ window[ jsonp ] = undefined;
+ try {
+ delete window[ jsonp ];
+ } catch( jsonpError ) {}
+ }
+
if ( head ) {
head.removeChild( script );
}
@@ -4872,10 +5563,10 @@ jQuery.extend({
}
if ( s.cache === false && type === "GET" ) {
- var ts = now();
+ var ts = jQuery.now();
// try replacing _= if it is there
- var ret = s.url.replace(rts, "$1_=" + ts + "$2");
+ var ret = s.url.replace(rts, "$1_=" + ts);
// if nothing was replaced, add timestamp to the end
s.url = ret + ((ret === s.url) ? (rquery.test(s.url) ? "&" : "?") + "_=" + ts : "");
@@ -4887,7 +5578,7 @@ jQuery.extend({
}
// Watch for a new set of requests
- if ( s.global && ! jQuery.active++ ) {
+ if ( s.global && jQuery.active++ === 0 ) {
jQuery.event.trigger( "ajaxStart" );
}
@@ -4900,10 +5591,10 @@ jQuery.extend({
if ( s.dataType === "script" && type === "GET" && remote ) {
var head = document.getElementsByTagName("head")[0] || document.documentElement;
var script = document.createElement("script");
- script.src = s.url;
if ( s.scriptCharset ) {
script.charset = s.scriptCharset;
}
+ script.src = s.url;
// Handle Script loading
if ( !jsonp ) {
@@ -4914,8 +5605,8 @@ jQuery.extend({
if ( !done && (!this.readyState ||
this.readyState === "loaded" || this.readyState === "complete") ) {
done = true;
- success();
- complete();
+ jQuery.handleSuccess( s, xhr, status, data );
+ jQuery.handleComplete( s, xhr, status, data );
// Handle memory leak in IE
script.onload = script.onreadystatechange = null;
@@ -4953,8 +5644,8 @@ jQuery.extend({
// Need an extra try/catch for cross domain requests in Firefox 3
try {
- // Set the correct header, if data is being sent
- if ( s.data || origSettings && origSettings.contentType ) {
+ // Set content-type if data specified and content-body is valid for this type
+ if ( (s.data != null && !noContent) || (origSettings && origSettings.contentType) ) {
xhr.setRequestHeader("Content-Type", s.contentType);
}
@@ -4977,14 +5668,14 @@ jQuery.extend({
// Set the Accepts header for the server, depending on the dataType
xhr.setRequestHeader("Accept", s.dataType && s.accepts[ s.dataType ] ?
- s.accepts[ s.dataType ] + ", */*" :
+ s.accepts[ s.dataType ] + ", */*; q=0.01" :
s.accepts._default );
- } catch(e) {}
+ } catch( headerError ) {}
// Allow custom headers/mimetypes and early abort
- if ( s.beforeSend && s.beforeSend.call(callbackContext, xhr, s) === false ) {
+ if ( s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false ) {
// Handle the global AJAX counter
- if ( s.global && ! --jQuery.active ) {
+ if ( s.global && jQuery.active-- === 1 ) {
jQuery.event.trigger( "ajaxStop" );
}
@@ -4994,7 +5685,7 @@ jQuery.extend({
}
if ( s.global ) {
- trigger("ajaxSend", [xhr, s]);
+ jQuery.triggerGlobal( s, "ajaxSend", [xhr, s] );
}
// Wait for a response to come back
@@ -5004,7 +5695,7 @@ jQuery.extend({
// Opera doesn't call onreadystatechange before this point
// so we simulate the call
if ( !requestDone ) {
- complete();
+ jQuery.handleComplete( s, xhr, status, data );
}
requestDone = true;
@@ -5032,9 +5723,9 @@ jQuery.extend({
try {
// process the data (runs the xml through httpData regardless of callback)
data = jQuery.httpData( xhr, s.dataType, s );
- } catch(err) {
+ } catch( parserError ) {
status = "parsererror";
- errMsg = err;
+ errMsg = parserError;
}
}
@@ -5042,14 +5733,16 @@ jQuery.extend({
if ( status === "success" || status === "notmodified" ) {
// JSONP handles its own success callback
if ( !jsonp ) {
- success();
+ jQuery.handleSuccess( s, xhr, status, data );
}
} else {
- jQuery.handleError(s, xhr, status, errMsg);
+ jQuery.handleError( s, xhr, status, errMsg );
}
// Fire the complete handlers
- complete();
+ if ( !jsonp ) {
+ jQuery.handleComplete( s, xhr, status, data );
+ }
if ( isTimeout === "timeout" ) {
xhr.abort();
@@ -5062,18 +5755,20 @@ jQuery.extend({
}
};
- // Override the abort handler, if we can (IE doesn't allow it, but that's OK)
+ // Override the abort handler, if we can (IE 6 doesn't allow it, but that's OK)
// Opera doesn't fire onreadystatechange at all on abort
try {
var oldAbort = xhr.abort;
xhr.abort = function() {
- if ( xhr ) {
+ // xhr.abort in IE7 is not a native JS function
+ // and does not have a call property
+ if ( xhr && oldAbort.call ) {
oldAbort.call( xhr );
}
onreadystatechange( "abort" );
};
- } catch(e) { }
+ } catch( abortError ) {}
// Timeout checker
if ( s.async && s.timeout > 0 ) {
@@ -5087,11 +5782,13 @@ jQuery.extend({
// Send the data
try {
- xhr.send( type === "POST" || type === "PUT" || type === "DELETE" ? s.data : null );
- } catch(e) {
- jQuery.handleError(s, xhr, null, e);
+ xhr.send( noContent || s.data == null ? null : s.data );
+
+ } catch( sendError ) {
+ jQuery.handleError( s, xhr, null, sendError );
+
// Fire the complete handlers
- complete();
+ jQuery.handleComplete( s, xhr, status, data );
}
// firefox 1.5 doesn't fire statechange for sync requests
@@ -5099,66 +5796,144 @@ jQuery.extend({
onreadystatechange();
}
- function success() {
- // If a local callback was specified, fire it and pass it the data
- if ( s.success ) {
- s.success.call( callbackContext, data, status, xhr );
- }
+ // return XMLHttpRequest to allow aborting the request etc.
+ return xhr;
+ },
- // Fire the global callback
- if ( s.global ) {
- trigger( "ajaxSuccess", [xhr, s] );
+ // Serialize an array of form elements or a set of
+ // key/values into a query string
+ param: function( a, traditional ) {
+ var s = [], add = function( key, value ) {
+ // If value is a function, invoke it and return its value
+ value = jQuery.isFunction(value) ? value() : value;
+ s[ s.length ] = encodeURIComponent(key) + "=" + encodeURIComponent(value);
+ };
+
+ // Set traditional to true for jQuery <= 1.3.2 behavior.
+ if ( traditional === undefined ) {
+ traditional = jQuery.ajaxSettings.traditional;
+ }
+
+ // If an array was passed in, assume that it is an array of form elements.
+ if ( jQuery.isArray(a) || a.jquery ) {
+ // Serialize the form elements
+ jQuery.each( a, function() {
+ add( this.name, this.value );
+ });
+
+ } else {
+ // If traditional, encode the "old" way (the way 1.3.2 or older
+ // did it), otherwise encode params recursively.
+ for ( var prefix in a ) {
+ buildParams( prefix, a[prefix], traditional, add );
}
}
- function complete() {
- // Process result
- if ( s.complete ) {
- s.complete.call( callbackContext, xhr, status);
- }
+ // Return the resulting serialization
+ return s.join("&").replace(r20, "+");
+ }
+});
- // The request was completed
- if ( s.global ) {
- trigger( "ajaxComplete", [xhr, s] );
- }
+function buildParams( prefix, obj, traditional, add ) {
+ if ( jQuery.isArray(obj) && obj.length ) {
+ // Serialize array item.
+ jQuery.each( obj, function( i, v ) {
+ if ( traditional || rbracket.test( prefix ) ) {
+ // Treat each array item as a scalar.
+ add( prefix, v );
- // Handle the global AJAX counter
- if ( s.global && ! --jQuery.active ) {
- jQuery.event.trigger( "ajaxStop" );
+ } else {
+ // If array item is non-scalar (array or object), encode its
+ // numeric index to resolve deserialization ambiguity issues.
+ // Note that rack (as of 1.0.0) can't currently deserialize
+ // nested arrays properly, and attempting to do so may cause
+ // a server error. Possible fixes are to modify rack's
+ // deserialization algorithm or to provide an option or flag
+ // to force array serialization to be shallow.
+ buildParams( prefix + "[" + ( typeof v === "object" || jQuery.isArray(v) ? i : "" ) + "]", v, traditional, add );
}
+ });
+
+ } else if ( !traditional && obj != null && typeof obj === "object" ) {
+ if ( jQuery.isEmptyObject( obj ) ) {
+ add( prefix, "" );
+
+ // Serialize object item.
+ } else {
+ jQuery.each( obj, function( k, v ) {
+ buildParams( prefix + "[" + k + "]", v, traditional, add );
+ });
}
-
- function trigger(type, args) {
- (s.context ? jQuery(s.context) : jQuery.event).trigger(type, args);
- }
+
+ } else {
+ // Serialize scalar item.
+ add( prefix, obj );
+ }
+}
- // return XMLHttpRequest to allow aborting the request etc.
- return xhr;
- },
+// This is still on the jQuery object... for now
+// Want to move this to jQuery.ajax some day
+jQuery.extend({
+
+ // Counter for holding the number of active queries
+ active: 0,
+
+ // Last-Modified header cache for next request
+ lastModified: {},
+ etag: {},
handleError: function( s, xhr, status, e ) {
// If a local callback was specified, fire it
if ( s.error ) {
- s.error.call( s.context || s, xhr, status, e );
+ s.error.call( s.context, xhr, status, e );
}
// Fire the global callback
if ( s.global ) {
- (s.context ? jQuery(s.context) : jQuery.event).trigger( "ajaxError", [xhr, s, e] );
+ jQuery.triggerGlobal( s, "ajaxError", [xhr, s, e] );
}
},
- // Counter for holding the number of active queries
- active: 0,
+ handleSuccess: function( s, xhr, status, data ) {
+ // If a local callback was specified, fire it and pass it the data
+ if ( s.success ) {
+ s.success.call( s.context, data, status, xhr );
+ }
+
+ // Fire the global callback
+ if ( s.global ) {
+ jQuery.triggerGlobal( s, "ajaxSuccess", [xhr, s] );
+ }
+ },
+
+ handleComplete: function( s, xhr, status ) {
+ // Process result
+ if ( s.complete ) {
+ s.complete.call( s.context, xhr, status );
+ }
+
+ // The request was completed
+ if ( s.global ) {
+ jQuery.triggerGlobal( s, "ajaxComplete", [xhr, s] );
+ }
+
+ // Handle the global AJAX counter
+ if ( s.global && jQuery.active-- === 1 ) {
+ jQuery.event.trigger( "ajaxStop" );
+ }
+ },
+
+ triggerGlobal: function( s, type, args ) {
+ (s.context && s.context.url == null ? jQuery(s.context) : jQuery.event).trigger(type, args);
+ },
// Determines if an XMLHttpRequest was successful or not
httpSuccess: function( xhr ) {
try {
// IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450
return !xhr.status && location.protocol === "file:" ||
- // Opera returns 0 when status is 304
- ( xhr.status >= 200 && xhr.status < 300 ) ||
- xhr.status === 304 || xhr.status === 1223 || xhr.status === 0;
+ xhr.status >= 200 && xhr.status < 300 ||
+ xhr.status === 304 || xhr.status === 1223;
} catch(e) {}
return false;
@@ -5177,8 +5952,7 @@ jQuery.extend({
jQuery.etag[url] = etag;
}
- // Opera returns 0 when status is 304
- return xhr.status === 304 || xhr.status === 0;
+ return xhr.status === 304;
},
httpData: function( xhr, type, s ) {
@@ -5209,77 +5983,40 @@ jQuery.extend({
}
return data;
- },
+ }
- // Serialize an array of form elements or a set of
- // key/values into a query string
- param: function( a, traditional ) {
- var s = [];
-
- // Set traditional to true for jQuery <= 1.3.2 behavior.
- if ( traditional === undefined ) {
- traditional = jQuery.ajaxSettings.traditional;
- }
-
- // If an array was passed in, assume that it is an array of form elements.
- if ( jQuery.isArray(a) || a.jquery ) {
- // Serialize the form elements
- jQuery.each( a, function() {
- add( this.name, this.value );
- });
-
- } else {
- // If traditional, encode the "old" way (the way 1.3.2 or older
- // did it), otherwise encode params recursively.
- for ( var prefix in a ) {
- buildParams( prefix, a[prefix] );
- }
+});
+
+/*
+ * Create the request object; Microsoft failed to properly
+ * implement the XMLHttpRequest in IE7 (can't request local files),
+ * so we use the ActiveXObject when it is available
+ * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
+ * we need a fallback.
+ */
+if ( window.ActiveXObject ) {
+ jQuery.ajaxSettings.xhr = function() {
+ if ( window.location.protocol !== "file:" ) {
+ try {
+ return new window.XMLHttpRequest();
+ } catch(xhrError) {}
}
- // Return the resulting serialization
- return s.join("&").replace(r20, "+");
+ try {
+ return new window.ActiveXObject("Microsoft.XMLHTTP");
+ } catch(activeError) {}
+ };
+}
+
+// Does this browser support XHR requests?
+jQuery.support.ajax = !!jQuery.ajaxSettings.xhr();
+
+
- function buildParams( prefix, obj ) {
- if ( jQuery.isArray(obj) ) {
- // Serialize array item.
- jQuery.each( obj, function( i, v ) {
- if ( traditional ) {
- // Treat each array item as a scalar.
- add( prefix, v );
- } else {
- // If array item is non-scalar (array or object), encode its
- // numeric index to resolve deserialization ambiguity issues.
- // Note that rack (as of 1.0.0) can't currently deserialize
- // nested arrays properly, and attempting to do so may cause
- // a server error. Possible fixes are to modify rack's
- // deserialization algorithm or to provide an option or flag
- // to force array serialization to be shallow.
- buildParams( prefix + "[" + ( typeof v === "object" || jQuery.isArray(v) ? i : "" ) + "]", v );
- }
- });
-
- } else if ( !traditional && obj != null && typeof obj === "object" ) {
- // Serialize object item.
- jQuery.each( obj, function( k, v ) {
- buildParams( prefix + "[" + k + "]", v );
- });
-
- } else {
- // Serialize scalar item.
- add( prefix, obj );
- }
- }
- function add( key, value ) {
- // If value is a function, invoke it and return its value
- value = jQuery.isFunction(value) ? value() : value;
- s[ s.length ] = encodeURIComponent(key) + "=" + encodeURIComponent(value);
- }
- }
-});
var elemdisplay = {},
- rfxtypes = /toggle|show|hide/,
- rfxnum = /^([+-]=)?([\d+-.]+)(.*)$/,
+ rfxtypes = /^(?:toggle|show|hide)$/,
+ rfxnum = /^([+\-]=)?([\d+.\-]+)(.*)$/,
timerId,
fxAttrs = [
// height animations
@@ -5291,66 +6028,52 @@ var elemdisplay = {},
];
jQuery.fn.extend({
- show: function( speed, callback ) {
- if ( speed || speed === 0) {
- return this.animate( genFx("show", 3), speed, callback);
-
+ show: function( speed, easing, callback ) {
+ if ( speed || speed === 0 ) {
+ return this.animate( genFx("show", 3), speed, easing, callback);
} else {
- for ( var i = 0, l = this.length; i < l; i++ ) {
- var old = jQuery.data(this[i], "olddisplay");
-
- this[i].style.display = old || "";
-
- if ( jQuery.css(this[i], "display") === "none" ) {
- var nodeName = this[i].nodeName, display;
-
- if ( elemdisplay[ nodeName ] ) {
- display = elemdisplay[ nodeName ];
-
- } else {
- var elem = jQuery("<" + nodeName + " />").appendTo("body");
-
- display = elem.css("display");
-
- if ( display === "none" ) {
- display = "block";
- }
-
- elem.remove();
-
- elemdisplay[ nodeName ] = display;
- }
+ for ( var i = 0, j = this.length; i < j; i++ ) {
+ // Reset the inline display of this element to learn if it is
+ // being hidden by cascaded rules or not
+ if ( !jQuery.data(this[i], "olddisplay") && this[i].style.display === "none" ) {
+ this[i].style.display = "";
+ }
- jQuery.data(this[i], "olddisplay", display);
+ // Set elements which have been overridden with display: none
+ // in a stylesheet to whatever the default browser style is
+ // for such an element
+ if ( this[i].style.display === "" && jQuery.css( this[i], "display" ) === "none" ) {
+ jQuery.data(this[i], "olddisplay", defaultDisplay(this[i].nodeName));
}
}
- // Set the display of the elements in a second loop
+ // Set the display of most of the elements in a second loop
// to avoid the constant reflow
- for ( var j = 0, k = this.length; j < k; j++ ) {
- this[j].style.display = jQuery.data(this[j], "olddisplay") || "";
+ for ( i = 0; i < j; i++ ) {
+ this[i].style.display = jQuery.data(this[i], "olddisplay") || "";
}
return this;
}
},
- hide: function( speed, callback ) {
+ hide: function( speed, easing, callback ) {
if ( speed || speed === 0 ) {
- return this.animate( genFx("hide", 3), speed, callback);
+ return this.animate( genFx("hide", 3), speed, easing, callback);
} else {
- for ( var i = 0, l = this.length; i < l; i++ ) {
- var old = jQuery.data(this[i], "olddisplay");
- if ( !old && old !== "none" ) {
- jQuery.data(this[i], "olddisplay", jQuery.css(this[i], "display"));
+ for ( var i = 0, j = this.length; i < j; i++ ) {
+ var display = jQuery.css( this[i], "display" );
+
+ if ( display !== "none" ) {
+ jQuery.data( this[i], "olddisplay", display );
}
}
// Set the display of the elements in a second loop
// to avoid the constant reflow
- for ( var j = 0, k = this.length; j < k; j++ ) {
- this[j].style.display = "none";
+ for ( i = 0; i < j; i++ ) {
+ this[i].style.display = "none";
}
return this;
@@ -5360,7 +6083,7 @@ jQuery.fn.extend({
// Save the old toggle function
_toggle: jQuery.fn.toggle,
- toggle: function( fn, fn2 ) {
+ toggle: function( fn, fn2, callback ) {
var bool = typeof fn === "boolean";
if ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {
@@ -5373,15 +6096,15 @@ jQuery.fn.extend({
});
} else {
- this.animate(genFx("toggle", 3), fn, fn2);
+ this.animate(genFx("toggle", 3), fn, fn2, callback);
}
return this;
},
- fadeTo: function( speed, to, callback ) {
+ fadeTo: function( speed, to, easing, callback ) {
return this.filter(":hidden").css("opacity", 0).show().end()
- .animate({opacity: to}, speed, callback);
+ .animate({opacity: to}, speed, easing, callback);
},
animate: function( prop, speed, easing, callback ) {
@@ -5392,12 +6115,16 @@ jQuery.fn.extend({
}
return this[ optall.queue === false ? "each" : "queue" ](function() {
+ // XXX ‘this’ does not always have a nodeName when running the
+ // test suite
+
var opt = jQuery.extend({}, optall), p,
- hidden = this.nodeType === 1 && jQuery(this).is(":hidden"),
+ isElement = this.nodeType === 1,
+ hidden = isElement && jQuery(this).is(":hidden"),
self = this;
for ( p in prop ) {
- var name = p.replace(rdashAlpha, fcamelCase);
+ var name = jQuery.camelCase( p );
if ( p !== name ) {
prop[ name ] = prop[ p ];
@@ -5409,12 +6136,35 @@ jQuery.fn.extend({
return opt.complete.call(this);
}
- if ( ( p === "height" || p === "width" ) && this.style ) {
- // Store display property
- opt.display = jQuery.css(this, "display");
-
+ if ( isElement && ( p === "height" || p === "width" ) ) {
// Make sure that nothing sneaks out
- opt.overflow = this.style.overflow;
+ // Record all 3 overflow attributes because IE does not
+ // change the overflow attribute when overflowX and
+ // overflowY are set to the same value
+ opt.overflow = [ this.style.overflow, this.style.overflowX, this.style.overflowY ];
+
+ // Set display property to inline-block for height/width
+ // animations on inline elements that are having width/height
+ // animated
+ if ( jQuery.css( this, "display" ) === "inline" &&
+ jQuery.css( this, "float" ) === "none" ) {
+ if ( !jQuery.support.inlineBlockNeedsLayout ) {
+ this.style.display = "inline-block";
+
+ } else {
+ var display = defaultDisplay(this.nodeName);
+
+ // inline-level elements accept inline-block;
+ // block-level elements need to be inline with layout
+ if ( display === "inline" ) {
+ this.style.display = "inline-block";
+
+ } else {
+ this.style.display = "inline";
+ this.style.zoom = 1;
+ }
+ }
+ }
}
if ( jQuery.isArray( prop[p] ) ) {
@@ -5446,9 +6196,9 @@ jQuery.fn.extend({
// We need to compute starting value
if ( unit !== "px" ) {
- self.style[ name ] = (end || 1) + unit;
+ jQuery.style( self, name, (end || 1) + unit);
start = ((end || 1) / e.cur(true)) * start;
- self.style[ name ] = start + unit;
+ jQuery.style( self, name, start + unit);
}
// If a +=/-= token was provided, we're doing a relative animation
@@ -5500,6 +6250,16 @@ jQuery.fn.extend({
});
+function genFx( type, num ) {
+ var obj = {};
+
+ jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function() {
+ obj[ this ] = type;
+ });
+
+ return obj;
+}
+
// Generate shortcuts for custom animations
jQuery.each({
slideDown: genFx("show", 1),
@@ -5508,14 +6268,14 @@ jQuery.each({
fadeIn: { opacity: "show" },
fadeOut: { opacity: "hide" }
}, function( name, props ) {
- jQuery.fn[ name ] = function( speed, callback ) {
- return this.animate( props, speed, callback );
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
+ return this.animate( props, speed, easing, callback );
};
});
jQuery.extend({
speed: function( speed, easing, fn ) {
- var opt = speed && typeof speed === "object" ? speed : {
+ var opt = speed && typeof speed === "object" ? jQuery.extend({}, speed) : {
complete: fn || !fn && easing ||
jQuery.isFunction( speed ) && speed,
duration: speed,
@@ -5523,7 +6283,7 @@ jQuery.extend({
};
opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
- jQuery.fx.speeds[opt.duration] || jQuery.fx.speeds._default;
+ opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[opt.duration] : jQuery.fx.speeds._default;
// Queueing
opt.old = opt.complete;
@@ -5570,33 +6330,28 @@ jQuery.fx.prototype = {
}
(jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );
-
- // Set display property to block for height/width animations
- if ( ( this.prop === "height" || this.prop === "width" ) && this.elem.style ) {
- this.elem.style.display = "block";
- }
},
// Get the current size
- cur: function( force ) {
+ cur: function() {
if ( this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null) ) {
return this.elem[ this.prop ];
}
- var r = parseFloat(jQuery.css(this.elem, this.prop, force));
- return r && r > -10000 ? r : parseFloat(jQuery.curCSS(this.elem, this.prop)) || 0;
+ var r = parseFloat( jQuery.css( this.elem, this.prop ) );
+ return r && r > -10000 ? r : 0;
},
// Start an animation from one number to another
custom: function( from, to, unit ) {
- this.startTime = now();
+ this.startTime = jQuery.now();
this.start = from;
this.end = to;
this.unit = unit || this.unit || "px";
this.now = this.start;
this.pos = this.state = 0;
- var self = this;
+ var self = this, fx = jQuery.fx;
function t( gotoEnd ) {
return self.step(gotoEnd);
}
@@ -5604,7 +6359,7 @@ jQuery.fx.prototype = {
t.elem = this.elem;
if ( t() && jQuery.timers.push(t) && !timerId ) {
- timerId = setInterval(jQuery.fx.tick, 13);
+ timerId = setInterval(fx.tick, fx.interval);
}
},
@@ -5635,7 +6390,7 @@ jQuery.fx.prototype = {
// Each step of an animation
step: function( gotoEnd ) {
- var t = now(), done = true;
+ var t = jQuery.now(), done = true;
if ( gotoEnd || t >= this.options.duration + this.startTime ) {
this.now = this.end;
@@ -5651,17 +6406,12 @@ jQuery.fx.prototype = {
}
if ( done ) {
- if ( this.options.display != null ) {
- // Reset the overflow
- this.elem.style.overflow = this.options.overflow;
-
- // Reset the display
- var old = jQuery.data(this.elem, "olddisplay");
- this.elem.style.display = old ? old : this.options.display;
-
- if ( jQuery.css(this.elem, "display") === "none" ) {
- this.elem.style.display = "block";
- }
+ // Reset the overflow
+ if ( this.options.overflow != null && !jQuery.support.shrinkWrapBlocks ) {
+ var elem = this.elem, options = this.options;
+ jQuery.each( [ "", "X", "Y" ], function (index, value) {
+ elem.style[ "overflow" + value ] = options.overflow[index];
+ } );
}
// Hide the element if the "hide" operation was done
@@ -5672,7 +6422,7 @@ jQuery.fx.prototype = {
// Reset the properties, if the item has been hidden or shown
if ( this.options.hide || this.options.show ) {
for ( var p in this.options.curAnim ) {
- jQuery.style(this.elem, p, this.options.orig[p]);
+ jQuery.style( this.elem, p, this.options.orig[p] );
}
}
@@ -5714,22 +6464,24 @@ jQuery.extend( jQuery.fx, {
jQuery.fx.stop();
}
},
-
+
+ interval: 13,
+
stop: function() {
clearInterval( timerId );
timerId = null;
},
-
+
speeds: {
slow: 600,
- fast: 200,
- // Default speed
- _default: 400
+ fast: 200,
+ // Default speed
+ _default: 400
},
step: {
opacity: function( fx ) {
- jQuery.style(fx.elem, "opacity", fx.now);
+ jQuery.style( fx.elem, "opacity", fx.now );
},
_default: function( fx ) {
@@ -5750,18 +6502,32 @@ if ( jQuery.expr && jQuery.expr.filters ) {
};
}
-function genFx( type, num ) {
- var obj = {};
+function defaultDisplay( nodeName ) {
+ if ( !elemdisplay[ nodeName ] ) {
+ var elem = jQuery("<" + nodeName + ">").appendTo("body"),
+ display = elem.css("display");
- jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function() {
- obj[ this ] = type;
- });
+ elem.remove();
- return obj;
+ if ( display === "none" || display === "" ) {
+ display = "block";
+ }
+
+ elemdisplay[ nodeName ] = display;
+ }
+
+ return elemdisplay[ nodeName ];
}
+
+
+
+
+var rtable = /^t(?:able|d|h)$/i,
+ rroot = /^(?:body|html)$/i;
+
if ( "getBoundingClientRect" in document.documentElement ) {
jQuery.fn.offset = function( options ) {
- var elem = this[0];
+ var elem = this[0], box;
if ( options ) {
return this.each(function( i ) {
@@ -5777,10 +6543,26 @@ if ( "getBoundingClientRect" in document.documentElement ) {
return jQuery.offset.bodyOffset( elem );
}
- var box = elem.getBoundingClientRect(), doc = elem.ownerDocument, body = doc.body, docElem = doc.documentElement,
- clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0,
- top = box.top + (self.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop ) - clientTop,
- left = box.left + (self.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft) - clientLeft;
+ try {
+ box = elem.getBoundingClientRect();
+ } catch(e) {}
+
+ var doc = elem.ownerDocument,
+ docElem = doc.documentElement;
+
+ // Make sure we're not dealing with a disconnected DOM node
+ if ( !box || !jQuery.contains( docElem, elem ) ) {
+ return box || { top: 0, left: 0 };
+ }
+
+ var body = doc.body,
+ win = getWindow(doc),
+ clientTop = docElem.clientTop || body.clientTop || 0,
+ clientLeft = docElem.clientLeft || body.clientLeft || 0,
+ scrollTop = (win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop ),
+ scrollLeft = (win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft),
+ top = box.top + scrollTop - clientTop,
+ left = box.left + scrollLeft - clientLeft;
return { top: top, left: left };
};
@@ -5824,12 +6606,13 @@ if ( "getBoundingClientRect" in document.documentElement ) {
top += elem.offsetTop;
left += elem.offsetLeft;
- if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && /^t(able|d|h)$/i.test(elem.nodeName)) ) {
+ if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {
top += parseFloat( computedStyle.borderTopWidth ) || 0;
left += parseFloat( computedStyle.borderLeftWidth ) || 0;
}
- prevOffsetParent = offsetParent, offsetParent = elem.offsetParent;
+ prevOffsetParent = offsetParent;
+ offsetParent = elem.offsetParent;
}
if ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
@@ -5856,7 +6639,7 @@ if ( "getBoundingClientRect" in document.documentElement ) {
jQuery.offset = {
initialize: function() {
- var body = document.body, container = document.createElement("div"), innerDiv, checkDiv, table, td, bodyMarginTop = parseFloat( jQuery.curCSS(body, "marginTop", true) ) || 0,
+ var body = document.body, container = document.createElement("div"), innerDiv, checkDiv, table, td, bodyMarginTop = parseFloat( jQuery.css(body, "marginTop") ) || 0,
html = "<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
jQuery.extend( container.style, { position: "absolute", top: 0, left: 0, margin: 0, border: 0, width: "1px", height: "1px", visibility: "hidden" } );
@@ -5870,12 +6653,16 @@ jQuery.offset = {
this.doesNotAddBorder = (checkDiv.offsetTop !== 5);
this.doesAddBorderForTableAndCells = (td.offsetTop === 5);
- checkDiv.style.position = "fixed", checkDiv.style.top = "20px";
+ checkDiv.style.position = "fixed";
+ checkDiv.style.top = "20px";
+
// safari subtracts parent border width here which is 5px
this.supportsFixedPosition = (checkDiv.offsetTop === 20 || checkDiv.offsetTop === 15);
checkDiv.style.position = checkDiv.style.top = "";
- innerDiv.style.overflow = "hidden", innerDiv.style.position = "relative";
+ innerDiv.style.overflow = "hidden";
+ innerDiv.style.position = "relative";
+
this.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5);
this.doesNotIncludeMarginInBodyOffset = (body.offsetTop !== bodyMarginTop);
@@ -5891,31 +6678,46 @@ jQuery.offset = {
jQuery.offset.initialize();
if ( jQuery.offset.doesNotIncludeMarginInBodyOffset ) {
- top += parseFloat( jQuery.curCSS(body, "marginTop", true) ) || 0;
- left += parseFloat( jQuery.curCSS(body, "marginLeft", true) ) || 0;
+ top += parseFloat( jQuery.css(body, "marginTop") ) || 0;
+ left += parseFloat( jQuery.css(body, "marginLeft") ) || 0;
}
return { top: top, left: left };
},
setOffset: function( elem, options, i ) {
+ var position = jQuery.css( elem, "position" );
+
// set position first, in-case top/left are set even on static elem
- if ( /static/.test( jQuery.curCSS( elem, "position" ) ) ) {
+ if ( position === "static" ) {
elem.style.position = "relative";
}
- var curElem = jQuery( elem ),
+
+ var curElem = jQuery( elem ),
curOffset = curElem.offset(),
- curTop = parseInt( jQuery.curCSS( elem, "top", true ), 10 ) || 0,
- curLeft = parseInt( jQuery.curCSS( elem, "left", true ), 10 ) || 0;
+ curCSSTop = jQuery.css( elem, "top" ),
+ curCSSLeft = jQuery.css( elem, "left" ),
+ calculatePosition = (position === "absolute" && jQuery.inArray('auto', [curCSSTop, curCSSLeft]) > -1),
+ props = {}, curPosition = {}, curTop, curLeft;
+
+ // need to be able to calculate position if either top or left is auto and position is absolute
+ if ( calculatePosition ) {
+ curPosition = curElem.position();
+ }
+
+ curTop = calculatePosition ? curPosition.top : parseInt( curCSSTop, 10 ) || 0;
+ curLeft = calculatePosition ? curPosition.left : parseInt( curCSSLeft, 10 ) || 0;
if ( jQuery.isFunction( options ) ) {
options = options.call( elem, i, curOffset );
}
- var props = {
- top: (options.top - curOffset.top) + curTop,
- left: (options.left - curOffset.left) + curLeft
- };
+ if (options.top != null) {
+ props.top = (options.top - curOffset.top) + curTop;
+ }
+ if (options.left != null) {
+ props.left = (options.left - curOffset.left) + curLeft;
+ }
if ( "using" in options ) {
options.using.call( elem, props );
@@ -5939,17 +6741,17 @@ jQuery.fn.extend({
// Get correct offsets
offset = this.offset(),
- parentOffset = /^body|html$/i.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
+ parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
// Subtract element margins
// note: when an element has margin: auto the offsetLeft and marginLeft
// are the same in Safari causing offset.left to incorrectly be 0
- offset.top -= parseFloat( jQuery.curCSS(elem, "marginTop", true) ) || 0;
- offset.left -= parseFloat( jQuery.curCSS(elem, "marginLeft", true) ) || 0;
+ offset.top -= parseFloat( jQuery.css(elem, "marginTop") ) || 0;
+ offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0;
// Add offsetParent borders
- parentOffset.top += parseFloat( jQuery.curCSS(offsetParent[0], "borderTopWidth", true) ) || 0;
- parentOffset.left += parseFloat( jQuery.curCSS(offsetParent[0], "borderLeftWidth", true) ) || 0;
+ parentOffset.top += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0;
+ parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0;
// Subtract the two offsets
return {
@@ -5961,7 +6763,7 @@ jQuery.fn.extend({
offsetParent: function() {
return this.map(function() {
var offsetParent = this.offsetParent || document.body;
- while ( offsetParent && (!/^body|html$/i.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
+ while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
offsetParent = offsetParent.offsetParent;
}
return offsetParent;
@@ -6009,12 +6811,16 @@ jQuery.each( ["Left", "Top"], function( i, name ) {
});
function getWindow( elem ) {
- return ("scrollTo" in elem && elem.document) ?
+ return jQuery.isWindow( elem ) ?
elem :
elem.nodeType === 9 ?
elem.defaultView || elem.parentWindow :
false;
}
+
+
+
+
// Create innerHeight, innerWidth, outerHeight and outerWidth methods
jQuery.each([ "Height", "Width" ], function( i, name ) {
@@ -6023,14 +6829,14 @@ jQuery.each([ "Height", "Width" ], function( i, name ) {
// innerHeight and innerWidth
jQuery.fn["inner" + name] = function() {
return this[0] ?
- jQuery.css( this[0], type, false, "padding" ) :
+ parseFloat( jQuery.css( this[0], type, "padding" ) ) :
null;
};
// outerHeight and outerWidth
jQuery.fn["outer" + name] = function( margin ) {
return this[0] ?
- jQuery.css( this[0], type, false, margin ? "margin" : "border" ) :
+ parseFloat( jQuery.css( this[0], type, margin ? "margin" : "border" ) ) :
null;
};
@@ -6048,7 +6854,7 @@ jQuery.each([ "Height", "Width" ], function( i, name ) {
});
}
- return ("scrollTo" in elem && elem.document) ? // does it walk and quack like a window?
+ return jQuery.isWindow( elem ) ?
// Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
elem.document.compatMode === "CSS1Compat" && elem.document.documentElement[ "client" + name ] ||
elem.document.body[ "client" + name ] :
@@ -6065,14 +6871,13 @@ jQuery.each([ "Height", "Width" ], function( i, name ) {
// Get or set width or height on the element
size === undefined ?
// Get width or height on the element
- jQuery.css( elem, type ) :
+ parseFloat( jQuery.css( elem, type ) ) :
// Set the width or height on the element (default to pixels if value is unitless)
this.css( type, typeof size === "string" ? size : size + "px" );
};
});
-// Expose jQuery to the global object
-window.jQuery = window.$ = jQuery;
+
})(window);
diff --git a/railties/lib/rails/rack/log_tailer.rb b/railties/lib/rails/rack/log_tailer.rb
index 011ac6cecc..830d840894 100644
--- a/railties/lib/rails/rack/log_tailer.rb
+++ b/railties/lib/rails/rack/log_tailer.rb
@@ -19,7 +19,7 @@ module Rails
def tail!
@file.seek @cursor
- if !@file.eof?
+ unless @file.eof?
contents = @file.read
@cursor = @file.tell
$stdout.print contents