aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoshua Peek <josh@joshpeek.com>2010-01-30 14:39:41 -0600
committerJoshua Peek <josh@joshpeek.com>2010-01-30 14:39:59 -0600
commit4f7a85d2c66f100f83e2fe264e1f03bf079f13dc (patch)
treea9304cf3c3006b472da7e75cf339d6641160e728
parentac20f2cea15844b5cc06bdfefbb410fc55ba5caf (diff)
downloadrails-4f7a85d2c66f100f83e2fe264e1f03bf079f13dc.tar.gz
rails-4f7a85d2c66f100f83e2fe264e1f03bf079f13dc.tar.bz2
rails-4f7a85d2c66f100f83e2fe264e1f03bf079f13dc.zip
Revert "Merge branch 'rails/master' into ujs"
This reverts commit 3aa1ea1ae4baa4a03d03644e798eeb98a4745785, reversing changes made to 2c12a71378d2146c822acb389b00b866f6420ff5. Conflicts: actionpack/lib/action_view/helpers/javascript_helper.rb actionpack/lib/action_view/helpers/url_helper.rb actionpack/test/template/url_helper_test.rb
-rw-r--r--actionpack/lib/action_view/helpers.rb8
-rw-r--r--actionpack/lib/action_view/helpers/ajax_helper.rb735
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb36
-rw-r--r--actionpack/lib/action_view/helpers/form_tag_helper.rb20
-rw-r--r--actionpack/lib/action_view/helpers/javascript_helper.rb63
-rw-r--r--actionpack/lib/action_view/helpers/prototype_helper.rb449
-rw-r--r--actionpack/lib/action_view/helpers/url_helper.rb45
-rw-r--r--actionpack/test/template/ajax_helper_test.rb452
-rw-r--r--actionpack/test/template/ajax_test.rb114
-rw-r--r--actionpack/test/template/form_helper_test.rb8
-rw-r--r--actionpack/test/template/form_tag_helper_test.rb12
-rw-r--r--actionpack/test/template/prototype_helper_test.rb193
-rw-r--r--actionpack/test/template/url_helper_test.rb18
-rw-r--r--railties/lib/generators/rails/app/templates/public/javascripts/jquery-1.4.1.min.js152
-rw-r--r--railties/lib/generators/rails/app/templates/public/javascripts/jquery.rails.js239
-rw-r--r--railties/lib/generators/rails/app/templates/public/javascripts/prototype.rails.js324
16 files changed, 912 insertions, 1956 deletions
diff --git a/actionpack/lib/action_view/helpers.rb b/actionpack/lib/action_view/helpers.rb
index 080eb87445..3d088678fc 100644
--- a/actionpack/lib/action_view/helpers.rb
+++ b/actionpack/lib/action_view/helpers.rb
@@ -3,7 +3,7 @@ require 'active_support/benchmarkable'
module ActionView #:nodoc:
module Helpers #:nodoc:
autoload :ActiveModelHelper, 'action_view/helpers/active_model_helper'
- autoload :AjaxHelperCompat, 'action_view/helpers/ajax_helper'
+ autoload :AjaxHelper, 'action_view/helpers/ajax_helper'
autoload :AssetTagHelper, 'action_view/helpers/asset_tag_helper'
autoload :AtomFeedHelper, 'action_view/helpers/atom_feed_helper'
autoload :CacheHelper, 'action_view/helpers/cache_helper'
@@ -15,11 +15,12 @@ module ActionView #:nodoc:
autoload :FormTagHelper, 'action_view/helpers/form_tag_helper'
autoload :JavaScriptHelper, 'action_view/helpers/javascript_helper'
autoload :NumberHelper, 'action_view/helpers/number_helper'
- autoload :AjaxHelper, 'action_view/helpers/ajax_helper'
+ autoload :PrototypeHelper, 'action_view/helpers/prototype_helper'
autoload :RawOutputHelper, 'action_view/helpers/raw_output_helper'
autoload :RecordIdentificationHelper, 'action_view/helpers/record_identification_helper'
autoload :RecordTagHelper, 'action_view/helpers/record_tag_helper'
autoload :SanitizeHelper, 'action_view/helpers/sanitize_helper'
+ autoload :ScriptaculousHelper, 'action_view/helpers/scriptaculous_helper'
autoload :TagHelper, 'action_view/helpers/tag_helper'
autoload :TextHelper, 'action_view/helpers/text_helper'
autoload :TranslationHelper, 'action_view/helpers/translation_helper'
@@ -47,11 +48,12 @@ module ActionView #:nodoc:
include FormTagHelper
include JavaScriptHelper
include NumberHelper
- include AjaxHelperCompat
+ include PrototypeHelper
include RawOutputHelper
include RecordIdentificationHelper
include RecordTagHelper
include SanitizeHelper
+ include ScriptaculousHelper
include TagHelper
include TextHelper
include TranslationHelper
diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb
index 169a803848..9cc2acc239 100644
--- a/actionpack/lib/action_view/helpers/ajax_helper.rb
+++ b/actionpack/lib/action_view/helpers/ajax_helper.rb
@@ -1,713 +1,68 @@
module ActionView
module Helpers
module AjaxHelper
- # Included for backwards compatibility / RJS functionality
- # Rails classes should not be aware of individual JS frameworks
- include PrototypeHelper
-
- # Returns a form that will allow the unobtrusive JavaScript drivers to submit the
- # form dynamically. The default driver behaviour is an XMLHttpRequest in the background
- # instead of the regular POST arrangement. Even though it's using JavaScript to serialize
- # the form elements, the form submission will work just like a regular submission as
- # viewed by the receiving side (all elements available in <tt>params</tt>). The options
- # for specifying the target with <tt>:url</tt> anddefining callbacks is the same as +link_to_remote+.
- #
- # === Resource
- #
- # Example:
- #
- # # Generates:
- # # <form action='/authors'
- # # data-remote='true'
- # # class='new_author'
- # # id='create-author'
- # # method='post'> ... </form>
- # #
- # <% remote_form_for(@record, {:html => { :id => 'create-author' }}) do |f| %>
- # ...
- # <% end %>
- #
- # This will expand to be the same as:
- #
- # <% remote_form_for :post, @post, :url => post_path(@post),
- # :html => { :method => :put,
- # :class => "edit_post",
- # :id => "edit_post_45" } do |f| %>
- # ...
- # <% end %>
- #
- # === Nested Resource
- #
- # Example:
- # # Generates:
- # # <form action='/authors/1/articles'
- # # data-remote="true"
- # # class='new_article'
- # # method='post'
- # # id='new_article'></form>
- # #
- # <% remote_form_for([@author, @article]) do |f| %>
- # ...
- # <% end %>
- #
- # This will expand to be the same as:
- #
- # <% remote_form_for :article, @article, :url => author_article_path(@author, @article),
- # :html => { :method => :put,
- # :class => "new_article",
- # :id => "new_comment" } do |f| %>
- # ...
- # <% end %>
- #
- # If you don't need to attach a form to a resource, then check out form_remote_tag.
- #
- # See FormHelper#form_for for additional semantics.
- def remote_form_for(record_or_name_or_array, *args, &proc)
- options = args.extract_options!
-
- if confirm = options.delete(:confirm)
- add_confirm_to_attributes!(options, confirm)
- end
-
- object_name = extract_object_name_for_form!(args, options, record_or_name_or_array)
-
- concat(form_remote_tag(options))
- fields_for(object_name, *(args << options), &proc)
- concat('</form>'.html_safe!)
- end
- alias_method :form_remote_for, :remote_form_for
-
- # Returns a form tag that will allow the unobtrusive JavaScript drivers to submit the
- # form dynamically. The default JavaScript driver behaviour is an XMLHttpRequest
- # in the background instead of the regular POST arrangement. Even though it's using
- # JavaScript to serialize the form elements, the form submission will work just like
- # a regular submission as viewed by the receiving side (all elements available in
- # <tt>params</tt>). The options for specifying the target with <tt>:url</tt> and
- # defining callbacks is the same as +link_to_remote+.
- #
- # A "fall-through" target for browsers that doesn't do JavaScript can be
- # specified with the <tt>:action</tt>/<tt>:method</tt> options on <tt>:html</tt>.
- #
- # Example:
- #
- # # Generates:
- # # <form action="http://www.example.com/fast"
- # # method="post"
- # # data-remote="true"
- # # data-update-success="glass_of_beer"></form>
- # #
- # form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) {}
- #
- # The Hash passed to the <tt>:html</tt> key is equivalent to the options (2nd)
- # argument in the FormTagHelper.form_tag method.
- #
- # By default the fall-through action is the same as the one specified in
- # the <tt>:url</tt> (and the default method is <tt>:post</tt>).
- #
- # form_remote_tag also takes a block, like form_tag:
- # # Generates:
- # # <form action='/posts'
- # # method='post'
- # # data-remote='true'>
- # # <input name="commit" type="submit" value="Save" />
- # # </form>
- # #
- # <% form_remote_tag :url => '/posts' do -%>
- # <%= submit_tag 'Save' %>
- # <% end -%>
- #
- # # Generates:
- # # <form action="http://www.example.com/fast"
- # # method="post"
- # # data-remote="true"
- # # data-update-success="glass_of_beer">Hello world!</form>
- # #
- # <% form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) do -%>
- # "Hello world!"
- # <% end -%>
- #
- def form_remote_tag(options = {}, &block)
- html_options = options.delete(:callbacks)
-
- attributes = {}
- attributes.merge!(extract_remote_attributes!(options))
- attributes.merge!(html_options) if html_options
- attributes.merge!(options)
- attributes.delete(:builder)
-
- form_tag(attributes.delete(:action) || attributes.delete("data-url"), attributes, &block)
- end
-
- # Returns a link that will allow unobtrusive JavaScript to dynamical adjust its
- # behaviour. The default behaviour is an XMLHttpRequest in the background instead
- # of the regular GET arrangement. The result of that request can then be inserted
- # into a DOM object whose id can be specified with <tt>options[:update]</tt>. Usually,
- # the result would be a partial prepared by the controller with render :partial.
- #
- # Examples:
- #
- # # Generates:
- # # <a href="#"
- # # data-remote="true"
- # # data-url="http://www.example.com/whatnot"
- # # data-method="delete"
- # # rel="nofollow">Remove Author</a>
- # #
- # link_to_remote("Remove Author", { :url => { :action => "whatnot" },
- # :method => "delete"})
- #
- #
- # You can override the generated HTML options by specifying a hash in
- # <tt>options[:html]</tt>.
- #
- # # Generates:
- # # <a class="fine"
- # # href="#"
- # # data-remote="true"
- # # data-url="http://www.example.com/whatnot"
- # # data-method="delete"
- # # rel="nofollow">Remove Author</a>
- # #
- # link_to_remote("Remove Author", { :url => { :action => "whatnot" },
- # :method => "delete",
- # :html => { :class => "fine" }})
- #
- #
- # You can also specify a hash for <tt>options[:update]</tt> to allow for
- # easy redirection of output to an other DOM element if a server-side
- # error occurs:
- #
- # Example:
- # # Generates:
- # #
- # # <a href="#"
- # # data-url="http://www.example.com/destroy"
- # # data-update-success="posts"
- # # data-update-failure="error"
- # # data-remote="true">Delete this Post</a>'
- # #
- # link_to_remote "Delete this post",
- # :url => { :action => "destroy"},
- # :update => { :success => "posts", :failure => "error" }
- #
- # Optionally, you can use the <tt>options[:position]</tt> parameter to
- # influence how the target DOM element is updated. It must be one of
- # <tt>:before</tt>, <tt>:top</tt>, <tt>:bottom</tt>, or <tt>:after</tt>.
- #
- # Example:
- # # Generates:
- # # <a href="#"
- # # data-remote="true"
- # # data-url="http://www.example.com/whatnot"
- # # data-update-position="bottom">Remove Author</a>
- # #
- # link_to_remote("Remove Author", :url => { :action => "whatnot" }, :position => :bottom)
- #
- #
- # The method used is by default POST. You can also specify GET or you
- # can simulate PUT or DELETE over POST. All specified with <tt>options[:method]</tt>
- #
- # Example:
- # # Generates:
- # # <a href='#'
- # # data-url='/person/4'
- # # rel='nofollow'
- # # data-remote='true'
- # # data-method='delete'>Destroy</a>
- # #
- # link_to_remote "Destroy", :url => person_url(:id => person), :method => :delete
- #
- # By default, these remote requests are processed asynchronous during
- # which various JavaScript callbacks can be triggered (for progress
- # indicators and the likes). All callbacks get access to the
- # <tt>request</tt> object, which holds the underlying XMLHttpRequest.
- #
- # To access the server response, use <tt>request.responseText</tt>, to
- # find out the HTTP status, use <tt>request.status</tt>.
- #
- # Example:
- # # Generates:
- # #
- # # <a href='#'
- # # data-url='http://www.example.com/undo?n=5'
- # # data-oncomplete='undoRequestCompleted(request)'
- # # data-remote='true'>undo</a>
- # #
- # link_to_remote "undo",
- # :url => { :controller => "words", :action => "undo", :n => word_counter },
- # :complete => "undoRequestCompleted(request)"
- #
- # The callbacks that may be specified are (in order):
- #
- # <tt>:loading</tt>:: Called when the remote document is being
- # loaded with data by the browser.
- # <tt>:loaded</tt>:: Called when the browser has finished loading
- # the remote document.
- # <tt>:interactive</tt>:: Called when the user can interact with the
- # remote document, even though it has not
- # finished loading.
- # <tt>:success</tt>:: Called when the XMLHttpRequest is completed,
- # and the HTTP status code is in the 2XX range.
- # <tt>:failure</tt>:: Called when the XMLHttpRequest is completed,
- # and the HTTP status code is not in the 2XX
- # range.
- # <tt>:complete</tt>:: Called when the XMLHttpRequest is complete
- # (fires after success/failure if they are
- # present).
- #
- # You can further refine <tt>:success</tt> and <tt>:failure</tt> by
- # adding additional callbacks for specific status codes.
- #
- # Example:
- #
- # # Generates:
- # # <a href='/testing/action'
- # # date-remote='true'
- # # data-failure="function(request){alert('HTTP Error '+ request.status +'+!');return false}"
- # # data-404="function(request){alert('Not found...? Wrong URL...?')}"> Hello</a>
- # #
- # link_to_remote word,
- # :url => { :action => "action" },
- # 404 => "alert('Not found...? Wrong URL...?')",
- # :failure => "alert('HTTP Error ' + request.status + '!')"
- #
- # A status code callback overrides the success/failure handlers if
- # present.
- #
- # If you for some reason or another need synchronous processing (that'll
- # block the browser while the request is happening), you can specify
- # <tt>options[:type] = :synchronous</tt>.
- #
- # You can customize further browser side call logic by passing in
- # JavaScript code snippets via some optional parameters. In their order
- # of use these are:
- #
- # <tt>:confirm</tt>:: Adds confirmation dialog.
- # <tt>:condition</tt>:: Perform remote request conditionally
- # by this expression. Use this to
- # describe browser-side conditions when
- # request should not be initiated.
- # <tt>:before</tt>:: Called before request is initiated.
- # <tt>:after</tt>:: Called immediately after request was
- # initiated and before <tt>:loading</tt>.
- # <tt>:submit</tt>:: Specifies the DOM element ID that's used
- # as the parent of the form elements. By
- # default this is the current form, but
- # it could just as well be the ID of a
- # table row or any other DOM element.
- # <tt>:with</tt>:: A JavaScript expression specifying
- # the parameters for the XMLHttpRequest.
- # Any expressions should return a valid
- # URL query string.
- #
- # Example:
- #
- # :with => "'name=' + $('name').value"
- #
- # You can generate a link that uses the UJS drivers in the general case, while
- # degrading gracefully to plain link behavior in the absence of
- # JavaScript by setting <tt>html_options[:href]</tt> to an alternate URL.
- # Note the extra curly braces around the <tt>options</tt> hash separate
- # it as the second parameter from <tt>html_options</tt>, the third.
- #
- # Example:
- #
- # # Generates:
- # # <a href='/posts/1'
- # # rel='nofollow'
- # # data-remote='true'
- # # data-method='delete'> Delete this post</a>
- # #
- # link_to_remote "Delete this post",
- # { :update => "posts", :url => { :action => "destroy", :id => post.id } }
- #
- def link_to_remote(name, options, html_options = {})
- attributes = {}
-
- attributes.merge!(:rel => "nofollow") if options[:method] && options[:method].to_s.downcase == "delete"
- attributes.merge!(extract_remote_attributes!(options))
+ include UrlHelper
+
+ def link_to_remote(name, url, options = {})
+ html = options.delete(:html) || {}
- if confirm = options.delete(:confirm)
- add_confirm_to_attributes!(attributes, confirm)
- end
-
- attributes.merge!(html_options)
- href = html_options[:href].nil? ? "#" : html_options[:href]
- attributes.merge!(:href => href)
-
- content_tag(:a, name, attributes)
- end
-
- # Returns an input of type button, which allows the unobtrusive JavaScript driver
- # to dynamically adjust its behaviour. The default driver behaviour is to call a
- # remote action via XMLHttpRequest in the background.
- # The options for specifying the target with :url and defining callbacks is the same
- # as link_to_remote.
- #
- # Example:
- #
- # # Generates:
- # # <input class="fine"
- # # type="button"
- # # value="Remote outpost"
- # # data-remote="true"
- # # data-url="http://www.example.com/whatnot" />
- # #
- # button_to_remote("Remote outpost", { :url => { :action => "whatnot" }}, { :class => "fine" })
- #
- def button_to_remote(name, options = {}, html_options = {})
- attributes = html_options.merge!(:type => "button", :value => name)
-
- if confirm = options.delete(:confirm)
- add_confirm_to_attributes!(attributes, confirm)
- end
-
- if disable_with = options.delete(:disable_with)
- add_disable_with_to_attributes!(attributes, disable_with)
- end
-
- attributes.merge!(extract_remote_attributes!(options))
-
- tag(:input, attributes)
- end
-
- # Returns an input tag of type button, with the element name of +name+ and a value (i.e., display text)
- # of +value+ which will allow the unobtrusive JavaScript driver to dynamically adjust its behaviour
- # The default behaviour is to call a remote action via XMLHttpRequest in the background.
- #
- # request that reloads the page.
- #
- # # Create a button that submits to the create action
- # #
- # # Generates:
- # # <input name='create_btn'
- # # type='button'
- # # value='Create'
- # # data-remote='true'
- # # data-url='/create' />
- # #
- # <%= submit_to_remote 'create_btn', 'Create', :url => { :action => 'create' } %>
- #
- # # Submit to the remote action update and update the DIV succeed or fail based
- # # on the success or failure of the request
- # #
- # # Generates:
- # # <input name='update_btn'
- # # type='button'
- # # value='Update'
- # # date-remote-submit='true'
- # # data-url='/testing/update'
- # # data-success='succeed'
- # # data-failure='fail' />
- # #
- # <%= submit_to_remote 'update_btn', 'Update', :url => { :action => 'update' },
- # :update => { :success => "succeed", :failure => "fail" }
- #
- # <tt>options</tt> argument is the same as in form_remote_tag.
- def submit_to_remote(name, value, options = {})
- html_options = options.delete(:html) || {}
- html_options.merge!(:name => name, :value => value, :type => "button")
-
- attributes = extract_remote_attributes!(options)
- attributes.merge!(html_options)
- attributes["data-remote-submit"] = true
- attributes.delete("data-remote")
-
- tag(:input, attributes)
- end
-
- # Periodically provides the UJS driver with the information to call the specified
- # url (<tt>options[:url]</tt>) every <tt>options[:frequency]</tt> seconds (default is 10). Usually used to
- # update a specified div (<tt>options[:update]</tt>) with the results
- # of the remote call. The options for specifying the target with <tt>:url</tt>
- # and defining callbacks is the same as link_to_remote.
- # Examples:
- # # Call get_averages and put its results in 'avg' every 10 seconds
- # # Generates:
- # # <script data-periodical='true'
- # # data-url='/get_averages'
- # # type='application/json'
- # # data-update-success='avg'
- # # data-frequency='10'></script>
- # #
- # periodically_call_remote(:url => { :action => 'get_averages' }, :update => 'avg')
- #
- # # Call invoice every 10 seconds with the id of the customer
- # # If it succeeds, update the invoice DIV; if it fails, update the error DIV
- # # Generates:
- # # <script data-periodical='true'
- # # data-url='/invoice/1'
- # # type='application/json'
- # # data-update-success='invoice'
- # # data-update-failure='error'
- # # data-frequency='10'></script>"
- # #
- # periodically_call_remote(:url => { :action => 'invoice', :id => 1 },
- # :update => { :success => "invoice", :failure => "error" }
- #
- # # Call update every 20 seconds and update the new_block DIV
- # # Generates:
- # # <script data-periodical='true'
- # # data-url='update'
- # # type='application/json'
- # # data-update-success='news_block'
- # # data-frequency='20'></script>
- # #
- # periodically_call_remote(:url => 'update', :frequency => '20', :update => 'news_block')
- #
- def periodically_call_remote(options = {})
- attributes = extract_observer_attributes!(options)
- attributes["data-periodical"] = true
- attributes["data-frequency"] ||= 10
-
- # periodically_call_remote does not need data-observe=true
- attributes.delete('data-observe')
-
- script_decorator(attributes).html_safe!
- end
-
- # Observes the field with the DOM ID specified by +field_id+ and calls a
- # callback when its contents have changed. The default callback is an
- # Ajax call. By default the value of the observed field is sent as a
- # parameter with the Ajax call.
- #
- # Example:
- # # Generates:
- # # "<script type='text/javascript'
- # # data-observe='true'
- # # data-observed='suggest'
- # # data-frequency='0.25'
- # # type='application/json'
- # # data-url='/find_suggestion'
- # # data-update-success='suggest'
- # # data-with='q'></script>"
- # #
- # <%= observe_field :suggest, :url => { :action => :find_suggestion },
- # :frequency => 0.25,
- # :update => :suggest,
- # :with => 'q'
- # %>
- #
- # Required +options+ are either of:
- # <tt>:url</tt>:: +url_for+-style options for the action to call
- # when the field has changed.
- # <tt>:function</tt>:: Instead of making a remote call to a URL, you
- # can specify javascript code to be called instead.
- # Note that the value of this option is used as the
- # *body* of the javascript function, a function definition
- # with parameters named element and value will be generated for you
- # for example:
- # observe_field("glass", :frequency => 1, :function => "alert('Element changed')")
- # will generate:
- # new Form.Element.Observer('glass', 1, function(element, value) {alert('Element changed')})
- # The element parameter is the DOM element being observed, and the value is its value at the
- # time the observer is triggered.
- #
- # Additional options are:
- # <tt>:frequency</tt>:: The frequency (in seconds) at which changes to
- # this field will be detected. Not setting this
- # option at all or to a value equal to or less than
- # zero will use event based observation instead of
- # time based observation.
- # <tt>:update</tt>:: Specifies the DOM ID of the element whose
- # innerHTML should be updated with the
- # XMLHttpRequest response text.
- # <tt>:with</tt>:: A JavaScript expression specifying the parameters
- # for the XMLHttpRequest. The default is to send the
- # key and value of the observed field. Any custom
- # expressions should return a valid URL query string.
- # The value of the field is stored in the JavaScript
- # variable +value+.
- #
- # Examples
- #
- # :with => "'my_custom_key=' + value"
- # :with => "'person[name]=' + prompt('New name')"
- # :with => "Form.Element.serialize('other-field')"
- #
- # Finally
- # :with => 'name'
- # is shorthand for
- # :with => "'name=' + value"
- # This essentially just changes the key of the parameter.
- #
- # Additionally, you may specify any of the options documented in the
- # <em>Common options</em> section at the top of this document.
- #
- # Example:
- #
- # # Sends params: {:title => 'Title of the book'} when the book_title input
- # # field is changed.
- # observe_field 'book_title',
- # :url => 'http://example.com/books/edit/1',
- # :with => 'title'
- #
- #
- def observe_field(name, options = {})
- html_options = options.delete(:callbacks)
-
- options[:observed] = name
- attributes = extract_observer_attributes!(options)
- attributes.merge!(html_options) if html_options
-
- script_decorator(attributes).html_safe!
- end
-
- # Observes the form with the DOM ID specified by +form_id+ and calls a
- # callback when its contents have changed. The default callback is an
- # Ajax call. By default all fields of the observed field are sent as
- # parameters with the Ajax call.
- #
- # The +options+ for +observe_form+ are the same as the options for
- # +observe_field+. The JavaScript variable +value+ available to the
- # <tt>:with</tt> option is set to the serialized form by default.
- def observe_form(name, options = {})
- html_options = options.delete(:callbacks)
-
- options[:observed] = name
- attributes = extract_observer_attributes!(options)
- attributes.merge!(html_options) if html_options
-
- script_decorator(attributes).html_safe!
- end
-
- def script_decorator(options)
- attributes = %w(type="application/json")
- attributes += options.map{|k, v| k + '="' + v.to_s + '"'}
- "<script " + attributes.join(" ") + "></script>"
- end
-
- private
-
- def extract_remote_attributes!(options)
- attributes = options.delete(:html) || {}
-
- attributes.merge!(extract_update_attributes!(options))
- attributes.merge!(extract_request_attributes!(options))
- attributes["data-remote"] = true
-
- if submit = options.delete(:submit)
- attributes["data-submit"] = submit
- end
-
- attributes
- end
-
- def extract_request_attributes!(options)
- attributes = {}
- if method = options.delete(:method)
- attributes["data-method"] = method.to_s
- end
-
- if type = options.delete(:type)
- attributes["data-remote-type"] = type.to_s
- end
-
- url_options = options.delete(:url)
- url_options = url_options.merge(:escape => false) if url_options.is_a?(Hash)
- attributes["data-url"] = escape_javascript(url_for(url_options)) if url_options
-
- purge_unused_attributes!(attributes)
+ update = options.delete(:update)
+ if update.is_a?(Hash)
+ html["data-update-success"] = update[:success]
+ html["data-update-failure"] = update[:failure]
+ else
+ html["data-update-success"] = update
end
- def extract_update_attributes!(options)
- attributes = {}
- update = options.delete(:update)
- if update.is_a?(Hash)
- attributes["data-update-success"] = update[:success]
- attributes["data-update-failure"] = update[:failure]
- else
- attributes["data-update-success"] = update
- end
-
- if position = options.delete(:position)
- attributes["data-update-position"] = position.to_s
- end
-
- purge_unused_attributes!(attributes)
- end
-
- def extract_observer_attributes!(options)
- callback = options.delete(:function)
- frequency = options.delete(:frequency) || 10
-
-
- attributes = extract_remote_attributes!(options)
- attributes["data-observe"] = true
- attributes["data-observed"] = options.delete(:observed)
- attributes["data-onobserve"] = callback if callback
- attributes["data-frequency"] = frequency if frequency && frequency.to_f != 0
- attributes.delete("data-remote")
-
- purge_unused_attributes!(attributes)
- end
-
- def purge_unused_attributes!(attributes)
- attributes.delete_if {|key, value| value.nil? }
- attributes
- end
- end
-
- # TODO: All evaled goes here per wycat
- module AjaxHelperCompat
- include AjaxHelper
-
- def link_to_remote(name, options, html_options = {})
- set_callbacks(options, html_options)
- set_with_and_condition_attributes(options, html_options)
- super
+ html["data-update-position"] = options.delete(:position)
+ html["data-method"] = options.delete(:method)
+ html["data-remote"] = "true"
+
+ html.merge!(options)
+
+ url = url_for(url) if url.is_a?(Hash)
+ link_to(name, url, html)
end
def button_to_remote(name, options = {}, html_options = {})
- set_callbacks(options, html_options)
- set_with_and_condition_attributes(options, html_options)
- super
- end
-
- def form_remote_tag(options, &block)
- html = {}
- set_callbacks(options, html)
- set_with_and_condition_attributes(options, html)
- options.merge!(:callbacks => html)
- super
- end
-
- def observe_field(name, options = {})
- html = {}
- set_with_and_condition_attributes(options, html)
- options.merge!(:callbacks => html)
- super
+ url = options.delete(:url)
+ url = url_for(url) if url.is_a?(Hash)
+
+ html_options.merge!(:type => "button", :value => name,
+ :"data-url" => url)
+
+ tag(:input, html_options)
end
- def observe_form(name, options = {})
- html = {}
- set_with_and_condition_attributes(options, html)
- options.merge!(:callbacks => html)
- super
- end
-
- private
+ module Rails2Compatibility
def set_callbacks(options, html)
- [:before, :after, :uninitialized, :complete, :failure, :success, :interactive, :loaded, :loading].each do |type|
- html["data-on#{type}"] = options.delete(type.to_sym)
+ [:complete, :failure, :success, :interactive, :loaded, :loading].each do |type|
+ html["data-#{type}-code"] = options.delete(type.to_sym)
end
options.each do |option, value|
if option.is_a?(Integer)
- html["data-on#{option}"] = options.delete(option)
+ html["data-#{option}-code"] = options.delete(option)
end
end
end
-
- def set_with_and_condition_attributes(options, html)
- if with = options.delete(:with)
- html["data-with"] = with
- end
-
- if condition = options.delete(:condition)
- html["data-condition"] = condition
+
+ def link_to_remote(name, url, options = nil)
+ if !options && url.is_a?(Hash) && url.key?(:url)
+ url, options = url.delete(:url), url
end
+
+ set_callbacks(options, options[:html] ||= {})
+
+ super
+ end
+
+ def button_to_remote(name, options = {}, html_options = {})
+ set_callbacks(options, html_options)
+ super
end
+ end
+
end
end
-end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index 1615f135b4..20e9916d62 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -262,8 +262,23 @@ module ActionView
# FormTagHelper#form_tag.
def form_for(record_or_name_or_array, *args, &proc)
raise ArgumentError, "Missing block" unless block_given?
+
options = args.extract_options!
- object_name = extract_object_name_for_form!(args, options, record_or_name_or_array)
+
+ case record_or_name_or_array
+ when String, Symbol
+ object_name = record_or_name_or_array
+ when Array
+ object = record_or_name_or_array.last
+ object_name = ActionController::RecordIdentifier.singular_class_name(object)
+ apply_form_for_options!(record_or_name_or_array, options)
+ args.unshift object
+ else
+ object = record_or_name_or_array
+ object_name = ActionController::RecordIdentifier.singular_class_name(object)
+ apply_form_for_options!([object], options)
+ args.unshift object
+ end
concat(form_tag(options.delete(:url) || {}, options.delete(:html) || {}))
fields_for(object_name, *(args << options), &proc)
@@ -727,25 +742,6 @@ module ActionView
def radio_button(object_name, method, tag_value, options = {})
InstanceTag.new(object_name, method, self, options.delete(:object)).to_radio_button_tag(tag_value, options)
end
-
- private
- def extract_object_name_for_form!(args, options, record_or_name_or_array)
- case record_or_name_or_array
- when String, Symbol
- object_name = record_or_name_or_array
- when Array
- object = record_or_name_or_array.last
- object_name = ActionController::RecordIdentifier.singular_class_name(object)
- apply_form_for_options!(record_or_name_or_array, options)
- args.unshift object
- else
- object = record_or_name_or_array
- object_name = ActionController::RecordIdentifier.singular_class_name(object)
- apply_form_for_options!([object], options)
- args.unshift object
- end
- object_name
- end
end
module InstanceTagMethods #:nodoc:
diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb
index ebce5c1513..048bedc7ba 100644
--- a/actionpack/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -352,24 +352,33 @@ module ActionView
# # => <input disabled="disabled" name="commit" type="submit" value="Save edits" />
#
# submit_tag "Complete sale", :disable_with => "Please wait..."
- # # => <input name="commit" data-disable-with="Please wait..."
+ # # => <input name="commit" onclick="this.disabled=true;this.value='Please wait...';this.form.submit();"
# # type="submit" value="Complete sale" />
#
# submit_tag nil, :class => "form_submit"
# # => <input class="form_submit" name="commit" type="submit" />
#
# submit_tag "Edit", :disable_with => "Editing...", :class => "edit-button"
- # # => <input class="edit-button" data-disable-with="Editing..."
+ # # => <input class="edit-button" onclick="this.disabled=true;this.value='Editing...';this.form.submit();"
# # name="commit" type="submit" value="Edit" />
def submit_tag(value = "Save changes", options = {})
options.stringify_keys!
if disable_with = options.delete("disable_with")
- add_disable_with_to_attributes!(options, disable_with)
+ disable_with = "this.value='#{disable_with}'"
+ disable_with << ";#{options.delete('onclick')}" if options['onclick']
+
+ options["onclick"] = "if (window.hiddenCommit) { window.hiddenCommit.setAttribute('value', this.value); }"
+ options["onclick"] << "else { hiddenCommit = document.createElement('input');hiddenCommit.type = 'hidden';"
+ options["onclick"] << "hiddenCommit.value = this.value;hiddenCommit.name = this.name;this.form.appendChild(hiddenCommit); }"
+ options["onclick"] << "this.setAttribute('originalValue', this.value);this.disabled = true;#{disable_with};"
+ options["onclick"] << "result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit());"
+ options["onclick"] << "if (result == false) { this.value = this.getAttribute('originalValue');this.disabled = false; }return result;"
end
if confirm = options.delete("confirm")
- add_confirm_to_attributes!(options, confirm)
+ options["onclick"] ||= 'return true;'
+ options["onclick"] = "if (!#{confirm_javascript_function(confirm)}) return false; #{options['onclick']}"
end
tag :input, { "type" => "submit", "name" => "commit", "value" => value }.update(options.stringify_keys)
@@ -402,7 +411,8 @@ module ActionView
options.stringify_keys!
if confirm = options.delete("confirm")
- add_confirm_to_attributes!(options, confirm)
+ options["onclick"] ||= ''
+ options["onclick"] += "return #{confirm_javascript_function(confirm)};"
end
tag :input, { "type" => "image", "src" => path_to_image(source) }.update(options.stringify_keys)
diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb
index 02d0a88189..06a9d3405a 100644
--- a/actionpack/lib/action_view/helpers/javascript_helper.rb
+++ b/actionpack/lib/action_view/helpers/javascript_helper.rb
@@ -39,7 +39,7 @@ module ActionView
JAVASCRIPT_PATH = File.join(File.dirname(__FILE__), 'javascripts')
end
- include AjaxHelperCompat
+ include PrototypeHelper
# Returns a link of the given +name+ that will trigger a JavaScript +function+ using the
# onclick handler and return false after the fact.
@@ -187,57 +187,22 @@ module ActionView
"\n//#{cdata_section("\n#{content}\n//")}\n"
end
- protected
- def convert_options_to_javascript!(html_options, url = '')
- confirm = html_options.delete("confirm")
-
- if html_options.key?("popup")
- ActiveSupport::Deprecation.warn(":popup has been deprecated", caller)
- end
-
- method, href = html_options.delete("method"), html_options['href']
-
- if confirm && method
- add_confirm_to_attributes!(html_options, confirm)
- add_method_to_attributes!(html_options, method, url)
- elsif confirm
- add_confirm_to_attributes!(html_options, confirm)
- elsif method
- add_method_to_attributes!(html_options, method, url)
- end
- end
-
- def add_confirm_to_attributes!(html_options, confirm)
- html_options["data-confirm"] = confirm if confirm
- end
-
- def add_method_to_attributes!(html_options, method, url = nil)
- html_options["rel"] = "nofollow" if method.to_s.downcase == "delete"
- html_options["data-method"] = method
- if url.size > 0
- html_options["data-url"] = url
- end
- end
-
- def add_disable_with_to_attributes!(html_options, disable_with)
- html_options["data-disable-with"] = disable_with if disable_with
- end
-
- def options_for_javascript(options)
- if options.empty?
- '{}'
- else
- "{#{options.keys.map { |k| "#{k}:#{options[k]}" }.sort.join(', ')}}"
+ protected
+ def options_for_javascript(options)
+ if options.empty?
+ '{}'
+ else
+ "{#{options.keys.map { |k| "#{k}:#{options[k]}" }.sort.join(', ')}}"
+ end
end
- end
- def array_or_string_for_javascript(option)
- if option.kind_of?(Array)
- "['#{option.join('\',\'')}']"
- elsif !option.nil?
- "'#{option}'"
+ def array_or_string_for_javascript(option)
+ if option.kind_of?(Array)
+ "['#{option.join('\',\'')}']"
+ elsif !option.nil?
+ "'#{option}'"
+ end
end
- end
end
end
end
diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb
index d861810f19..bef93dd0f8 100644
--- a/actionpack/lib/action_view/helpers/prototype_helper.rb
+++ b/actionpack/lib/action_view/helpers/prototype_helper.rb
@@ -1,7 +1,6 @@
require 'set'
require 'active_support/json'
require 'active_support/core_ext/object/returning'
-require 'action_view/helpers/scriptaculous_helper'
module ActionView
module Helpers
@@ -28,6 +27,40 @@ module ActionView
# ActionView::Helpers::JavaScriptHelper for more information on including
# this and other JavaScript files in your Rails templates.)
#
+ # Now you're ready to call a remote action either through a link...
+ #
+ # link_to_remote "Add to cart",
+ # :url => { :action => "add", :id => product.id },
+ # :update => { :success => "cart", :failure => "error" }
+ #
+ # ...through a form...
+ #
+ # <% form_remote_tag :url => '/shipping' do -%>
+ # <div><%= submit_tag 'Recalculate Shipping' %></div>
+ # <% end -%>
+ #
+ # ...periodically...
+ #
+ # periodically_call_remote(:url => 'update', :frequency => '5', :update => 'ticker')
+ #
+ # ...or through an observer (i.e., a form or field that is observed and calls a remote
+ # action when changed).
+ #
+ # <%= observe_field(:searchbox,
+ # :url => { :action => :live_search }),
+ # :frequency => 0.5,
+ # :update => :hits,
+ # :with => 'query'
+ # %>
+ #
+ # As you can see, there are numerous ways to use Prototype's Ajax functions (and actually more than
+ # are listed here); check out the documentation for each method to find out more about its usage and options.
+ #
+ # === Common Options
+ # See link_to_remote for documentation of options common to all Ajax
+ # helpers; any of the options specified by link_to_remote can be used
+ # by the other helpers.
+ #
# == Designing your Rails actions for Ajax
# When building your action handlers (that is, the Rails actions that receive your background requests), it's
# important to remember a few things. First, whatever your action would normally return to the browser, it will
@@ -74,8 +107,6 @@ module ActionView
# See JavaScriptGenerator for information on updating multiple elements
# on the page in an Ajax response.
module PrototypeHelper
- include ScriptaculousHelper
-
unless const_defined? :CALLBACKS
CALLBACKS = Set.new([ :create, :uninitialized, :loading, :loaded,
:interactive, :complete, :failure, :success ] +
@@ -85,6 +116,325 @@ module ActionView
:form, :with, :update, :script, :type ]).merge(CALLBACKS)
end
+ # Returns a link to a remote action defined by <tt>options[:url]</tt>
+ # (using the url_for format) that's called in the background using
+ # XMLHttpRequest. The result of that request can then be inserted into a
+ # DOM object whose id can be specified with <tt>options[:update]</tt>.
+ # Usually, the result would be a partial prepared by the controller with
+ # render :partial.
+ #
+ # Examples:
+ # # Generates: <a href="#" onclick="new Ajax.Updater('posts', '/blog/destroy/3', {asynchronous:true, evalScripts:true});
+ # # return false;">Delete this post</a>
+ # link_to_remote "Delete this post", :update => "posts",
+ # :url => { :action => "destroy", :id => post.id }
+ #
+ # # Generates: <a href="#" onclick="new Ajax.Updater('emails', '/mail/list_emails', {asynchronous:true, evalScripts:true});
+ # # return false;"><img alt="Refresh" src="/images/refresh.png?" /></a>
+ # link_to_remote(image_tag("refresh"), :update => "emails",
+ # :url => { :action => "list_emails" })
+ #
+ # You can override the generated HTML options by specifying a hash in
+ # <tt>options[:html]</tt>.
+ #
+ # link_to_remote "Delete this post", :update => "posts",
+ # :url => post_url(@post), :method => :delete,
+ # :html => { :class => "destructive" }
+ #
+ # You can also specify a hash for <tt>options[:update]</tt> to allow for
+ # easy redirection of output to an other DOM element if a server-side
+ # error occurs:
+ #
+ # Example:
+ # # Generates: <a href="#" onclick="new Ajax.Updater({success:'posts',failure:'error'}, '/blog/destroy/5',
+ # # {asynchronous:true, evalScripts:true}); return false;">Delete this post</a>
+ # link_to_remote "Delete this post",
+ # :url => { :action => "destroy", :id => post.id },
+ # :update => { :success => "posts", :failure => "error" }
+ #
+ # Optionally, you can use the <tt>options[:position]</tt> parameter to
+ # influence how the target DOM element is updated. It must be one of
+ # <tt>:before</tt>, <tt>:top</tt>, <tt>:bottom</tt>, or <tt>:after</tt>.
+ #
+ # The method used is by default POST. You can also specify GET or you
+ # can simulate PUT or DELETE over POST. All specified with <tt>options[:method]</tt>
+ #
+ # Example:
+ # # Generates: <a href="#" onclick="new Ajax.Request('/person/4', {asynchronous:true, evalScripts:true, method:'delete'});
+ # # return false;">Destroy</a>
+ # link_to_remote "Destroy", :url => person_url(:id => person), :method => :delete
+ #
+ # By default, these remote requests are processed asynchronous during
+ # which various JavaScript callbacks can be triggered (for progress
+ # indicators and the likes). All callbacks get access to the
+ # <tt>request</tt> object, which holds the underlying XMLHttpRequest.
+ #
+ # To access the server response, use <tt>request.responseText</tt>, to
+ # find out the HTTP status, use <tt>request.status</tt>.
+ #
+ # Example:
+ # # Generates: <a href="#" onclick="new Ajax.Request('/words/undo?n=33', {asynchronous:true, evalScripts:true,
+ # # onComplete:function(request){undoRequestCompleted(request)}}); return false;">hello</a>
+ # word = 'hello'
+ # link_to_remote word,
+ # :url => { :action => "undo", :n => word_counter },
+ # :complete => "undoRequestCompleted(request)"
+ #
+ # The callbacks that may be specified are (in order):
+ #
+ # <tt>:loading</tt>:: Called when the remote document is being
+ # loaded with data by the browser.
+ # <tt>:loaded</tt>:: Called when the browser has finished loading
+ # the remote document.
+ # <tt>:interactive</tt>:: Called when the user can interact with the
+ # remote document, even though it has not
+ # finished loading.
+ # <tt>:success</tt>:: Called when the XMLHttpRequest is completed,
+ # and the HTTP status code is in the 2XX range.
+ # <tt>:failure</tt>:: Called when the XMLHttpRequest is completed,
+ # and the HTTP status code is not in the 2XX
+ # range.
+ # <tt>:complete</tt>:: Called when the XMLHttpRequest is complete
+ # (fires after success/failure if they are
+ # present).
+ #
+ # You can further refine <tt>:success</tt> and <tt>:failure</tt> by
+ # adding additional callbacks for specific status codes.
+ #
+ # Example:
+ # # Generates: <a href="#" onclick="new Ajax.Request('/testing/action', {asynchronous:true, evalScripts:true,
+ # # on404:function(request){alert('Not found...? Wrong URL...?')},
+ # # onFailure:function(request){alert('HTTP Error ' + request.status + '!')}}); return false;">hello</a>
+ # link_to_remote word,
+ # :url => { :action => "action" },
+ # 404 => "alert('Not found...? Wrong URL...?')",
+ # :failure => "alert('HTTP Error ' + request.status + '!')"
+ #
+ # A status code callback overrides the success/failure handlers if
+ # present.
+ #
+ # If you for some reason or another need synchronous processing (that'll
+ # block the browser while the request is happening), you can specify
+ # <tt>options[:type] = :synchronous</tt>.
+ #
+ # You can customize further browser side call logic by passing in
+ # JavaScript code snippets via some optional parameters. In their order
+ # of use these are:
+ #
+ # <tt>:confirm</tt>:: Adds confirmation dialog.
+ # <tt>:condition</tt>:: Perform remote request conditionally
+ # by this expression. Use this to
+ # describe browser-side conditions when
+ # request should not be initiated.
+ # <tt>:before</tt>:: Called before request is initiated.
+ # <tt>:after</tt>:: Called immediately after request was
+ # initiated and before <tt>:loading</tt>.
+ # <tt>:submit</tt>:: Specifies the DOM element ID that's used
+ # as the parent of the form elements. By
+ # default this is the current form, but
+ # it could just as well be the ID of a
+ # table row or any other DOM element.
+ # <tt>:with</tt>:: A JavaScript expression specifying
+ # the parameters for the XMLHttpRequest.
+ # Any expressions should return a valid
+ # URL query string.
+ #
+ # Example:
+ #
+ # :with => "'name=' + $('name').value"
+ #
+ # You can generate a link that uses AJAX in the general case, while
+ # degrading gracefully to plain link behavior in the absence of
+ # JavaScript by setting <tt>html_options[:href]</tt> to an alternate URL.
+ # Note the extra curly braces around the <tt>options</tt> hash separate
+ # it as the second parameter from <tt>html_options</tt>, the third.
+ #
+ # Example:
+ # link_to_remote "Delete this post",
+ # { :update => "posts", :url => { :action => "destroy", :id => post.id } },
+ # :href => url_for(:action => "destroy", :id => post.id)
+ def link_to_remote(name, options = {}, html_options = nil)
+ link_to_function(name, remote_function(options), html_options || options.delete(:html))
+ end
+
+ # Creates a button with an onclick event which calls a remote action
+ # via XMLHttpRequest
+ # The options for specifying the target with :url
+ # and defining callbacks is the same as link_to_remote.
+ def button_to_remote(name, options = {}, html_options = {})
+ button_to_function(name, remote_function(options), html_options)
+ end
+
+ # Periodically calls the specified url (<tt>options[:url]</tt>) every
+ # <tt>options[:frequency]</tt> seconds (default is 10). Usually used to
+ # update a specified div (<tt>options[:update]</tt>) with the results
+ # of the remote call. The options for specifying the target with <tt>:url</tt>
+ # and defining callbacks is the same as link_to_remote.
+ # Examples:
+ # # Call get_averages and put its results in 'avg' every 10 seconds
+ # # Generates:
+ # # new PeriodicalExecuter(function() {new Ajax.Updater('avg', '/grades/get_averages',
+ # # {asynchronous:true, evalScripts:true})}, 10)
+ # periodically_call_remote(:url => { :action => 'get_averages' }, :update => 'avg')
+ #
+ # # Call invoice every 10 seconds with the id of the customer
+ # # If it succeeds, update the invoice DIV; if it fails, update the error DIV
+ # # Generates:
+ # # new PeriodicalExecuter(function() {new Ajax.Updater({success:'invoice',failure:'error'},
+ # # '/testing/invoice/16', {asynchronous:true, evalScripts:true})}, 10)
+ # periodically_call_remote(:url => { :action => 'invoice', :id => customer.id },
+ # :update => { :success => "invoice", :failure => "error" }
+ #
+ # # Call update every 20 seconds and update the new_block DIV
+ # # Generates:
+ # # new PeriodicalExecuter(function() {new Ajax.Updater('news_block', 'update', {asynchronous:true, evalScripts:true})}, 20)
+ # periodically_call_remote(:url => 'update', :frequency => '20', :update => 'news_block')
+ #
+ def periodically_call_remote(options = {})
+ frequency = options[:frequency] || 10 # every ten seconds by default
+ code = "new PeriodicalExecuter(function() {#{remote_function(options)}}, #{frequency})"
+ javascript_tag(code)
+ end
+
+ # Returns a form tag that will submit using XMLHttpRequest in the
+ # background instead of the regular reloading POST arrangement. Even
+ # though it's using JavaScript to serialize the form elements, the form
+ # submission will work just like a regular submission as viewed by the
+ # receiving side (all elements available in <tt>params</tt>). The options for
+ # specifying the target with <tt>:url</tt> and defining callbacks is the same as
+ # +link_to_remote+.
+ #
+ # A "fall-through" target for browsers that doesn't do JavaScript can be
+ # specified with the <tt>:action</tt>/<tt>:method</tt> options on <tt>:html</tt>.
+ #
+ # Example:
+ # # Generates:
+ # # <form action="/some/place" method="post" onsubmit="new Ajax.Request('',
+ # # {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;">
+ # form_remote_tag :html => { :action =>
+ # url_for(:controller => "some", :action => "place") }
+ #
+ # The Hash passed to the <tt>:html</tt> key is equivalent to the options (2nd)
+ # argument in the FormTagHelper.form_tag method.
+ #
+ # By default the fall-through action is the same as the one specified in
+ # the <tt>:url</tt> (and the default method is <tt>:post</tt>).
+ #
+ # form_remote_tag also takes a block, like form_tag:
+ # # Generates:
+ # # <form action="/" method="post" onsubmit="new Ajax.Request('/',
+ # # {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)});
+ # # return false;"> <div><input name="commit" type="submit" value="Save" /></div>
+ # # </form>
+ # <% form_remote_tag :url => '/posts' do -%>
+ # <div><%= submit_tag 'Save' %></div>
+ # <% end -%>
+ def form_remote_tag(options = {}, &block)
+ options[:form] = true
+
+ options[:html] ||= {}
+ options[:html][:onsubmit] =
+ (options[:html][:onsubmit] ? options[:html][:onsubmit] + "; " : "") +
+ "#{remote_function(options)}; return false;"
+
+ form_tag(options[:html].delete(:action) || url_for(options[:url]), options[:html], &block)
+ end
+
+ # Creates a form that will submit using XMLHttpRequest in the background
+ # instead of the regular reloading POST arrangement and a scope around a
+ # specific resource that is used as a base for questioning about
+ # values for the fields.
+ #
+ # === Resource
+ #
+ # Example:
+ # <% remote_form_for(@post) do |f| %>
+ # ...
+ # <% end %>
+ #
+ # This will expand to be the same as:
+ #
+ # <% remote_form_for :post, @post, :url => post_path(@post), :html => { :method => :put, :class => "edit_post", :id => "edit_post_45" } do |f| %>
+ # ...
+ # <% end %>
+ #
+ # === Nested Resource
+ #
+ # Example:
+ # <% remote_form_for([@post, @comment]) do |f| %>
+ # ...
+ # <% end %>
+ #
+ # This will expand to be the same as:
+ #
+ # <% remote_form_for :comment, @comment, :url => post_comment_path(@post, @comment), :html => { :method => :put, :class => "edit_comment", :id => "edit_comment_45" } do |f| %>
+ # ...
+ # <% end %>
+ #
+ # If you don't need to attach a form to a resource, then check out form_remote_tag.
+ #
+ # See FormHelper#form_for for additional semantics.
+ def remote_form_for(record_or_name_or_array, *args, &proc)
+ options = args.extract_options!
+
+ case record_or_name_or_array
+ when String, Symbol
+ object_name = record_or_name_or_array
+ when Array
+ object = record_or_name_or_array.last
+ object_name = ActionController::RecordIdentifier.singular_class_name(object)
+ apply_form_for_options!(record_or_name_or_array, options)
+ args.unshift object
+ else
+ object = record_or_name_or_array
+ object_name = ActionController::RecordIdentifier.singular_class_name(record_or_name_or_array)
+ apply_form_for_options!(object, options)
+ args.unshift object
+ end
+
+ concat(form_remote_tag(options))
+ fields_for(object_name, *(args << options), &proc)
+ concat('</form>'.html_safe!)
+ end
+ alias_method :form_remote_for, :remote_form_for
+
+ # Returns a button input tag with the element name of +name+ and a value (i.e., display text) of +value+
+ # that will submit form using XMLHttpRequest in the background instead of a regular POST request that
+ # reloads the page.
+ #
+ # # Create a button that submits to the create action
+ # #
+ # # Generates: <input name="create_btn" onclick="new Ajax.Request('/testing/create',
+ # # {asynchronous:true, evalScripts:true, parameters:Form.serialize(this.form)});
+ # # return false;" type="button" value="Create" />
+ # <%= submit_to_remote 'create_btn', 'Create', :url => { :action => 'create' } %>
+ #
+ # # Submit to the remote action update and update the DIV succeed or fail based
+ # # on the success or failure of the request
+ # #
+ # # Generates: <input name="update_btn" onclick="new Ajax.Updater({success:'succeed',failure:'fail'},
+ # # '/testing/update', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this.form)});
+ # # return false;" type="button" value="Update" />
+ # <%= submit_to_remote 'update_btn', 'Update', :url => { :action => 'update' },
+ # :update => { :success => "succeed", :failure => "fail" }
+ #
+ # <tt>options</tt> argument is the same as in form_remote_tag.
+ def submit_to_remote(name, value, options = {})
+ options[:with] ||= 'Form.serialize(this.form)'
+
+ html_options = options.delete(:html) || {}
+ html_options[:name] = name
+
+ button_to_remote(value, options, html_options)
+ end
+
+ # Returns '<tt>eval(request.responseText)</tt>' which is the JavaScript function
+ # that +form_remote_tag+ can call in <tt>:complete</tt> to evaluate a multiple
+ # update return document using +update_element_function+ calls.
+ def evaluate_remote_response
+ "eval(request.responseText)"
+ end
+
# Returns the JavaScript needed for a remote function.
# Takes the same arguments as link_to_remote.
#
@@ -126,6 +476,99 @@ module ActionView
return function
end
+ # Observes the field with the DOM ID specified by +field_id+ and calls a
+ # callback when its contents have changed. The default callback is an
+ # Ajax call. By default the value of the observed field is sent as a
+ # parameter with the Ajax call.
+ #
+ # Example:
+ # # Generates: new Form.Element.Observer('suggest', 0.25, function(element, value) {new Ajax.Updater('suggest',
+ # # '/testing/find_suggestion', {asynchronous:true, evalScripts:true, parameters:'q=' + value})})
+ # <%= observe_field :suggest, :url => { :action => :find_suggestion },
+ # :frequency => 0.25,
+ # :update => :suggest,
+ # :with => 'q'
+ # %>
+ #
+ # Required +options+ are either of:
+ # <tt>:url</tt>:: +url_for+-style options for the action to call
+ # when the field has changed.
+ # <tt>:function</tt>:: Instead of making a remote call to a URL, you
+ # can specify javascript code to be called instead.
+ # Note that the value of this option is used as the
+ # *body* of the javascript function, a function definition
+ # with parameters named element and value will be generated for you
+ # for example:
+ # observe_field("glass", :frequency => 1, :function => "alert('Element changed')")
+ # will generate:
+ # new Form.Element.Observer('glass', 1, function(element, value) {alert('Element changed')})
+ # The element parameter is the DOM element being observed, and the value is its value at the
+ # time the observer is triggered.
+ #
+ # Additional options are:
+ # <tt>:frequency</tt>:: The frequency (in seconds) at which changes to
+ # this field will be detected. Not setting this
+ # option at all or to a value equal to or less than
+ # zero will use event based observation instead of
+ # time based observation.
+ # <tt>:update</tt>:: Specifies the DOM ID of the element whose
+ # innerHTML should be updated with the
+ # XMLHttpRequest response text.
+ # <tt>:with</tt>:: A JavaScript expression specifying the parameters
+ # for the XMLHttpRequest. The default is to send the
+ # key and value of the observed field. Any custom
+ # expressions should return a valid URL query string.
+ # The value of the field is stored in the JavaScript
+ # variable +value+.
+ #
+ # Examples
+ #
+ # :with => "'my_custom_key=' + value"
+ # :with => "'person[name]=' + prompt('New name')"
+ # :with => "Form.Element.serialize('other-field')"
+ #
+ # Finally
+ # :with => 'name'
+ # is shorthand for
+ # :with => "'name=' + value"
+ # This essentially just changes the key of the parameter.
+ #
+ # Additionally, you may specify any of the options documented in the
+ # <em>Common options</em> section at the top of this document.
+ #
+ # Example:
+ #
+ # # Sends params: {:title => 'Title of the book'} when the book_title input
+ # # field is changed.
+ # observe_field 'book_title',
+ # :url => 'http://example.com/books/edit/1',
+ # :with => 'title'
+ #
+ #
+ def observe_field(field_id, options = {})
+ if options[:frequency] && options[:frequency] > 0
+ build_observer('Form.Element.Observer', field_id, options)
+ else
+ build_observer('Form.Element.EventObserver', field_id, options)
+ end
+ end
+
+ # Observes the form with the DOM ID specified by +form_id+ and calls a
+ # callback when its contents have changed. The default callback is an
+ # Ajax call. By default all fields of the observed field are sent as
+ # parameters with the Ajax call.
+ #
+ # The +options+ for +observe_form+ are the same as the options for
+ # +observe_field+. The JavaScript variable +value+ available to the
+ # <tt>:with</tt> option is set to the serialized form by default.
+ def observe_form(form_id, options = {})
+ if options[:frequency]
+ build_observer('Form.Observer', form_id, options)
+ else
+ build_observer('Form.EventObserver', form_id, options)
+ end
+ end
+
# All the methods were moved to GeneratorMethods so that
# #include_helpers_from_context has nothing to overwrite.
class JavaScriptGenerator #:nodoc:
diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb
index 837dca6149..d6bfc6d4c9 100644
--- a/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/actionpack/lib/action_view/helpers/url_helper.rb
@@ -291,6 +291,9 @@ module ActionView
request_token_tag = tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token)
end
+ if confirm = html_options.delete("confirm")
+ html_options["onclick"] = "return #{confirm_javascript_function(confirm)};"
+ end
url = options.is_a?(String) ? options : self.url_for(options)
name ||= url
@@ -548,6 +551,48 @@ module ActionView
end
private
+ def convert_options_to_javascript!(html_options, url = '')
+ confirm = html_options.delete("confirm")
+ method, href = html_options.delete("method"), html_options['href']
+
+ if html_options.key?("popup")
+ ActiveSupport::Deprecation.warn(":popup has been deprecated", caller)
+ end
+
+ html_options["onclick"] = case
+ when confirm && method
+ "if (#{confirm_javascript_function(confirm)}) { #{method_javascript_function(method, url, href)} };return false;"
+ when confirm
+ "return #{confirm_javascript_function(confirm)};"
+ when method
+ "#{method_javascript_function(method, url, href)}return false;"
+ else
+ html_options["onclick"]
+ end
+ end
+
+ def confirm_javascript_function(confirm)
+ "confirm('#{escape_javascript(confirm)}')"
+ end
+
+ def method_javascript_function(method, url = '', href = nil)
+ action = (href && url.size > 0) ? "'#{url}'" : 'this.href'
+ submit_function =
+ "var f = document.createElement('form'); f.style.display = 'none'; " +
+ "this.parentNode.appendChild(f); f.method = 'POST'; f.action = #{action};"
+
+ unless method == :post
+ submit_function << "var m = document.createElement('input'); m.setAttribute('type', 'hidden'); "
+ submit_function << "m.setAttribute('name', '_method'); m.setAttribute('value', '#{method}'); f.appendChild(m);"
+ end
+
+ if protect_against_forgery?
+ submit_function << "var s = document.createElement('input'); s.setAttribute('type', 'hidden'); "
+ submit_function << "s.setAttribute('name', '#{request_forgery_protection_token}'); s.setAttribute('value', '#{escape_javascript form_authenticity_token}'); f.appendChild(s);"
+ end
+ submit_function << "f.submit();"
+ end
+
# Processes the +html_options+ hash, converting the boolean
# attributes from true/false form into the form required by
# HTML/XHTML. (An attribute is considered to be boolean if
diff --git a/actionpack/test/template/ajax_helper_test.rb b/actionpack/test/template/ajax_helper_test.rb
deleted file mode 100644
index c925dbb8f6..0000000000
--- a/actionpack/test/template/ajax_helper_test.rb
+++ /dev/null
@@ -1,452 +0,0 @@
-require 'abstract_unit'
-require 'active_model'
-
-class Author
- extend ActiveModel::Naming
- include ActiveModel::Conversion
-
- attr_reader :id
- def save
- @id = 1
- end
-
- def new_record?
- @id.nil?
- end
-
- def name
- @id.nil? ? 'new author' : "author ##{@id}"
- end
-end
-
-class Article
- extend ActiveModel::Naming
- include ActiveModel::Conversion
- attr_reader :id
- attr_reader :author_id
-
- def save
- @id = 1
- @author_id = 1
- end
-
- def new_record?
- @id.nil?
- end
-
- def name
- @id.nil? ? 'new article' : "article ##{@id}"
- end
-end
-
-class AjaxHelperBaseTest < ActionView::TestCase
- attr_accessor :formats, :output_buffer
-
- def reset_formats(format)
- @format = format
- end
-
- def setup
- super
- @template = self
- @controller = Class.new do
-
- def url_for(options)
- return optons unless options.is_a?(Hash)
-
- url = options.delete(:only_path) ? '/' : 'http://www.example.com'
-
- if controller = options.delete(:controller)
- url << '/' << controller.to_s
- end
- if action = options.delete(:action)
- url << '/' << action.to_s
- end
-
- if id = options.delete(:id)
- url << '/' << id.to_s
- end
-
- url << hash_to_param(options) if options.any?
-
- url.gsub!(/\/\/+/,'/')
-
- url
- end
-
- private
- def hash_to_param(hash)
- hash.map { |k,v| "#{k}=#{v}" }.join('&').insert(0,'?')
- end
- end.new
- end
-
- protected
- def request_forgery_protection_token
- nil
- end
-
- def protect_against_forgery?
- false
- end
-end
-
-class AjaxHelperTest < AjaxHelperBaseTest
- def _evaluate_assigns_and_ivars() end
-
- def setup
- @record = @author = Author.new
- @article = Article.new
- super
- end
-
- test "link_to_remote" do
- assert_dom_equal %(<a class=\"fine\" href=\"#\" data-remote=\"true\" data-url=\"/whatnot\">Remove Author</a>),
- link_to_remote("Remove Author", { :url => { :action => "whatnot" }}, { :class => "fine" })
- assert_dom_equal %(<a href=\"#\" data-remote=\"true\" data-url=\"/whatnot\" data-oncomplete=\"alert(request.responseText)\">Remove Author</a>),
- link_to_remote("Remove Author", :complete => "alert(request.responseText)", :url => { :action => "whatnot" })
- assert_dom_equal %(<a href=\"#\" data-remote=\"true\" data-url=\"/whatnot\" data-onsuccess=\"alert(request.responseText)\">Remove Author</a>),
- link_to_remote("Remove Author", :success => "alert(request.responseText)", :url => { :action => "whatnot" })
- assert_dom_equal %(<a href=\"#\" data-remote=\"true\" data-url=\"/whatnot\" data-onfailure=\"alert(request.responseText)\">Remove Author</a>),
- link_to_remote("Remove Author", :failure => "alert(request.responseText)", :url => { :action => "whatnot" })
- assert_dom_equal %(<a href=\"#\" data-remote=\"true\" data-url=\"/whatnot?a=10&amp;b=20\" data-onfailure=\"alert(request.responseText)\">Remove Author</a>),
- link_to_remote("Remove Author", :failure => "alert(request.responseText)", :url => { :action => "whatnot", :a => '10', :b => '20' })
- assert_dom_equal %(<a href=\"#\" data-remote=\"true\" data-url=\"/whatnot\" data-remote-type=\"synchronous\">Remove Author</a>),
- link_to_remote("Remove Author", :url => { :action => "whatnot" }, :type => :synchronous)
- assert_dom_equal %(<a href=\"#\" data-remote=\"true\" data-url=\"/whatnot\" data-update-position=\"bottom\">Remove Author</a>),
- link_to_remote("Remove Author", :url => { :action => "whatnot" }, :position => :bottom)
- end
-
- test "link_to_remote with url and oncomplete" do
- actual = link_to_remote "undo", :url => { :controller => "words", :action => "undo", :n => 5 }, :complete => "undoRequestCompleted(request)"
- expected = '<a href="#" data-url="/words/undo?n=5" data-remote="true" data-oncomplete="undoRequestCompleted(request)">undo</a>'
- assert_dom_equal expected, actual
- end
-
- test "link_to_remote with delete" do
- actual = link_to_remote("Remove Author", { :url => { :action => "whatnot" }, :method => 'delete'}, { :class => "fine" })
- expected = '<a class="fine" rel="nofollow" href="#" data-remote="true" data-method="delete" data-url="/whatnot">Remove Author</a>'
- assert_dom_equal expected, actual
- end
-
- test "link_to_remote using both url and href" do
- expected = '<a href="/destroy" data-url="/destroy" data-update-success="posts" data-remote="true">Delete this Post</a>'
- assert_dom_equal expected, link_to_remote( "Delete this Post",
- { :update => "posts",
- :url => { :action => "destroy" } },
- :href => url_for(:action => "destroy"))
- end
-
- test "link_to_remote with update-success and url" do
- expected = '<a href="#" data-url="/destroy" data-update-success="posts" data-update-failure="error" data-remote="true">Delete this Post</a>'
- assert_dom_equal expected, link_to_remote( "Delete this Post", :url => { :action => "destroy"},
- :update => { :success => "posts", :failure => "error" })
- end
-
- test "link_to_remote with before/after callbacks" do
- assert_dom_equal %(<a href=\"#\" data-remote=\"true\" data-url=\"/whatnot\" data-onbefore=\"before();\" data-onafter=\"after();\">Remote outauthor</a>),
- link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :before => "before();", :after => "after();")
- end
-
- test "link_to_remote using :with expression" do
- expected = %(<a href=\"#\" data-remote=\"true\" data-url=\"/whatnot\" data-with=\"id=123\">Remote outauthor</a>)
- assert_dom_equal expected, link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :with => "id=123")
- end
-
- test "link_to_remote using :condition expression" do
- expected = %(<a href=\"#\" data-remote=\"true\" data-url=\"/whatnot\" data-condition=\"$('foo').val() == true\">Remote outauthor</a>)
- assert_dom_equal expected, link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :condition => '$(\'foo\').val() == true')
- end
-
- test "link_to_remote using explicit :href" do
- expected = %(<a href=\"http://www.example.com/testhref\" data-remote=\"true\" data-url=\"/whatnot\" data-condition=\"$('foo').val() == true\">Remote outauthor</a>)
- assert_dom_equal expected, link_to_remote("Remote outauthor", {:url => { :action => "whatnot" }, :condition => '$(\'foo\').val() == true'}, :href => 'http://www.example.com/testhref')
- end
-
- test "link_to_remote using :submit" do
- expected = %(<a href=\"#\" data-remote=\"true\" data-url=\"/whatnot\" data-submit=\"myForm\">Remote outauthor</a>)
- assert_dom_equal expected, link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :submit => 'myForm')
- end
-
- test "link_to_remote with method delete" do
- assert_dom_equal %(<a class=\"fine\" href=\"#\" data-remote=\"true\" data-url=\"/whatnot\" data-method=\"delete\" rel=\"nofollow\">Remote outauthor</a>),
- link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }, :method => "delete"}, { :class => "fine" })
- end
-
- test "link_to_remote with method delete as symbol" do
- assert_dom_equal %(<a class=\"fine\" href=\"#\" data-remote=\"true\" data-url=\"/whatnot\" data-method=\"delete\" rel=\"nofollow\">Remote outauthor</a>),
- link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }, :method => :delete}, { :class => "fine" })
- end
-
- test "link_to_remote html options" do
- assert_dom_equal %(<a class=\"fine\" href=\"#\" data-remote=\"true\" data-url=\"/whatnot\">Remote outauthor</a>),
- link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }, :html => { :class => "fine" } })
- end
-
- test "link_to_remote url quote escaping" do
- assert_dom_equal %(<a href="#" data-remote=\"true\" data-url=\"/whatnot\\\'s\">Remote</a>),
- link_to_remote("Remote", { :url => { :action => "whatnot's" } })
- end
-
- test "link_to_remote with confirm" do
- assert_dom_equal %(<a class=\"fine\" href=\"#\" data-remote=\"true\" data-url=\"/whatnot\" data-method=\"delete\" rel=\"nofollow\" data-confirm="Are you sure?">Remote confirm</a>),
- link_to_remote("Remote confirm", { :url => { :action => "whatnot" }, :method => "delete", :confirm => "Are you sure?"}, { :class => "fine" })
- end
-
- test "button_to_remote" do
- assert_dom_equal %(<input class=\"fine\" type=\"button\" value=\"Remote outpost\" data-remote=\"true\" data-url=\"/whatnot\" />),
- button_to_remote("Remote outpost", { :url => { :action => "whatnot" }}, { :class => "fine" })
- assert_dom_equal %(<input type=\"button\" value=\"Remote outpost\" data-remote=\"true\" data-url=\"/whatnot\" data-oncomplete=\"alert(request.reponseText)\" />),
- button_to_remote("Remote outpost", :complete => "alert(request.reponseText)", :url => { :action => "whatnot" })
- assert_dom_equal %(<input type=\"button\" value=\"Remote outpost\" data-remote=\"true\" data-url=\"/whatnot\" data-onsuccess=\"alert(request.reponseText)\" />),
- button_to_remote("Remote outpost", :success => "alert(request.reponseText)", :url => { :action => "whatnot" })
- assert_dom_equal %(<input type=\"button\" value=\"Remote outpost\" data-remote=\"true\" data-url=\"/whatnot\" data-onfailure=\"alert(request.reponseText)\" />),
- button_to_remote("Remote outpost", :failure => "alert(request.reponseText)", :url => { :action => "whatnot" })
- assert_dom_equal %(<input type=\"button\" value=\"Remote outpost\" data-remote=\"true\" data-url=\"/whatnot?a=10&amp;b=20\" data-onfailure=\"alert(request.reponseText)\" />),
- button_to_remote("Remote outpost", :failure => "alert(request.reponseText)", :url => { :action => "whatnot", :a => '10', :b => '20' })
- end
-
- test "button_to_remote with confirm" do
- assert_dom_equal %(<input class=\"fine\" type=\"button\" value=\"Remote outpost\" data-remote=\"true\" data-url=\"/whatnot\" data-confirm="Are you sure?" />),
- button_to_remote("Remote outpost", { :url => { :action => "whatnot" }, :confirm => "Are you sure?"}, { :class => "fine" })
- end
-
- test "button_to_remote with :submit" do
- assert_dom_equal %(<input class=\"fine\" type=\"button\" value=\"Remote outpost\" data-remote=\"true\" data-url=\"/whatnot\" data-submit="myForm" />),
- button_to_remote("Remote outpost", { :url => { :action => "whatnot" }, :submit => "myForm"}, { :class => "fine" })
- end
-
- test "periodically_call_remote" do
- expected = "<script data-url='/mehr_bier' data-update-success='schremser_bier' type='application/json' data-frequency='10' data-periodical='true'></script>"
- actual = periodically_call_remote(:update => "schremser_bier", :url => { :action => "mehr_bier" })
- assert_dom_equal expected, actual
- end
-
- test "periodically_call_remote_with_frequency" do
- expected = "<script data-periodical='true' type='application/json' data-frequency='2'></script>"
- actual = periodically_call_remote(:frequency => 2)
- assert_dom_equal expected, actual
- end
-
- test "periodically_call_remote_with_function" do
- expected = "<script data-periodical=\"true\" type=\"application/json\" data-onobserve=\"alert('test')\" data-frequency='2'></script>"
- actual = periodically_call_remote(:frequency => 2, :function => "alert('test')")
- assert_dom_equal expected, actual
- end
-
- test "periodically_call_remote_with_update" do
- actual = periodically_call_remote(:url => { :action => 'get_averages' }, :update => 'avg')
- expected = "<script data-periodical='true' data-url='/get_averages' type='application/json' data-update-success='avg' data-frequency='10'></script>"
- assert_dom_equal expected, actual
- end
-
- test "periodically_call_remote with update success and failure" do
- actual = periodically_call_remote(:url => { :action => 'invoice', :id => 1 },:update => { :success => "invoice", :failure => "error" })
- expected = "<script data-periodical='true' data-url='/invoice/1' type='application/json' data-update-success='invoice' data-frequency='10' data-update-failure='error'></script>"
- assert_dom_equal expected, actual
- end
-
- test "periodically_call_remote with frequency and update" do
- actual = periodically_call_remote(:url => 'update', :frequency => '20', :update => 'news_block')
- expected = "<script data-periodical='true' data-url='update' type='application/json' data-update-success='news_block' data-frequency='20'></script>"
- assert_dom_equal expected, actual
- end
-
- test "form_remote_tag" do
- assert_dom_equal %(<form action=\"/fast\" method=\"post\" data-remote=\"true\" data-update-success=\"glass_of_beer\">),
- form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast } )
- assert_dom_equal %(<form action=\"/fast\" method=\"post\" data-remote=\"true\" data-update-success=\"glass_of_beer\">),
- form_remote_tag(:update => { :success => "glass_of_beer" }, :url => { :action => :fast })
- assert_dom_equal %(<form action=\"/fast\" method=\"post\" data-remote=\"true\" data-update-failure=\"glass_of_water\">),
- form_remote_tag(:update => { :failure => "glass_of_water" }, :url => { :action => :fast })
- assert_dom_equal %(<form action=\"/fast\" method=\"post\" data-remote=\"true\" data-update-success=\"glass_of_beer\" data-update-failure=\"glass_of_water\">),
- form_remote_tag(:update => { :success => 'glass_of_beer', :failure => "glass_of_water" }, :url => { :action => :fast })
- end
-
- test "form_remote_tag with method" do
- assert_dom_equal %(<form action=\"/fast\" method=\"post\" data-remote=\"true\" data-update-success=\"glass_of_beer\"><div style='margin:0;padding:0;display:inline'><input name='_method' type='hidden' value='put' /></div>),
- form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, :html => { :method => :put })
- end
-
- test "form_remote_tag with url" do
- form_remote_tag(:url => '/posts' ){}
- expected = "<form action='/posts' method='post' data-remote='true'></form>"
- assert_dom_equal expected, output_buffer
- end
-
- test "form_remote_tag with block in erb" do
- __in_erb_template = ''
- form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) { concat "Hello world!" }
- assert_dom_equal %(<form action=\"/fast\" method=\"post\" data-remote=\"true\" data-update-success=\"glass_of_beer\">Hello world!</form>), output_buffer
- end
-
- test "remote_form_for with record identification with new record" do
- remote_form_for(@record, {:html => { :id => 'create-author' }}) {}
- expected = %(<form action='#{authors_path}' data-remote=\"true\" class='new_author' id='create-author' method='post'></form>)
- assert_dom_equal expected, output_buffer
- end
-
- test "remote_form_for with url" do
- remote_form_for(@record, {:html => { :id => 'create-author' }}) {}
- expected = "<form action='/authors' data-remote='true' class='new_author' id='create-author' method='post'></form>"
- assert_dom_equal expected, output_buffer
- end
-
- test "remote_form_for with record identification without html options" do
- remote_form_for(@record) {}
- expected = %(<form action='#{authors_path}' data-remote=\"true\" class='new_author' method='post' id='new_author'></form>)
- assert_dom_equal expected, output_buffer
- end
-
- test "remote_form_for with record identification with existing record" do
- @record.save
- remote_form_for(@record) {}
-
- expected = %(<form action='#{author_path(@record)}' id='edit_author_1' method='post' data-remote=\"true\" class='edit_author'><div style='margin:0;padding:0;display:inline'><input name='_method' type='hidden' value='put' /></div></form>)
- assert_dom_equal expected, output_buffer
- end
-
- test "remote_form_for with new nested object and an excisting parent" do
- @author.save
- remote_form_for([@author, @article]) {}
-
- expected = %(<form action='#{author_articles_path(@author)}' data-remote=\"true\" class='new_article' method='post' id='new_article'></form>)
- assert_dom_equal expected, output_buffer
- end
-
- test "remote_form_for with existing object in list" do
- @author.save
- @article.save
-
- remote_form_for([@author, @article]) {}
-
- expected = %(<form action='#{author_article_path(@author, @article)}' id='edit_article_#{@article.id}' method='post' data-remote=\"true\" class='edit_article'><div style='margin:0;padding:0;display:inline'><input name='_method' type='hidden' value='put' /></div></form>)
- assert_dom_equal expected, output_buffer
- end
-
- test "on callbacks" do
- callbacks = [:uninitialized, :loading, :loaded, :interactive, :complete, :success, :failure]
- callbacks.each do |callback|
- assert_dom_equal %(<form action=\"/fast\" method=\"post\" data-remote=\"true\" data-update-success=\"glass_of_beer\" data-on#{callback}=\"monkeys();\">),
- form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();")
- assert_dom_equal %(<form action=\"/fast\" method=\"post\" data-remote=\"true\" data-update-success=\"glass_of_beer\" data-on#{callback}=\"monkeys();\">),
- form_remote_tag(:update => { :success => "glass_of_beer" }, :url => { :action => :fast }, callback=>"monkeys();")
- assert_dom_equal %(<form action=\"/fast\" method=\"post\" data-remote=\"true\" data-update-failure=\"glass_of_beer\" data-on#{callback}=\"monkeys();\">),
- form_remote_tag(:update => { :failure => "glass_of_beer" }, :url => { :action => :fast }, callback=>"monkeys();")
- assert_dom_equal %(<form action=\"/fast\" method=\"post\" data-remote=\"true\" data-update-failure=\"glass_of_water\" data-update-success=\"glass_of_beer\" data-on#{callback}=\"monkeys();\">),
- form_remote_tag(:update => { :success => "glass_of_beer", :failure => "glass_of_water" }, :url => { :action => :fast }, callback=>"monkeys();")
- end
-
- #HTTP status codes 200 up to 599 have callbacks
- #these should work
- 100.upto(599) do |callback|
- assert_dom_equal %(<form action=\"/fast\" method=\"post\" data-remote=\"true\" data-update-success=\"glass_of_beer\" data-on#{callback}=\"monkeys();\">),
- form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();")
- end
-
- #test 200 and 404
- assert_dom_equal %(<form action=\"/fast\" method=\"post\" data-remote=\"true\" data-update-success=\"glass_of_beer\" data-on200=\"monkeys();\" data-on404=\"bananas();\">),
- form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, 200=>"monkeys();", 404=>"bananas();")
-
- #these shouldn't
- 1.upto(99) do |callback|
- assert_dom_equal %(<form action=\"/fast\" method=\"post\" data-remote=\"true\" data-update-success=\"glass_of_beer\" data-on#{callback}=\"monkeys();\">),
- form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();")
- end
- 600.upto(999) do |callback|
- assert_dom_equal %(<form action=\"/fast\" method=\"post\" data-remote=\"true\" data-update-success=\"glass_of_beer\" data-on#{callback}=\"monkeys();\">),
- form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();")
- end
-
- #test ultimate combo
- assert_dom_equal %(<form data-on404=\"bananas();\" method=\"post\" data-onsuccess=\"s()\" action=\"/fast\" data-oncomplete=\"c();\" data-update-success=\"glass_of_beer\" data-on200=\"monkeys();\" data-onloading=\"c1()\" data-remote=\"true\" data-onfailure=\"f();\">),
- form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, :loading => "c1()", :success => "s()", :failure => "f();", :complete => "c();", 200=>"monkeys();", 404=>"bananas();")
-
- end
-
- test "submit_to_remote" do
- assert_dom_equal %(<input name=\"More beer!\" type=\"button\" value=\"1000000\" data-url=\"/empty_bottle\" data-remote-submit=\"true\" data-update-success=\"empty_bottle\" />),
- submit_to_remote("More beer!", 1_000_000, :url => { :action => 'empty_bottle' }, :update => "empty_bottle")
- end
-
- test "submit_to_remote simple" do
- expected = "<input name='create_btn' type='button' value='Create' data-remote-submit='true' data-url='/create' />"
- actual = submit_to_remote 'create_btn', 'Create', :url => { :action => 'create' }
- assert_dom_equal expected, actual
- end
-
- test "submit_to_remote with success and failure" do
- expected = "<input name='update_btn' data-url='/update' data-remote-submit='true' data-update-failure='fail' data-update-success='succeed' value='Update' type='button' />"
- actual = submit_to_remote 'update_btn', 'Update', :url => { :action => 'update' }, :update => { :success => "succeed", :failure => "fail" }
- assert_dom_equal expected, actual
- end
-
- test "observe_field" do
- assert_dom_equal %(<script type=\"text/javascript\" data-observe=\"true\" data-observed=\"glass\" data-frequency=\"300\" type=\"application/json\" data-url=\"/reorder_if_empty\"></script>),
- observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" })
- end
-
- test "observe_field with url, frequency, update and with" do
- actual = observe_field :suggest, :url => { :action => :find_suggestion }, :frequency => 0.25, :update => :suggest, :with => 'q'
- expected = "<script type='text/javascript' data-observe='true' data-observed='suggest' data-frequency='0.25' type='application/json' data-url='/find_suggestion' data-update-success='suggest' data-with='q'></script>"
- assert_dom_equal actual, expected
- end
-
- test "observe_field default frequency" do
- actual = observe_field :suggest
- expected = "<script type='text/javascript' data-observe='true' data-observed='suggest' data-frequency='10' type='application/json'></script>"
- assert_dom_equal actual, expected
- end
-
- test "observe_field using with option" do
- expected = %(<script type=\"text/javascript\" data-observe=\"true\" data-observed=\"glass\" data-frequency=\"300\" type=\"application/json\" data-url=\"/check_value\" data-with=\"id=123\"></script>)
- assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => 'id=123')
- end
-
- test "observe_field using condition option" do
- expected = %(<script type=\"text/javascript\" data-observe=\"true\" data-observed=\"glass\" data-frequency=\"300\" type=\"application/json\" data-url=\"/check_value\" data-condition=\"$('foo').val() == true\"></script>)
- assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :condition => '$(\'foo\').val() == true')
- end
-
- test "observe_field using json in with option" do
- expected = %(<script data-with=\"{'id':value}\" data-observed=\"glass\" data-url=\"/check_value\" data-observe=\"true\" type=\"application/json\" data-frequency=\"300\"></script>)
- assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "{'id':value}")
- end
-
- test "observe_field using function for callback" do
- assert_dom_equal %(<script data-observed=\"glass\" data-observe=\"true\" type=\"application/json\" data-onobserve=\"alert('Element changed')\" data-frequency=\"300\"></script>),
- observe_field("glass", :frequency => 5.minutes, :function => "alert('Element changed')")
- end
-
- test "observe_form" do
- assert_dom_equal %(<script data-observed=\"cart\" data-url=\"/cart_changed\" data-observe=\"true\" type=\"application/json\" data-frequency=\"2\"></script>),
- observe_form("cart", :frequency => 2, :url => { :action => "cart_changed" })
- end
-
- test "observe_form using function for callback" do
- assert_dom_equal %(<script data-observed=\"cart\" data-observe=\"true\" type=\"application/json\" data-onobserve=\"alert('Form changed')\" data-frequency=\"2\"></script>),
- observe_form("cart", :frequency => 2, :function => "alert('Form changed')")
- end
-
- test "observe_field without frequency" do
- assert_dom_equal %(<script data-observed=\"glass\" data-observe=\"true\" type=\"application/json\" data-frequency='10'></script>),
- observe_field("glass")
- end
-
- protected
- def author_path(record)
- "/authors/#{record.id}"
- end
-
- def authors_path
- "/authors"
- end
-
- def author_articles_path(author)
- "/authors/#{author.id}/articles"
- end
-
- def author_article_path(author, article)
- "/authors/#{author.id}/articles/#{article.id}"
- end
-end
diff --git a/actionpack/test/template/ajax_test.rb b/actionpack/test/template/ajax_test.rb
new file mode 100644
index 0000000000..aeb7c09b09
--- /dev/null
+++ b/actionpack/test/template/ajax_test.rb
@@ -0,0 +1,114 @@
+require "abstract_unit"
+
+class AjaxTestCase < ActiveSupport::TestCase
+ include ActionView::Helpers::AjaxHelper
+ include ActionView::Helpers::TagHelper
+
+ def assert_html(html, matches)
+ matches.each do |match|
+ assert_match(Regexp.new(Regexp.escape(match)), html)
+ end
+ end
+
+ def self.assert_callbacks_work(&blk)
+ define_method(:assert_callbacks_work, &blk)
+
+ [:complete, :failure, :success, :interactive, :loaded, :loading, 404].each do |callback|
+ test "#{callback} callback" do
+ markup = assert_callbacks_work(callback)
+ assert_html markup, %W(data-#{callback}-code="undoRequestCompleted\(request\)")
+ end
+ end
+ end
+end
+
+class LinkToRemoteTest < AjaxTestCase
+ def url_for(hash)
+ "/blog/destroy/4"
+ end
+
+ def link(options = {})
+ link_to_remote("Delete this post", "/blog/destroy/3", options)
+ end
+
+ test "with no update" do
+ assert_html link, %w(href="/blog/destroy/4" Delete\ this\ post data-remote="true")
+ end
+
+ test "basic" do
+ assert_html link(:update => "#posts"),
+ %w(data-update-success="#posts")
+ end
+
+ test "using a url hash" do
+ link = link_to_remote("Delete this post", {:controller => :blog}, :update => "#posts")
+ assert_html link, %w(href="/blog/destroy/4" data-update-success="#posts")
+ end
+
+ test "with :html options" do
+ expected = %{<a href="/blog/destroy/4" data-custom="me" data-remote="true" data-update-success="#posts">Delete this post</a>}
+ assert_equal expected, link(:update => "#posts", :html => {"data-custom" => "me"})
+ end
+
+ test "with a hash for :update" do
+ link = link(:update => {:success => "#posts", :failure => "#error"})
+ assert_match(/data-update-success="#posts"/, link)
+ assert_match(/data-update-failure="#error"/, link)
+ end
+
+ test "with positional parameters" do
+ link = link(:position => :top, :update => "#posts")
+ assert_match(/data\-update\-position="top"/, link)
+ end
+
+ test "with an optional method" do
+ link = link(:method => "delete")
+ assert_match(/data-method="delete"/, link)
+ end
+
+ class LegacyLinkToRemoteTest < AjaxTestCase
+ include ActionView::Helpers::AjaxHelper::Rails2Compatibility
+
+ def link(options)
+ link_to_remote("Delete this post", "/blog/destroy/3", options)
+ end
+
+ test "basic link_to_remote with :url =>" do
+ expected = %{<a href="/blog/destroy/3" data-remote="true" data-update-success="#posts">Delete this post</a>}
+ assert_equal expected,
+ link_to_remote("Delete this post", :url => "/blog/destroy/3", :update => "#posts")
+ end
+
+ assert_callbacks_work do |callback|
+ link(callback => "undoRequestCompleted(request)")
+ end
+ end
+end
+
+class ButtonToRemoteTest < AjaxTestCase
+ def button(options, html = {})
+ button_to_remote("Remote outpost", options, html)
+ end
+
+ def url_for(*)
+ "/whatnot"
+ end
+
+ class StandardTest < ButtonToRemoteTest
+ test "basic" do
+ button = button({:url => {:action => "whatnot"}}, {:class => "fine"})
+ [/input/, /class="fine"/, /type="button"/, /value="Remote outpost"/,
+ /data-url="\/whatnot"/].each do |match|
+ assert_match(match, button)
+ end
+ end
+ end
+
+ class LegacyButtonToRemoteTest < ButtonToRemoteTest
+ include ActionView::Helpers::AjaxHelper::Rails2Compatibility
+
+ assert_callbacks_work do |callback|
+ button(callback => "undoRequestCompleted(request)")
+ end
+ end
+end
diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb
index 147d3dc05d..0c5c5d17ee 100644
--- a/actionpack/test/template/form_helper_test.rb
+++ b/actionpack/test/template/form_helper_test.rb
@@ -1232,7 +1232,7 @@ class FormHelperTest < ActionView::TestCase
# Perhaps this test should be moved to prototype helper tests.
def test_remote_form_for_with_labelled_builder
- self.extend ActionView::Helpers::AjaxHelper
+ self.extend ActionView::Helpers::PrototypeHelper
remote_form_for(:post, @post, :builder => LabelledFormBuilder) do |f|
concat f.text_field(:title)
@@ -1241,7 +1241,7 @@ class FormHelperTest < ActionView::TestCase
end
expected =
- %(<form action="http://www.example.com" data-remote="true" method="post">) +
+ %(<form action="http://www.example.com" onsubmit="new Ajax.Request('http://www.example.com', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" method="post">) +
"<label for='title'>Title:</label> <input name='post[title]' size='30' type='text' id='post_title' value='Hello World' /><br/>" +
"<label for='body'>Body:</label> <textarea name='post[body]' id='post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea><br/>" +
"<label for='secret'>Secret:</label> <input name='post[secret]' type='hidden' value='0' /><input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' /><br/>" +
@@ -1397,10 +1397,10 @@ class FormHelperTest < ActionView::TestCase
end
def test_remote_form_for_with_html_options_adds_options_to_form_tag
- self.extend ActionView::Helpers::AjaxHelper
+ self.extend ActionView::Helpers::PrototypeHelper
remote_form_for(:post, @post, :html => {:id => 'some_form', :class => 'some_class'}) do |f| end
- expected = "<form action=\"http://www.example.com\" class=\"some_class\" id=\"some_form\" method=\"post\" data-remote=\"true\"></form>"
+ expected = "<form action=\"http://www.example.com\" class=\"some_class\" id=\"some_form\" method=\"post\" onsubmit=\"new Ajax.Request('http://www.example.com', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\"></form>"
assert_dom_equal expected, output_buffer
end
diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb
index c8d929cee8..47462b1237 100644
--- a/actionpack/test/template/form_tag_helper_test.rb
+++ b/actionpack/test/template/form_tag_helper_test.rb
@@ -285,35 +285,35 @@ class FormTagHelperTest < ActionView::TestCase
def test_submit_tag
assert_dom_equal(
- %(<input name='commit' data-disable-with="Saving..." onclick="alert('hello!');" type="submit" value="Save" />),
- submit_tag("Save", :disable_with => "Saving...", :onclick => "alert('hello!');")
+ %(<input name='commit' onclick="if (window.hiddenCommit) { window.hiddenCommit.setAttribute('value', this.value); }else { hiddenCommit = document.createElement('input');hiddenCommit.type = 'hidden';hiddenCommit.value = this.value;hiddenCommit.name = this.name;this.form.appendChild(hiddenCommit); }this.setAttribute('originalValue', this.value);this.disabled = true;this.value='Saving...';alert('hello!');result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit());if (result == false) { this.value = this.getAttribute('originalValue');this.disabled = false; }return result;" type="submit" value="Save" />),
+ submit_tag("Save", :disable_with => "Saving...", :onclick => "alert('hello!')")
)
end
def test_submit_tag_with_no_onclick_options
assert_dom_equal(
- %(<input name='commit' data-disable-with="Saving..." type="submit" value="Save" />),
+ %(<input name='commit' onclick="if (window.hiddenCommit) { window.hiddenCommit.setAttribute('value', this.value); }else { hiddenCommit = document.createElement('input');hiddenCommit.type = 'hidden';hiddenCommit.value = this.value;hiddenCommit.name = this.name;this.form.appendChild(hiddenCommit); }this.setAttribute('originalValue', this.value);this.disabled = true;this.value='Saving...';result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit());if (result == false) { this.value = this.getAttribute('originalValue');this.disabled = false; }return result;" type="submit" value="Save" />),
submit_tag("Save", :disable_with => "Saving...")
)
end
def test_submit_tag_with_confirmation
assert_dom_equal(
- %(<input name='commit' type='submit' value='Save' data-confirm="Are you sure?"/>),
+ %(<input name='commit' type='submit' value='Save' onclick="if (!confirm('Are you sure?')) return false; return true;"/>),
submit_tag("Save", :confirm => "Are you sure?")
)
end
def test_submit_tag_with_confirmation_and_with_disable_with
assert_dom_equal(
- %(<input name="commit" data-confirm="Are you sure?" data-disable-with="Saving..." type="submit" value="Save" />),
+ %(<input name="commit" onclick="if (!confirm('Are you sure?')) return false; if (window.hiddenCommit) { window.hiddenCommit.setAttribute('value', this.value); }else { hiddenCommit = document.createElement('input');hiddenCommit.type = 'hidden';hiddenCommit.value = this.value;hiddenCommit.name = this.name;this.form.appendChild(hiddenCommit); }this.setAttribute('originalValue', this.value);this.disabled = true;this.value='Saving...';result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit());if (result == false) { this.value = this.getAttribute('originalValue');this.disabled = false; }return result;" type="submit" value="Save" />),
submit_tag("Save", :disable_with => "Saving...", :confirm => "Are you sure?")
)
end
def test_image_submit_tag_with_confirmation
assert_dom_equal(
- %(<input type="image" src="/images/save.gif" data-confirm="Are you sure?"/>),
+ %(<input type="image" src="/images/save.gif" onclick="return confirm('Are you sure?');"/>),
image_submit_tag("save.gif", :confirm => "Are you sure?")
)
end
diff --git a/actionpack/test/template/prototype_helper_test.rb b/actionpack/test/template/prototype_helper_test.rb
index 86f9c231c0..9225153798 100644
--- a/actionpack/test/template/prototype_helper_test.rb
+++ b/actionpack/test/template/prototype_helper_test.rb
@@ -82,6 +82,199 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
super
end
+ def test_link_to_remote
+ assert_dom_equal %(<a class=\"fine\" href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true}); return false;\">Remote outauthor</a>),
+ link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }}, { :class => "fine" })
+ assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onComplete:function(request){alert(request.responseText)}}); return false;\">Remote outauthor</a>),
+ link_to_remote("Remote outauthor", :complete => "alert(request.responseText)", :url => { :action => "whatnot" })
+ assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onSuccess:function(request){alert(request.responseText)}}); return false;\">Remote outauthor</a>),
+ link_to_remote("Remote outauthor", :success => "alert(request.responseText)", :url => { :action => "whatnot" })
+ assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onFailure:function(request){alert(request.responseText)}}); return false;\">Remote outauthor</a>),
+ link_to_remote("Remote outauthor", :failure => "alert(request.responseText)", :url => { :action => "whatnot" })
+ assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot?a=10&amp;b=20', {asynchronous:true, evalScripts:true, onFailure:function(request){alert(request.responseText)}}); return false;\">Remote outauthor</a>),
+ link_to_remote("Remote outauthor", :failure => "alert(request.responseText)", :url => { :action => "whatnot", :a => '10', :b => '20' })
+ assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:false, evalScripts:true}); return false;\">Remote outauthor</a>),
+ link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :type => :synchronous)
+ assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, insertion:'bottom'}); return false;\">Remote outauthor</a>),
+ link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :position => :bottom)
+ end
+
+ def test_link_to_remote_html_options
+ assert_dom_equal %(<a class=\"fine\" href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true}); return false;\">Remote outauthor</a>),
+ link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }, :html => { :class => "fine" } })
+ end
+
+ def test_link_to_remote_url_quote_escaping
+ assert_dom_equal %(<a href="#" onclick="new Ajax.Request('http://www.example.com/whatnot\\\'s', {asynchronous:true, evalScripts:true}); return false;">Remote</a>),
+ link_to_remote("Remote", { :url => { :action => "whatnot's" } })
+ end
+
+ def test_button_to_remote
+ assert_dom_equal %(<input class=\"fine\" type=\"button\" value=\"Remote outpost\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true});\" />),
+ button_to_remote("Remote outpost", { :url => { :action => "whatnot" }}, { :class => "fine" })
+ assert_dom_equal %(<input type=\"button\" value=\"Remote outpost\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onComplete:function(request){alert(request.reponseText)}});\" />),
+ button_to_remote("Remote outpost", :complete => "alert(request.reponseText)", :url => { :action => "whatnot" })
+ assert_dom_equal %(<input type=\"button\" value=\"Remote outpost\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onSuccess:function(request){alert(request.reponseText)}});\" />),
+ button_to_remote("Remote outpost", :success => "alert(request.reponseText)", :url => { :action => "whatnot" })
+ assert_dom_equal %(<input type=\"button\" value=\"Remote outpost\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onFailure:function(request){alert(request.reponseText)}});\" />),
+ button_to_remote("Remote outpost", :failure => "alert(request.reponseText)", :url => { :action => "whatnot" })
+ assert_dom_equal %(<input type=\"button\" value=\"Remote outpost\" onclick=\"new Ajax.Request('http://www.example.com/whatnot?a=10&amp;b=20', {asynchronous:true, evalScripts:true, onFailure:function(request){alert(request.reponseText)}});\" />),
+ button_to_remote("Remote outpost", :failure => "alert(request.reponseText)", :url => { :action => "whatnot", :a => '10', :b => '20' })
+ end
+
+ def test_periodically_call_remote
+ assert_dom_equal %(<script type="text/javascript">\n//<![CDATA[\nnew PeriodicalExecuter(function() {new Ajax.Updater('schremser_bier', 'http://www.example.com/mehr_bier', {asynchronous:true, evalScripts:true})}, 10)\n//]]>\n</script>),
+ periodically_call_remote(:update => "schremser_bier", :url => { :action => "mehr_bier" })
+ end
+
+ def test_periodically_call_remote_with_frequency
+ assert_dom_equal(
+ "<script type=\"text/javascript\">\n//<![CDATA[\nnew PeriodicalExecuter(function() {new Ajax.Request('http://www.example.com/', {asynchronous:true, evalScripts:true})}, 2)\n//]]>\n</script>",
+ periodically_call_remote(:frequency => 2)
+ )
+ end
+
+ def test_form_remote_tag
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\">),
+ form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast })
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater({success:'glass_of_beer'}, 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\">),
+ form_remote_tag(:update => { :success => "glass_of_beer" }, :url => { :action => :fast })
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater({failure:'glass_of_water'}, 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\">),
+ form_remote_tag(:update => { :failure => "glass_of_water" }, :url => { :action => :fast })
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater({success:'glass_of_beer',failure:'glass_of_water'}, 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\">),
+ form_remote_tag(:update => { :success => 'glass_of_beer', :failure => "glass_of_water" }, :url => { :action => :fast })
+ end
+
+ def test_form_remote_tag_with_method
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\"><div style='margin:0;padding:0;display:inline'><input name='_method' type='hidden' value='put' /></div>),
+ form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, :html => { :method => :put })
+ end
+
+ def test_form_remote_tag_with_block_in_erb
+ __in_erb_template = ''
+ form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) { concat "Hello world!" }
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\">Hello world!</form>), output_buffer
+ end
+
+ def test_remote_form_for_with_record_identification_with_new_record
+ remote_form_for(@record, {:html => { :id => 'create-author' }}) {}
+
+ expected = %(<form action='#{authors_path}' onsubmit="new Ajax.Request('#{authors_path}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='new_author' id='create-author' method='post'></form>)
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_remote_form_for_with_record_identification_without_html_options
+ remote_form_for(@record) {}
+
+ expected = %(<form action='#{authors_path}' onsubmit="new Ajax.Request('#{authors_path}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='new_author' method='post' id='new_author'></form>)
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_remote_form_for_with_record_identification_with_existing_record
+ @record.save
+ remote_form_for(@record) {}
+
+ expected = %(<form action='#{author_path(@record)}' id='edit_author_1' method='post' onsubmit="new Ajax.Request('#{author_path(@record)}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='edit_author'><div style='margin:0;padding:0;display:inline'><input name='_method' type='hidden' value='put' /></div></form>)
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_remote_form_for_with_new_object_in_list
+ remote_form_for([@author, @article]) {}
+
+ expected = %(<form action='#{author_articles_path(@author)}' onsubmit="new Ajax.Request('#{author_articles_path(@author)}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='new_article' method='post' id='new_article'></form>)
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_remote_form_for_with_existing_object_in_list
+ @author.save
+ @article.save
+ remote_form_for([@author, @article]) {}
+
+ expected = %(<form action='#{author_article_path(@author, @article)}' id='edit_article_1' method='post' onsubmit="new Ajax.Request('#{author_article_path(@author, @article)}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='edit_article'><div style='margin:0;padding:0;display:inline'><input name='_method' type='hidden' value='put' /></div></form>)
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_on_callbacks
+ callbacks = [:uninitialized, :loading, :loaded, :interactive, :complete, :success, :failure]
+ callbacks.each do |callback|
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on#{callback.to_s.capitalize}:function(request){monkeys();}, parameters:Form.serialize(this)}); return false;">),
+ form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();")
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater({success:'glass_of_beer'}, 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on#{callback.to_s.capitalize}:function(request){monkeys();}, parameters:Form.serialize(this)}); return false;">),
+ form_remote_tag(:update => { :success => "glass_of_beer" }, :url => { :action => :fast }, callback=>"monkeys();")
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater({failure:'glass_of_beer'}, 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on#{callback.to_s.capitalize}:function(request){monkeys();}, parameters:Form.serialize(this)}); return false;">),
+ form_remote_tag(:update => { :failure => "glass_of_beer" }, :url => { :action => :fast }, callback=>"monkeys();")
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater({success:'glass_of_beer',failure:'glass_of_water'}, 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on#{callback.to_s.capitalize}:function(request){monkeys();}, parameters:Form.serialize(this)}); return false;">),
+ form_remote_tag(:update => { :success => "glass_of_beer", :failure => "glass_of_water" }, :url => { :action => :fast }, callback=>"monkeys();")
+ end
+
+ #HTTP status codes 200 up to 599 have callbacks
+ #these should work
+ 100.upto(599) do |callback|
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on#{callback.to_s.capitalize}:function(request){monkeys();}, parameters:Form.serialize(this)}); return false;">),
+ form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();")
+ end
+
+ #test 200 and 404
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on200:function(request){monkeys();}, on404:function(request){bananas();}, parameters:Form.serialize(this)}); return false;">),
+ form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, 200=>"monkeys();", 404=>"bananas();")
+
+ #these shouldn't
+ 1.upto(99) do |callback|
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;">),
+ form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();")
+ end
+ 600.upto(999) do |callback|
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;">),
+ form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();")
+ end
+
+ #test ultimate combo
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on200:function(request){monkeys();}, on404:function(request){bananas();}, onComplete:function(request){c();}, onFailure:function(request){f();}, onLoading:function(request){c1()}, onSuccess:function(request){s()}, parameters:Form.serialize(this)}); return false;\">),
+ form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, :loading => "c1()", :success => "s()", :failure => "f();", :complete => "c();", 200=>"monkeys();", 404=>"bananas();")
+
+ end
+
+ def test_submit_to_remote
+ assert_dom_equal %(<input name=\"More beer!\" onclick=\"new Ajax.Updater('empty_bottle', 'http://www.example.com/', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this.form)});\" type=\"button\" value=\"1000000\" />),
+ submit_to_remote("More beer!", 1_000_000, :update => "empty_bottle")
+ end
+
+ def test_observe_field
+ assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {new Ajax.Request('http://www.example.com/reorder_if_empty', {asynchronous:true, evalScripts:true, parameters:value})})\n//]]>\n</script>),
+ observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" })
+ end
+
+ def test_observe_field_using_with_option
+ expected = %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {new Ajax.Request('http://www.example.com/check_value', {asynchronous:true, evalScripts:true, parameters:'id=' + encodeURIComponent(value)})})\n//]]>\n</script>)
+ assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => 'id')
+ assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "'id=' + encodeURIComponent(value)")
+ end
+
+ def test_observe_field_using_json_in_with_option
+ expected = %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {new Ajax.Request('http://www.example.com/check_value', {asynchronous:true, evalScripts:true, parameters:{'id':value}})})\n//]]>\n</script>)
+ assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "{'id':value}")
+ end
+
+ def test_observe_field_using_function_for_callback
+ assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {alert('Element changed')})\n//]]>\n</script>),
+ observe_field("glass", :frequency => 5.minutes, :function => "alert('Element changed')")
+ end
+
+ def test_observe_form
+ assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Observer('cart', 2, function(element, value) {new Ajax.Request('http://www.example.com/cart_changed', {asynchronous:true, evalScripts:true, parameters:value})})\n//]]>\n</script>),
+ observe_form("cart", :frequency => 2, :url => { :action => "cart_changed" })
+ end
+
+ def test_observe_form_using_function_for_callback
+ assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Observer('cart', 2, function(element, value) {alert('Form changed')})\n//]]>\n</script>),
+ observe_form("cart", :frequency => 2, :function => "alert('Form changed')")
+ end
+
+ def test_observe_field_without_frequency
+ assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.EventObserver('glass', function(element, value) {new Ajax.Request('http://www.example.com/', {asynchronous:true, evalScripts:true, parameters:value})})\n//]]>\n</script>),
+ observe_field("glass")
+ end
+
def test_update_page
old_output_buffer = output_buffer
diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb
index 984240d46f..dd28aec786 100644
--- a/actionpack/test/template/url_helper_test.rb
+++ b/actionpack/test/template/url_helper_test.rb
@@ -76,7 +76,7 @@ class UrlHelperTest < ActionView::TestCase
def test_button_to_with_javascript_confirm
assert_dom_equal(
- "<form method=\"post\" action=\"http://www.example.com\" class=\"button-to\"><div><input data-confirm=\"Are you sure?\" type=\"submit\" value=\"Hello\" /></div></form>",
+ "<form method=\"post\" action=\"http://www.example.com\" class=\"button-to\"><div><input onclick=\"return confirm('Are you sure?');\" type=\"submit\" value=\"Hello\" /></div></form>",
button_to("Hello", "http://www.example.com", :confirm => "Are you sure?")
)
end
@@ -170,50 +170,50 @@ class UrlHelperTest < ActionView::TestCase
def test_link_tag_with_javascript_confirm
assert_dom_equal(
- "<a href=\"http://www.example.com\" data-confirm=\"Are you sure?\">Hello</a>",
+ "<a href=\"http://www.example.com\" onclick=\"return confirm('Are you sure?');\">Hello</a>",
link_to("Hello", "http://www.example.com", :confirm => "Are you sure?")
)
assert_dom_equal(
- "<a href=\"http://www.example.com\" data-confirm=\"You can\'t possibly be sure, can you?\">Hello</a>",
+ "<a href=\"http://www.example.com\" onclick=\"return confirm('You can\\'t possibly be sure, can you?');\">Hello</a>",
link_to("Hello", "http://www.example.com", :confirm => "You can't possibly be sure, can you?")
)
assert_dom_equal(
- "<a href=\"http://www.example.com\" data-confirm=\"You can\'t possibly be sure,\n can you?\">Hello</a>",
+ "<a href=\"http://www.example.com\" onclick=\"return confirm('You can\\'t possibly be sure,\\n can you?');\">Hello</a>",
link_to("Hello", "http://www.example.com", :confirm => "You can't possibly be sure,\n can you?")
)
end
def test_link_tag_using_post_javascript
assert_dom_equal(
- "<a href='http://www.example.com' data-url='http://www.example.com' data-method=\"post\">Hello</a>",
+ "<a href='http://www.example.com' onclick=\"var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;f.submit();return false;\">Hello</a>",
link_to("Hello", "http://www.example.com", :method => :post)
)
end
def test_link_tag_using_delete_javascript
assert_dom_equal(
- "<a href='http://www.example.com' data-url='http://www.example.com' rel=\"nofollow\" data-method=\"delete\">Destroy</a>",
+ "<a href='http://www.example.com' onclick=\"var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;var m = document.createElement('input'); m.setAttribute('type', 'hidden'); m.setAttribute('name', '_method'); m.setAttribute('value', 'delete'); f.appendChild(m);f.submit();return false;\">Destroy</a>",
link_to("Destroy", "http://www.example.com", :method => :delete)
)
end
def test_link_tag_using_delete_javascript_and_href
assert_dom_equal(
- "<a href='\#' data-url='http://www.example.com' rel=\"nofollow\" data-method=\"delete\">Destroy</a>",
+ "<a href='\#' onclick=\"var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = 'http://www.example.com';var m = document.createElement('input'); m.setAttribute('type', 'hidden'); m.setAttribute('name', '_method'); m.setAttribute('value', 'delete'); f.appendChild(m);f.submit();return false;\">Destroy</a>",
link_to("Destroy", "http://www.example.com", :method => :delete, :href => '#')
)
end
def test_link_tag_using_post_javascript_and_confirm
assert_dom_equal(
- "<a href=\"http://www.example.com\" data-url='http://www.example.com' data-method=\"post\" data-confirm=\"Are you serious?\">Hello</a>",
+ "<a href=\"http://www.example.com\" onclick=\"if (confirm('Are you serious?')) { var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;f.submit(); };return false;\">Hello</a>",
link_to("Hello", "http://www.example.com", :method => :post, :confirm => "Are you serious?")
)
end
def test_link_tag_using_delete_javascript_and_href_and_confirm
assert_dom_equal(
- "<a href=\"#\" data-url='http://www.example.com' rel=\"nofollow\" data-method=\"delete\" data-confirm=\"Are you serious?\">Destroy</a>",
+ "<a href='\#' onclick=\"if (confirm('Are you serious?')) { var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = 'http://www.example.com';var m = document.createElement('input'); m.setAttribute('type', 'hidden'); m.setAttribute('name', '_method'); m.setAttribute('value', 'delete'); f.appendChild(m);f.submit(); };return false;\">Destroy</a>",
link_to("Destroy", "http://www.example.com", :method => :delete, :href => '#', :confirm => "Are you serious?"),
"When specifying url, form should be generated with it, but not this.href"
)
diff --git a/railties/lib/generators/rails/app/templates/public/javascripts/jquery-1.4.1.min.js b/railties/lib/generators/rails/app/templates/public/javascripts/jquery-1.4.1.min.js
deleted file mode 100644
index 0c7294c90a..0000000000
--- a/railties/lib/generators/rails/app/templates/public/javascripts/jquery-1.4.1.min.js
+++ /dev/null
@@ -1,152 +0,0 @@
-/*!
- * jQuery JavaScript Library v1.4.1
- * http://jquery.com/
- *
- * Copyright 2010, John Resig
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * Includes Sizzle.js
- * http://sizzlejs.com/
- * Copyright 2010, The Dojo Foundation
- * Released under the MIT, BSD, and GPL Licenses.
- *
- * Date: Mon Jan 25 19:43:33 2010 -0500
- */
-(function(z,v){function la(){if(!c.isReady){try{r.documentElement.doScroll("left")}catch(a){setTimeout(la,1);return}c.ready()}}function Ma(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,i){var j=a.length;if(typeof b==="object"){for(var n in b)X(a,n,b[n],f,e,d);return a}if(d!==v){f=!i&&f&&c.isFunction(d);for(n=0;n<j;n++)e(a[n],b,f?d.call(a[n],n,e(a[n],b)):d,i);return a}return j?
-e(a[0],b):null}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function ma(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function na(a){var b,d=[],f=[],e=arguments,i,j,n,o,m,s,x=c.extend({},c.data(this,"events").live);if(!(a.button&&a.type==="click")){for(o in x){j=x[o];if(j.live===a.type||j.altLive&&c.inArray(a.type,j.altLive)>-1){i=j.data;i.beforeFilter&&i.beforeFilter[a.type]&&!i.beforeFilter[a.type](a)||f.push(j.selector)}else delete x[o]}i=c(a.target).closest(f,
-a.currentTarget);m=0;for(s=i.length;m<s;m++)for(o in x){j=x[o];n=i[m].elem;f=null;if(i[m].selector===j.selector){if(j.live==="mouseenter"||j.live==="mouseleave")f=c(a.relatedTarget).closest(j.selector)[0];if(!f||f!==n)d.push({elem:n,fn:j})}}m=0;for(s=d.length;m<s;m++){i=d[m];a.currentTarget=i.elem;a.data=i.fn.data;if(i.fn.apply(i.elem,e)===false){b=false;break}}return b}}function oa(a,b){return"live."+(a?a+".":"")+b.replace(/\./g,"`").replace(/ /g,"&")}function pa(a){return!a||!a.parentNode||a.parentNode.nodeType===
-11}function qa(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var i in f)for(var j in f[i])c.event.add(this,i,f[i][j],f[i][j].data)}}})}function ra(a,b,d){var f,e,i;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&a[0].indexOf("<option")<0&&(c.support.checkClone||!sa.test(a[0]))){e=true;if(i=c.fragments[a[0]])if(i!==1)f=i}if(!f){b=b&&b[0]?b[0].ownerDocument||b[0]:r;f=b.createDocumentFragment();
-c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=i?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(ta.concat.apply([],ta.slice(0,b)),function(){d[this]=a});return d}function ua(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Na=z.jQuery,Oa=z.$,r=z.document,S,Pa=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Qa=/^.[^:#\[\.,]*$/,Ra=/\S/,Sa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Ta=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,O=navigator.userAgent,
-va=false,P=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,Q=Array.prototype.slice,wa=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(typeof a==="string")if((d=Pa.exec(a))&&(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:r;if(a=Ta.exec(a))if(c.isPlainObject(b)){a=[r.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=ra([d[1]],
-[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}}else{if(b=r.getElementById(d[2])){if(b.id!==d[2])return S.find(a);this.length=1;this[0]=b}this.context=r;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=r;a=r.getElementsByTagName(a)}else return!b||b.jquery?(b||S).find(a):c(b).find(a);else if(c.isFunction(a))return S.ready(a);if(a.selector!==v){this.selector=a.selector;this.context=a.context}return c.isArray(a)?this.setArray(a):c.makeArray(a,
-this)},selector:"",jquery:"1.4.1",length:0,size:function(){return this.length},toArray:function(){return Q.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){a=c(a||null);a.prevObject=this;a.context=this.context;if(b==="find")a.selector=this.selector+(this.selector?" ":"")+d;else if(b)a.selector=this.selector+"."+b+"("+d+")";return a},setArray:function(a){this.length=0;ba.apply(this,a);return this},each:function(a,b){return c.each(this,
-a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(r,c);else P&&P.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(Q.apply(this,arguments),"slice",Q.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};
-c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,i,j,n;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(i in e){j=a[i];n=e[i];if(a!==n)if(f&&n&&(c.isPlainObject(n)||c.isArray(n))){j=j&&(c.isPlainObject(j)||c.isArray(j))?j:c.isArray(n)?[]:{};a[i]=c.extend(f,j,n)}else if(n!==v)a[i]=n}return a};c.extend({noConflict:function(a){z.$=
-Oa;if(a)z.jQuery=Na;return c},isReady:false,ready:function(){if(!c.isReady){if(!r.body)return setTimeout(c.ready,13);c.isReady=true;if(P){for(var a,b=0;a=P[b++];)a.call(r,c);P=null}c.fn.triggerHandler&&c(r).triggerHandler("ready")}},bindReady:function(){if(!va){va=true;if(r.readyState==="complete")return c.ready();if(r.addEventListener){r.addEventListener("DOMContentLoaded",L,false);z.addEventListener("load",c.ready,false)}else if(r.attachEvent){r.attachEvent("onreadystatechange",L);z.attachEvent("onload",
-c.ready);var a=false;try{a=z.frameElement==null}catch(b){}r.documentElement.doScroll&&a&&la()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype,"isPrototypeOf"))return false;var b;for(b in a);return b===v||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;
-return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return z.JSON&&z.JSON.parse?z.JSON.parse(a):(new Function("return "+a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Ra.test(a)){var b=r.getElementsByTagName("head")[0]||
-r.documentElement,d=r.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(r.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,i=a.length,j=i===v||c.isFunction(a);if(d)if(j)for(f in a){if(b.apply(a[f],d)===false)break}else for(;e<i;){if(b.apply(a[e++],d)===false)break}else if(j)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=
-a[0];e<i&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Sa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]===a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==
-v;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,i=a.length;e<i;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,i=0,j=a.length;i<j;i++){e=b(a[i],i,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=v}else if(b&&!c.isFunction(b)){d=b;b=v}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},
-uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});O=c.uaMatch(O);if(O.browser){c.browser[O.browser]=true;c.browser.version=O.version}if(c.browser.webkit)c.browser.safari=true;if(wa)c.inArray=function(a,b){return wa.call(b,a)};S=c(r);if(r.addEventListener)L=function(){r.removeEventListener("DOMContentLoaded",
-L,false);c.ready()};else if(r.attachEvent)L=function(){if(r.readyState==="complete"){r.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=r.documentElement,b=r.createElement("script"),d=r.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";var e=d.getElementsByTagName("*"),i=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!i)){c.support=
-{leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(i.getAttribute("style")),hrefNormalized:i.getAttribute("href")==="/a",opacity:/^0.55$/.test(i.style.opacity),cssFloat:!!i.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:r.createElement("select").appendChild(r.createElement("option")).selected,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};
-b.type="text/javascript";try{b.appendChild(r.createTextNode("window."+f+"=1;"))}catch(j){}a.insertBefore(b,a.firstChild);if(z[f]){c.support.scriptEval=true;delete z[f]}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function n(){c.support.noCloneEvent=false;d.detachEvent("onclick",n)});d.cloneNode(true).fireEvent("onclick")}d=r.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=r.createDocumentFragment();a.appendChild(d.firstChild);
-c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var n=r.createElement("div");n.style.width=n.style.paddingLeft="1px";r.body.appendChild(n);c.boxModel=c.support.boxModel=n.offsetWidth===2;r.body.removeChild(n).style.display="none"});a=function(n){var o=r.createElement("div");n="on"+n;var m=n in o;if(!m){o.setAttribute(n,"return;");m=typeof o[n]==="function"}return m};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=i=null}})();c.props=
-{"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ua=0,xa={},Va={};c.extend({cache:{},expando:G,noData:{embed:true,object:true,applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==z?xa:a;var f=a[G],e=c.cache;if(!b&&!f)return null;f||(f=++Ua);if(typeof b==="object"){a[G]=f;e=e[f]=c.extend(true,
-{},b)}else e=e[f]?e[f]:typeof d==="undefined"?Va:(e[f]={});if(d!==v){a[G]=f;e[b]=d}return typeof b==="string"?e[b]:e}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==z?xa:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{try{delete a[G]}catch(i){a.removeAttribute&&a.removeAttribute(G)}delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,
-a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===v){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===v&&this.length)f=c.data(this[0],a);return f===v&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);
-return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===v)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||
-a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var ya=/[\n\t]/g,ca=/\s+/,Wa=/\r/g,Xa=/href|src|style/,Ya=/(button|input)/i,Za=/(button|input|object|select|textarea)/i,$a=/^(a|area)$/i,za=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(o){var m=
-c(this);m.addClass(a.call(this,o,m.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className)for(var i=" "+e.className+" ",j=0,n=b.length;j<n;j++){if(i.indexOf(" "+b[j]+" ")<0)e.className+=" "+b[j]}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(o){var m=c(this);m.removeClass(a.call(this,o,m.attr("class")))});if(a&&typeof a==="string"||a===v)for(var b=(a||"").split(ca),
-d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var i=(" "+e.className+" ").replace(ya," "),j=0,n=b.length;j<n;j++)i=i.replace(" "+b[j]+" "," ");e.className=i.substring(1,i.length-1)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var i=c(this);i.toggleClass(a.call(this,e,i.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,i=0,j=c(this),n=b,o=
-a.split(ca);e=o[i++];){n=f?n:!j.hasClass(e);j[n?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(ya," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===v){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||
-{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var i=b?d:0;for(d=b?d+1:e.length;i<d;i++){var j=e[i];if(j.selected){a=c(j).val();if(b)return a;f.push(a)}}return f}if(za.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Wa,"")}return v}var n=c.isFunction(a);return this.each(function(o){var m=c(this),s=a;if(this.nodeType===1){if(n)s=a.call(this,o,m.val());
-if(typeof s==="number")s+="";if(c.isArray(s)&&za.test(this.type))this.checked=c.inArray(m.val(),s)>=0;else if(c.nodeName(this,"select")){var x=c.makeArray(s);c("option",this).each(function(){this.selected=c.inArray(c(this).val(),x)>=0});if(!x.length)this.selectedIndex=-1}else this.value=s}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return v;if(f&&b in c.attrFn)return c(a)[b](d);
-f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==v;b=f&&c.props[b]||b;if(a.nodeType===1){var i=Xa.test(b);if(b in a&&f&&!i){if(e){b==="type"&&Ya.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:Za.test(a.nodeName)||$a.test(a.nodeName)&&a.href?0:v;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=
-""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&i?a.getAttribute(b,2):a.getAttribute(b);return a===null?v:a}return c.style(a,b,d)}});var ab=function(a){return a.replace(/[^\w\s\.\|`]/g,function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==z&&!a.frameElement)a=z;if(!d.guid)d.guid=c.guid++;if(f!==v){d=c.proxy(d);d.data=f}var e=c.data(a,"events")||c.data(a,"events",{}),i=c.data(a,"handle"),j;if(!i){j=
-function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(j.elem,arguments):v};i=c.data(a,"handle",j)}if(i){i.elem=a;b=b.split(/\s+/);for(var n,o=0;n=b[o++];){var m=n.split(".");n=m.shift();if(o>1){d=c.proxy(d);if(f!==v)d.data=f}d.type=m.slice(0).sort().join(".");var s=e[n],x=this.special[n]||{};if(!s){s=e[n]={};if(!x.setup||x.setup.call(a,f,m,d)===false)if(a.addEventListener)a.addEventListener(n,i,false);else a.attachEvent&&a.attachEvent("on"+n,i)}if(x.add)if((m=x.add.call(a,
-d,f,m,s))&&c.isFunction(m)){m.guid=m.guid||d.guid;m.data=m.data||d.data;m.type=m.type||d.type;d=m}s[d.guid]=d;this.global[n]=true}a=null}}},global:{},remove:function(a,b,d){if(!(a.nodeType===3||a.nodeType===8)){var f=c.data(a,"events"),e,i,j;if(f){if(b===v||typeof b==="string"&&b.charAt(0)===".")for(i in f)this.remove(a,i+(b||""));else{if(b.type){d=b.handler;b=b.type}b=b.split(/\s+/);for(var n=0;i=b[n++];){var o=i.split(".");i=o.shift();var m=!o.length,s=c.map(o.slice(0).sort(),ab);s=new RegExp("(^|\\.)"+
-s.join("\\.(?:.*\\.)?")+"(\\.|$)");var x=this.special[i]||{};if(f[i]){if(d){j=f[i][d.guid];delete f[i][d.guid]}else for(var A in f[i])if(m||s.test(f[i][A].type))delete f[i][A];x.remove&&x.remove.call(a,o,j);for(e in f[i])break;if(!e){if(!x.teardown||x.teardown.call(a,o)===false)if(a.removeEventListener)a.removeEventListener(i,c.data(a,"handle"),false);else a.detachEvent&&a.detachEvent("on"+i,c.data(a,"handle"));e=null;delete f[i]}}}}for(e in f)break;if(!e){if(A=c.data(a,"handle"))A.elem=null;c.removeData(a,
-"events");c.removeData(a,"handle")}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();this.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return v;a.result=v;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,
-b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(i){}if(!a.isPropagationStopped()&&f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){d=a.target;var j;if(!(c.nodeName(d,"a")&&e==="click")&&!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()])){try{if(d[e]){if(j=d["on"+e])d["on"+e]=null;this.triggered=true;d[e]()}}catch(n){}if(j)d["on"+e]=j;this.triggered=false}}},handle:function(a){var b,
-d;a=arguments[0]=c.event.fix(a||z.event);a.currentTarget=this;d=a.type.split(".");a.type=d.shift();b=!d.length&&!a.exclusive;var f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)");d=(c.data(this,"events")||{})[a.type];for(var e in d){var i=d[e];if(b||f.test(i.type)){a.handler=i;a.data=i.data;i=i.apply(this,arguments);if(i!==v){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}return a.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(" "),
-fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||r;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=r.documentElement;d=r.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
-d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==v)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a,b){c.extend(a,b||{});a.guid+=b.selector+b.live;b.liveProxy=a;c.event.add(this,b.live,na,b)},remove:function(a){if(a.length){var b=
-0,d=new RegExp("(^|\\.)"+a[0]+"(\\.|$)");c.each(c.data(this,"events").live||{},function(){d.test(this.type)&&b++});b<1&&c.event.remove(this,a[0],na)}},special:{}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true};
-c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y,isImmediatePropagationStopped:Y};var Aa=function(a){for(var b=
-a.relatedTarget;b&&b!==this;)try{b=b.parentNode}catch(d){break}if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}},Ba=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ba:Aa,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ba:Aa)}}});if(!c.support.submitBubbles)c.event.special.submit={setup:function(a,b,d){if(this.nodeName.toLowerCase()!==
-"form"){c.event.add(this,"click.specialSubmit."+d.guid,function(f){var e=f.target,i=e.type;if((i==="submit"||i==="image")&&c(e).closest("form").length)return ma("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit."+d.guid,function(f){var e=f.target,i=e.type;if((i==="text"||i==="password")&&c(e).closest("form").length&&f.keyCode===13)return ma("submit",this,arguments)})}else return false},remove:function(a,b){c.event.remove(this,"click.specialSubmit"+(b?"."+b.guid:""));c.event.remove(this,
-"keypress.specialSubmit"+(b?"."+b.guid:""))}};if(!c.support.changeBubbles){var da=/textarea|input|select/i;function Ca(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d}function ea(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Ca(d);if(a.type!=="focusout"||
-d.type!=="radio")c.data(d,"_change_data",e);if(!(f===v||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}}c.event.special.change={filters:{focusout:ea,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return ea.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return ea.call(this,a)},beforeactivate:function(a){a=
-a.target;a.nodeName.toLowerCase()==="input"&&a.type==="radio"&&c.data(a,"_change_data",Ca(a))}},setup:function(a,b,d){for(var f in T)c.event.add(this,f+".specialChange."+d.guid,T[f]);return da.test(this.nodeName)},remove:function(a,b){for(var d in T)c.event.remove(this,d+".specialChange"+(b?"."+b.guid:""),T[d]);return da.test(this.nodeName)}};var T=c.event.special.change.filters}r.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,
-f)}c.event.special[b]={setup:function(){this.addEventListener(a,d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var i in d)this[b](i,f,d[i],e);return this}if(c.isFunction(f)){e=f;f=v}var j=b==="one"?c.proxy(e,function(n){c(this).unbind(n,j);return e.apply(this,arguments)}):e;return d==="unload"&&b!=="one"?this.one(d,f,e):this.each(function(){c.event.add(this,d,j,f)})}});c.fn.extend({unbind:function(a,
-b){if(typeof a==="object"&&!a.preventDefault){for(var d in a)this.unbind(d,a[d]);return this}return this.each(function(){c.event.remove(this,a,b)})},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+
-a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e){var i,j=0;if(c.isFunction(f)){e=f;f=v}for(d=(d||"").split(/\s+/);(i=d[j++])!=null;){i=i==="focus"?"focusin":i==="blur"?"focusout":i==="hover"?d.push("mouseleave")&&"mouseenter":i;b==="live"?c(this.context).bind(oa(i,this.selector),{data:f,selector:this.selector,
-live:i},e):c(this.context).unbind(oa(i,this.selector),e?{guid:e.guid+this.selector+i}:null)}return this}});c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});z.attachEvent&&!z.addEventListener&&z.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});
-(function(){function a(g){for(var h="",k,l=0;g[l];l++){k=g[l];if(k.nodeType===3||k.nodeType===4)h+=k.nodeValue;else if(k.nodeType!==8)h+=a(k.childNodes)}return h}function b(g,h,k,l,q,p){q=0;for(var u=l.length;q<u;q++){var t=l[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===k){y=l[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=k;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}l[q]=y}}}function d(g,h,k,l,q,p){q=0;for(var u=l.length;q<u;q++){var t=l[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===
-k){y=l[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=k;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(o.filter(h,[t]).length>0){y=t;break}}t=t[g]}l[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,i=Object.prototype.toString,j=false,n=true;[0,0].sort(function(){n=false;return 0});var o=function(g,h,k,l){k=k||[];var q=h=h||r;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||
-typeof g!=="string")return k;for(var p=[],u,t,y,R,H=true,M=w(h),I=g;(f.exec(""),u=f.exec(I))!==null;){I=u[3];p.push(u[1]);if(u[2]){R=u[3];break}}if(p.length>1&&s.exec(g))if(p.length===2&&m.relative[p[0]])t=fa(p[0]+p[1],h);else for(t=m.relative[p[0]]?[h]:o(p.shift(),h);p.length;){g=p.shift();if(m.relative[g])g+=p.shift();t=fa(g,t)}else{if(!l&&p.length>1&&h.nodeType===9&&!M&&m.match.ID.test(p[0])&&!m.match.ID.test(p[p.length-1])){u=o.find(p.shift(),h,M);h=u.expr?o.filter(u.expr,u.set)[0]:u.set[0]}if(h){u=
-l?{expr:p.pop(),set:A(l)}:o.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=u.expr?o.filter(u.expr,u.set):u.set;if(p.length>0)y=A(t);else H=false;for(;p.length;){var D=p.pop();u=D;if(m.relative[D])u=p.pop();else D="";if(u==null)u=h;m.relative[D](y,u,M)}}else y=[]}y||(y=t);y||o.error(D||g);if(i.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))k.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&
-y[g].nodeType===1&&k.push(t[g]);else k.push.apply(k,y);else A(y,k);if(R){o(R,q,k,l);o.uniqueSort(k)}return k};o.uniqueSort=function(g){if(C){j=n;g.sort(C);if(j)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};o.matches=function(g,h){return o(g,null,null,h)};o.find=function(g,h,k){var l,q;if(!g)return[];for(var p=0,u=m.order.length;p<u;p++){var t=m.order[p];if(q=m.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");l=m.find[t](q,
-h,k);if(l!=null){g=g.replace(m.match[t],"");break}}}}l||(l=h.getElementsByTagName("*"));return{set:l,expr:g}};o.filter=function(g,h,k,l){for(var q=g,p=[],u=h,t,y,R=h&&h[0]&&w(h[0]);g&&h.length;){for(var H in m.filter)if((t=m.leftMatch[H].exec(g))!=null&&t[2]){var M=m.filter[H],I,D;D=t[1];y=false;t.splice(1,1);if(D.substr(D.length-1)!=="\\"){if(u===p)p=[];if(m.preFilter[H])if(t=m.preFilter[H](t,u,k,p,l,R)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=u[U])!=null;U++)if(D){I=M(D,t,U,u);var Da=
-l^!!I;if(k&&I!=null)if(Da)y=true;else u[U]=false;else if(Da){p.push(D);y=true}}if(I!==v){k||(u=p);g=g.replace(m.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)o.error(g);else break;q=g}return u};o.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var m=o.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\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},relative:{"+":function(g,h){var k=typeof h==="string",l=k&&!/\W/.test(h);k=k&&!l;if(l)h=h.toLowerCase();l=0;for(var q=g.length,
-p;l<q;l++)if(p=g[l]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[l]=k||p&&p.nodeName.toLowerCase()===h?p||false:p===h}k&&o.filter(h,g,true)},">":function(g,h){var k=typeof h==="string";if(k&&!/\W/.test(h)){h=h.toLowerCase();for(var l=0,q=g.length;l<q;l++){var p=g[l];if(p){k=p.parentNode;g[l]=k.nodeName.toLowerCase()===h?k:false}}}else{l=0;for(q=g.length;l<q;l++)if(p=g[l])g[l]=k?p.parentNode:p.parentNode===h;k&&o.filter(h,g,true)}},"":function(g,h,k){var l=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=
-h=h.toLowerCase();q=b}q("parentNode",h,l,g,p,k)},"~":function(g,h,k){var l=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,l,g,p,k)}},find:{ID:function(g,h,k){if(typeof h.getElementById!=="undefined"&&!k)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var k=[];h=h.getElementsByName(g[1]);for(var l=0,q=h.length;l<q;l++)h[l].getAttribute("name")===g[1]&&k.push(h[l]);return k.length===0?null:k}},
-TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,k,l,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var u;(u=h[p])!=null;p++)if(u)if(q^(u.className&&(" "+u.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))k||l.push(u);else if(k)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&
-"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,k,l,q,p){h=g[1].replace(/\\/g,"");if(!p&&m.attrMap[h])g[1]=m.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,k,l,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=o(g[3],null,null,h);else{g=o.filter(g[3],h,k,true^q);k||l.push.apply(l,g);return false}else if(m.match.POS.test(g[0])||m.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);
-return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,k){return!!o(k[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===
-g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},setFilters:{first:function(g,h){return h===0},last:function(g,h,k,l){return h===l.length-1},even:function(g,h){return h%2===
-0},odd:function(g,h){return h%2===1},lt:function(g,h,k){return h<k[3]-0},gt:function(g,h,k){return h>k[3]-0},nth:function(g,h,k){return k[3]-0===h},eq:function(g,h,k){return k[3]-0===h}},filter:{PSEUDO:function(g,h,k,l){var q=h[1],p=m.filters[q];if(p)return p(g,k,h,l);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h=h[3];k=0;for(l=h.length;k<l;k++)if(h[k]===g)return false;return true}else o.error("Syntax error, unrecognized expression: "+
-q)},CHILD:function(g,h){var k=h[1],l=g;switch(k){case "only":case "first":for(;l=l.previousSibling;)if(l.nodeType===1)return false;if(k==="first")return true;l=g;case "last":for(;l=l.nextSibling;)if(l.nodeType===1)return false;return true;case "nth":k=h[2];var q=h[3];if(k===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var u=0;for(l=p.firstChild;l;l=l.nextSibling)if(l.nodeType===1)l.nodeIndex=++u;p.sizcache=h}g=g.nodeIndex-q;return k===0?g===0:g%k===0&&g/k>=
-0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var k=h[1];g=m.attrHandle[k]?m.attrHandle[k](g):g[k]!=null?g[k]:g.getAttribute(k);k=g+"";var l=h[2];h=h[4];return g==null?l==="!=":l==="="?k===h:l==="*="?k.indexOf(h)>=0:l==="~="?(" "+k+" ").indexOf(h)>=0:!h?k&&g!==false:l==="!="?k!==h:l==="^="?
-k.indexOf(h)===0:l==="$="?k.substr(k.length-h.length)===h:l==="|="?k===h||k.substr(0,h.length+1)===h+"-":false},POS:function(g,h,k,l){var q=m.setFilters[h[2]];if(q)return q(g,k,h,l)}}},s=m.match.POS;for(var x in m.match){m.match[x]=new RegExp(m.match[x].source+/(?![^\[]*\])(?![^\(]*\))/.source);m.leftMatch[x]=new RegExp(/(^(?:.|\r|\n)*?)/.source+m.match[x].source.replace(/\\(\d+)/g,function(g,h){return"\\"+(h-0+1)}))}var A=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};
-try{Array.prototype.slice.call(r.documentElement.childNodes,0)}catch(B){A=function(g,h){h=h||[];if(i.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var k=0,l=g.length;k<l;k++)h.push(g[k]);else for(k=0;g[k];k++)h.push(g[k]);return h}}var C;if(r.documentElement.compareDocumentPosition)C=function(g,h){if(!g.compareDocumentPosition||!h.compareDocumentPosition){if(g==h)j=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===
-h?0:1;if(g===0)j=true;return g};else if("sourceIndex"in r.documentElement)C=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)j=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)j=true;return g};else if(r.createRange)C=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)j=true;return g.ownerDocument?-1:1}var k=g.ownerDocument.createRange(),l=h.ownerDocument.createRange();k.setStart(g,0);k.setEnd(g,0);l.setStart(h,0);l.setEnd(h,0);g=k.compareBoundaryPoints(Range.START_TO_END,
-l);if(g===0)j=true;return g};(function(){var g=r.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var k=r.documentElement;k.insertBefore(g,k.firstChild);if(r.getElementById(h)){m.find.ID=function(l,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(l[1]))?q.id===l[1]||typeof q.getAttributeNode!=="undefined"&&q.getAttributeNode("id").nodeValue===l[1]?[q]:v:[]};m.filter.ID=function(l,q){var p=typeof l.getAttributeNode!=="undefined"&&l.getAttributeNode("id");
-return l.nodeType===1&&p&&p.nodeValue===q}}k.removeChild(g);k=g=null})();(function(){var g=r.createElement("div");g.appendChild(r.createComment(""));if(g.getElementsByTagName("*").length>0)m.find.TAG=function(h,k){k=k.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var l=0;k[l];l++)k[l].nodeType===1&&h.push(k[l]);k=h}return k};g.innerHTML="<a href='#'></a>";if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")m.attrHandle.href=function(h){return h.getAttribute("href",
-2)};g=null})();r.querySelectorAll&&function(){var g=o,h=r.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){o=function(l,q,p,u){q=q||r;if(!u&&q.nodeType===9&&!w(q))try{return A(q.querySelectorAll(l),p)}catch(t){}return g(l,q,p,u)};for(var k in g)o[k]=g[k];h=null}}();(function(){var g=r.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===
-0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){m.order.splice(1,0,"CLASS");m.find.CLASS=function(h,k,l){if(typeof k.getElementsByClassName!=="undefined"&&!l)return k.getElementsByClassName(h[1])};g=null}}})();var E=r.compareDocumentPosition?function(g,h){return g.compareDocumentPosition(h)&16}:function(g,h){return g!==h&&(g.contains?g.contains(h):true)},w=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},fa=function(g,h){var k=[],
-l="",q;for(h=h.nodeType?[h]:h;q=m.match.PSEUDO.exec(g);){l+=q[0];g=g.replace(m.match.PSEUDO,"")}g=m.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)o(g,h[q],k);return o.filter(l,k)};c.find=o;c.expr=o.selectors;c.expr[":"]=c.expr.filters;c.unique=o.uniqueSort;c.getText=a;c.isXMLDoc=w;c.contains=E})();var bb=/Until$/,cb=/^(?:parents|prevUntil|prevAll)/,db=/,/;Q=Array.prototype.slice;var Ea=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,i){return!!b.call(e,i,e)===d});else if(b.nodeType)return c.grep(a,
-function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Qa.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length;c.find(a,this[f],b);if(f>0)for(var i=d;i<b.length;i++)for(var j=0;j<d;j++)if(b[j]===b[i]){b.splice(i--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=
-0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ea(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ea(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,i={},j;if(f&&a.length){e=0;for(var n=a.length;e<n;e++){j=a[e];i[j]||(i[j]=c.expr.match.POS.test(j)?c(j,b||this.context):j)}for(;f&&f.ownerDocument&&f!==b;){for(j in i){e=i[j];if(e.jquery?e.index(f)>
--1:c(f).is(e)){d.push({selector:j,elem:f});delete i[j]}}f=f.parentNode}}return d}var o=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(m,s){for(;s&&s.ownerDocument&&s!==b;){if(o?o.index(s)>-1:c(s).is(a))return s;s=s.parentNode}return null})},index:function(a){if(!a||typeof a==="string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),
-a);return this.pushStack(pa(a[0])||pa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},
-nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);bb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):
-e;if((this.length>1||db.test(f))&&cb.test(a))e=e.reverse();return this.pushStack(e,a,Q.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===v||a.nodeType!==1||!c(a).is(d));){a.nodeType===1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==
-b&&d.push(a);return d}});var Fa=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ga=/(<([\w:]+)[^>]*?)\/>/g,eb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,Ha=/<([\w:]+)/,fb=/<tbody/i,gb=/<|&\w+;/,sa=/checked\s*(?:[^=]|=\s*.checked.)/i,Ia=function(a,b,d){return eb.test(d)?a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],
-col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==v)return this.empty().append((this[0]&&this[0].ownerDocument||r).createTextNode(a));return c.getText(this)},
-wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?
-d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,
-false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&
-!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Fa,"").replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){qa(this,b);qa(this.find("*"),b.find("*"))}return b},html:function(a){if(a===v)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Fa,""):null;else if(typeof a==="string"&&!/<script/i.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(Ha.exec(a)||
-["",""])[1].toLowerCase()]){a=a.replace(Ga,Ia);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var i=c(this),j=i.html();i.empty().append(function(){return a.call(this,e,j)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this,
-b,f))});else a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(s){return c.nodeName(s,"table")?s.getElementsByTagName("tbody")[0]||s.appendChild(s.ownerDocument.createElement("tbody")):s}var e,i,j=a[0],n=[];if(!c.support.checkClone&&arguments.length===3&&typeof j===
-"string"&&sa.test(j))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(j))return this.each(function(s){var x=c(this);a[0]=j.call(this,s,b?x.html():v);x.domManip(a,b,d)});if(this[0]){e=a[0]&&a[0].parentNode&&a[0].parentNode.nodeType===11?{fragment:a[0].parentNode}:ra(a,this,n);if(i=e.fragment.firstChild){b=b&&c.nodeName(i,"tr");for(var o=0,m=this.length;o<m;o++)d.call(b?f(this[o],i):this[o],e.cacheable||this.length>1||o>0?e.fragment.cloneNode(true):e.fragment)}n&&c.each(n,
-Ma)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);for(var e=0,i=d.length;e<i;e++){var j=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),j);f=f.concat(j)}return this.pushStack(f,a,d.selector)}});c.each({remove:function(a,b){if(!a||c.filter(a,[this]).length){if(!b&&this.nodeType===1){c.cleanData(this.getElementsByTagName("*"));c.cleanData([this])}this.parentNode&&
-this.parentNode.removeChild(this)}},empty:function(){for(this.nodeType===1&&c.cleanData(this.getElementsByTagName("*"));this.firstChild;)this.removeChild(this.firstChild)}},function(a,b){c.fn[a]=function(){return this.each(b,arguments)}});c.extend({clean:function(a,b,d,f){b=b||r;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||r;var e=[];c.each(a,function(i,j){if(typeof j==="number")j+="";if(j){if(typeof j==="string"&&!gb.test(j))j=b.createTextNode(j);else if(typeof j===
-"string"){j=j.replace(Ga,Ia);var n=(Ha.exec(j)||["",""])[1].toLowerCase(),o=F[n]||F._default,m=o[0];i=b.createElement("div");for(i.innerHTML=o[1]+j+o[2];m--;)i=i.lastChild;if(!c.support.tbody){m=fb.test(j);n=n==="table"&&!m?i.firstChild&&i.firstChild.childNodes:o[1]==="<table>"&&!m?i.childNodes:[];for(o=n.length-1;o>=0;--o)c.nodeName(n[o],"tbody")&&!n[o].childNodes.length&&n[o].parentNode.removeChild(n[o])}!c.support.leadingWhitespace&&V.test(j)&&i.insertBefore(b.createTextNode(V.exec(j)[0]),i.firstChild);
-j=c.makeArray(i.childNodes)}if(j.nodeType)e.push(j);else e=c.merge(e,j)}});if(d)for(a=0;e[a];a++)if(f&&c.nodeName(e[a],"script")&&(!e[a].type||e[a].type.toLowerCase()==="text/javascript"))f.push(e[a].parentNode?e[a].parentNode.removeChild(e[a]):e[a]);else{e[a].nodeType===1&&e.splice.apply(e,[a+1,0].concat(c.makeArray(e[a].getElementsByTagName("script"))));d.appendChild(e[a])}return e},cleanData:function(a){for(var b=0,d;(d=a[b])!=null;b++){c.event.remove(d);c.removeData(d)}}});var hb=/z-?index|font-?weight|opacity|zoom|line-?height/i,
-Ja=/alpha\([^)]*\)/,Ka=/opacity=([^)]*)/,ga=/float/i,ha=/-([a-z])/ig,ib=/([A-Z])/g,jb=/^-?\d+(?:px)?$/i,kb=/^-?\d/,lb={position:"absolute",visibility:"hidden",display:"block"},mb=["Left","Right"],nb=["Top","Bottom"],ob=r.defaultView&&r.defaultView.getComputedStyle,La=c.support.cssFloat?"cssFloat":"styleFloat",ia=function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===v)return c.curCSS(d,f);if(typeof e==="number"&&!hb.test(f))e+="px";c.style(d,f,e)})};
-c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return v;if((b==="width"||b==="height")&&parseFloat(d)<0)d=v;var f=a.style||a,e=d!==v;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=Ja.test(a)?a.replace(Ja,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Ka.exec(f.filter)[1])/100+"":""}if(ga.test(b))b=La;b=b.replace(ha,ia);if(e)f[b]=d;return f[b]},css:function(a,
-b,d,f){if(b==="width"||b==="height"){var e,i=b==="width"?mb:nb;function j(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(i,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,"border"+this+"Width",true))||0})}a.offsetWidth!==0?j():c.swap(a,lb,j);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&
-a.currentStyle){f=Ka.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ga.test(b))b=La;if(!d&&e&&e[b])f=e[b];else if(ob){if(ga.test(b))b="float";b=b.replace(ib,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ha,ia);f=a.currentStyle[b]||a.currentStyle[d];if(!jb.test(f)&&kb.test(f)){b=e.left;var i=a.runtimeStyle.left;a.runtimeStyle.left=
-a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=i}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var pb=
-J(),qb=/<script(.|\s)*?\/script>/gi,rb=/select|textarea/i,sb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ja=/\?/,tb=/(\?|&)_=.*?(&|$)/,ub=/^(\w+:)?\/\/([^\/?#]+)/,vb=/%20/g;c.fn.extend({_load:c.fn.load,load:function(a,b,d){if(typeof a!=="string")return this._load(a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=
-c.param(b,c.ajaxSettings.traditional);f="POST"}var i=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(j,n){if(n==="success"||n==="notmodified")i.html(e?c("<div />").append(j.responseText.replace(qb,"")).find(e):j.responseText);d&&i.each(d,[j.responseText,n,j])}});return this},serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&
-(this.checked||rb.test(this.nodeName)||sb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,
-b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:z.XMLHttpRequest&&(z.location.protocol!=="file:"||!z.ActiveXObject)?function(){return new z.XMLHttpRequest}:
-function(){try{return new z.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&&e.success.call(o,n,j,w);e.global&&f("ajaxSuccess",[w,e])}function d(){e.complete&&e.complete.call(o,w,j);e.global&&f("ajaxComplete",[w,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}
-function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),i,j,n,o=a&&a.context||e,m=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(m==="GET")N.test(e.url)||(e.url+=(ja.test(e.url)?"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||
-N.test(e.url))){i=e.jsonpCallback||"jsonp"+pb++;if(e.data)e.data=(e.data+"").replace(N,"="+i+"$1");e.url=e.url.replace(N,"="+i+"$1");e.dataType="script";z[i]=z[i]||function(q){n=q;b();d();z[i]=v;try{delete z[i]}catch(p){}A&&A.removeChild(B)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache===false&&m==="GET"){var s=J(),x=e.url.replace(tb,"$1_="+s+"$2");e.url=x+(x===e.url?(ja.test(e.url)?"&":"?")+"_="+s:"")}if(e.data&&m==="GET")e.url+=(ja.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&
-c.event.trigger("ajaxStart");s=(s=ub.exec(e.url))&&(s[1]&&s[1]!==location.protocol||s[2]!==location.host);if(e.dataType==="script"&&m==="GET"&&s){var A=r.getElementsByTagName("head")[0]||r.documentElement,B=r.createElement("script");B.src=e.url;if(e.scriptCharset)B.charset=e.scriptCharset;if(!i){var C=false;B.onload=B.onreadystatechange=function(){if(!C&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){C=true;b();d();B.onload=B.onreadystatechange=null;A&&B.parentNode&&
-A.removeChild(B)}}}A.insertBefore(B,A.firstChild);return v}var E=false,w=e.xhr();if(w){e.username?w.open(m,e.url,e.async,e.username,e.password):w.open(m,e.url,e.async);try{if(e.data||a&&a.contentType)w.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&w.setRequestHeader("If-Modified-Since",c.lastModified[e.url]);c.etag[e.url]&&w.setRequestHeader("If-None-Match",c.etag[e.url])}s||w.setRequestHeader("X-Requested-With","XMLHttpRequest");w.setRequestHeader("Accept",
-e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(fa){}if(e.beforeSend&&e.beforeSend.call(o,w,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");w.abort();return false}e.global&&f("ajaxSend",[w,e]);var g=w.onreadystatechange=function(q){if(!w||w.readyState===0||q==="abort"){E||d();E=true;if(w)w.onreadystatechange=c.noop}else if(!E&&w&&(w.readyState===4||q==="timeout")){E=true;w.onreadystatechange=c.noop;j=q==="timeout"?"timeout":!c.httpSuccess(w)?
-"error":e.ifModified&&c.httpNotModified(w,e.url)?"notmodified":"success";var p;if(j==="success")try{n=c.httpData(w,e.dataType,e)}catch(u){j="parsererror";p=u}if(j==="success"||j==="notmodified")i||b();else c.handleError(e,w,j,p);d();q==="timeout"&&w.abort();if(e.async)w=null}};try{var h=w.abort;w.abort=function(){w&&h.call(w);g("abort")}}catch(k){}e.async&&e.timeout>0&&setTimeout(function(){w&&!E&&g("timeout")},e.timeout);try{w.send(m==="POST"||m==="PUT"||m==="DELETE"?e.data:null)}catch(l){c.handleError(e,
-w,null,l);d()}e.async||g();return w}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=
-f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b==="json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(j,n){if(c.isArray(n))c.each(n,
-function(o,m){b?f(j,m):d(j+"["+(typeof m==="object"||c.isArray(m)?o:"")+"]",m)});else!b&&n!=null&&typeof n==="object"?c.each(n,function(o,m){d(j+"["+o+"]",m)}):f(j,n)}function f(j,n){n=c.isFunction(n)?n():n;e[e.length]=encodeURIComponent(j)+"="+encodeURIComponent(n)}var e=[];if(b===v)b=c.ajaxSettings.traditional;if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var i in a)d(i,a[i]);return e.join("&").replace(vb,"+")}});var ka={},wb=/toggle|show|hide/,xb=/^([+-]=)?([\d+-.]+)(.*)$/,
-W,ta=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(ka[d])f=ka[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();
-ka[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a],"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&
-c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)},animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var i=c.extend({},e),j,n=this.nodeType===1&&c(this).is(":hidden"),
-o=this;for(j in a){var m=j.replace(ha,ia);if(j!==m){a[m]=a[j];delete a[j];j=m}if(a[j]==="hide"&&n||a[j]==="show"&&!n)return i.complete.call(this);if((j==="height"||j==="width")&&this.style){i.display=c.css(this,"display");i.overflow=this.style.overflow}if(c.isArray(a[j])){(i.specialEasing=i.specialEasing||{})[j]=a[j][1];a[j]=a[j][0]}}if(i.overflow!=null)this.style.overflow="hidden";i.curAnim=c.extend({},a);c.each(a,function(s,x){var A=new c.fx(o,i,s);if(wb.test(x))A[x==="toggle"?n?"show":"hide":x](a);
-else{var B=xb.exec(x),C=A.cur(true)||0;if(B){x=parseFloat(B[2]);var E=B[3]||"px";if(E!=="px"){o.style[s]=(x||1)+E;C=(x||1)/A.cur(true)*C;o.style[s]=C+E}if(B[1])x=(B[1]==="-="?-1:1)*x+C;A.custom(C,x,E)}else A.custom(C,x,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",
-1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration==="number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,
-b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==
-null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(i){return e.step(i)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop===
-"width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=
-this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem,e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=
-c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=
-null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in r.documentElement?function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),
-f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b=this[0];if(a)return this.each(function(s){c.offset.setOffset(this,a,s)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=
-b,e=b.ownerDocument,i,j=e.documentElement,n=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var o=b.offsetTop,m=b.offsetLeft;(b=b.parentNode)&&b!==n&&b!==j;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;i=e?e.getComputedStyle(b,null):b.currentStyle;o-=b.scrollTop;m-=b.scrollLeft;if(b===d){o+=b.offsetTop;m+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){o+=parseFloat(i.borderTopWidth)||
-0;m+=parseFloat(i.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&i.overflow!=="visible"){o+=parseFloat(i.borderTopWidth)||0;m+=parseFloat(i.borderLeftWidth)||0}f=i}if(f.position==="relative"||f.position==="static"){o+=n.offsetTop;m+=n.offsetLeft}if(c.offset.supportsFixedPosition&&f.position==="fixed"){o+=Math.max(j.scrollTop,n.scrollTop);m+=Math.max(j.scrollLeft,n.scrollLeft)}return{top:o,left:m}};c.offset={initialize:function(){var a=r.body,b=r.createElement("div"),
-d,f,e,i=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<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>";a.insertBefore(b,a.firstChild);
-d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i;a.removeChild(b);c.offset.initialize=c.noop},
-bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),i=parseInt(c.curCSS(a,"top",true),10)||0,j=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a,d,e);d={top:b.top-e.top+i,left:b.left-
-e.left+j};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top-f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=
-this.offsetParent||r.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],i;if(!e)return null;if(f!==v)return this.each(function(){if(i=ua(this))i.scrollTo(!a?f:c(i).scrollLeft(),a?f:c(i).scrollTop());else this[d]=f});else return(i=ua(e))?"pageXOffset"in i?i[a?"pageYOffset":"pageXOffset"]:c.support.boxModel&&i.document.documentElement[d]||i.document.body[d]:e[d]}});
-c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(i){var j=c(this);j[d](f.call(this,i,j[d]()))});return"scrollTo"in e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||
-e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===v?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});z.jQuery=z.$=c})(window);
diff --git a/railties/lib/generators/rails/app/templates/public/javascripts/jquery.rails.js b/railties/lib/generators/rails/app/templates/public/javascripts/jquery.rails.js
deleted file mode 100644
index 887da514e2..0000000000
--- a/railties/lib/generators/rails/app/templates/public/javascripts/jquery.rails.js
+++ /dev/null
@@ -1,239 +0,0 @@
-jQuery(function ($) {
- var rails = {
- update: function (selector, content, position) {
- var element = $('#' + selector);
- if (position) {
- switch (position) {
- case "before":
- element.before(content);
- break;
- case "after":
- element.after(content);
- break;
- case "top":
- element.prepend(content);
- break;
- case "bottom":
- element.append(content);
- break;
- default:
- element.append(content);
- break;
- }
- } else {
- element.html(content);
- }
- },
- remote: function (e) {
- var el = $(this),
- data = [],
- condition = el.attr('data-condition') ? eval(el.attr('data-condition')) : true,
- method = el.attr('method') || el.attr('data-method') || 'GET',
- url = el.attr('action') || el.attr('data-url') || '#',
- async = el.attr('data-remote-type') === 'synchronous' ? false : true;
-
- if (el.attr('data-submit')) {
- data = $('#' + el.attr('data-submit')).serializeArray();
- } else if (el.attr('data-with')) {
-
- if (e && e.target.tagName.toUpperCase() == 'SCRIPT' && el.attr('data-observed') !== null) {
- var observed = $('#' + el.attr('data-observed'));
- if(observed[0].tagName.toUpperCase() === 'FORM'){
- data = el.attr('data-with') + '=' + observed.serialize();
- } else if(observed[0].tagName.toUpperCase() === 'INPUT' && observed.attr('type').toUpperCase() !== "BUTTON" && observed.attr('type').toUpperCase() !== "SUBMIT") {
- data = el.attr('data-with') + '=' + observed.val();
- }
- } else {
- // TODO: remove eval when deprecated
- data = eval(el.attr('data-with'));
- }
- } else if (e && e.target.tagName.toUpperCase() == 'FORM') {
- data = el.serializeArray();
- } else if (e && e.target.tagName.toUpperCase() == 'INPUT') {
- data = el.closest('form').serializeArray();
- }
-
- if (condition) {
- el.trigger('rails:before');
-
- $.ajax({
- async: async,
- url: url,
- data: data,
- type: method.toUpperCase(),
- beforeSend: function (xhr) {
- xhr.setRequestHeader("Accept", "text/javascript")
- el.trigger('rails:after', xhr);
- el.trigger('rails:loading', xhr);
- },
- success: function (data, status, xhr) {
- el.trigger('rails:success', [data, status, xhr]);
- if (el.attr('data-update-success')) {
- rails.update(el.attr('data-update-success'), data, el.attr('data-update-position'));
- }
- },
- complete: function (xhr) {
- // enable disabled_with buttons
- if (el[0].tagName.toUpperCase() == 'FORM') {
- el.children('input[type="button"][data-enable-with],input[type="submit"][data-enable-with]').each(function(i, button){
- button = $(button);
- button.attr('value', button.attr('data-enable-with'));
- button.removeAttr('data-enable-with');
- button.removeAttr('disabled');
-
- });
- } else {
- el.attr('value', el.attr('data-enable-with'));
- el.removeAttr('data-enable-with');
- el.removeAttr('disabled');
- }
-
- el.trigger('rails:complete', xhr);
- el.trigger('rails:loaded', xhr);
- },
- error: function (xhr, status, error) {
- el.trigger('rails:failure', [xhr, status, error]);
- if (el.attr('data-update-failure')) {
- rails.update(el.attr('data-update-failure'), xhr.responseText, el.attr('data-update-position'));
- }
- }
- });
- }
- e.preventDefault();
- }
- }
-
- /**
- * observe_form, and observe_field
- */
- $('script[data-observe="true"]').each(function (index, e) {
- var el = $(e),
- observed = $('#' + $(e).attr('data-observed'));
- frequency = el.attr('data-frequency') ? el.attr('data-frequency') : 10,
- value = observed[0].tagName.toUpperCase() === 'FORM' ? observed.serialize() : observed.val();
-
- var observe = function (observed, frequency, value, e) {
- return function () {
- var event = new jQuery.Event('periodical'),
- newValue = observed[0].tagName.toUpperCase() === 'FORM' ? observed.serialize() : observed.val();
- event.target = e;
-
- if(value !== newValue) {
- value = newValue;
- $(e).trigger('rails:observe');
- rails.remote.call(el, event);
- }
- }
- }(observed, frequency, value, e);
-
- setInterval(observe, frequency * 1000);
- });
-
- /**
- * confirm
- * make sure this event is first!
- */
- $('a[data-confirm],input[type="submit"][data-confirm],input[type="button"][data-confirm]').live('click', function(e){
- var el = $(this);
-
- if(!confirm(el.attr('data-confirm'))){
- return false;
- }
- });
-
- /**
- * periodically_call_remote
- */
- $('script[data-periodical="true"]').each(function (index, e) {
- var el = $(e),
- frequency = el.attr('data-frequency') ? el.attr('data-frequency') : 10;
-
- setInterval(function () {
- return function () {
- var event = new jQuery.Event('periodical');
- event.target = e;
-
- rails.remote.call(el, event);
- }
- }(e, el), frequency * 1000);
- });
-
- /**
- * disable_with
- */
- $('input[type="button"][data-disable-with],input[type="submit"][data-disable-with]').live('click', function(e){
- var el = $(this);
-
- el.attr('data-enable-with', el.attr('value'));
- el.attr('disabled', 'disabled');
- el.attr('value', el.attr('data-disable-with'));
- });
-
- /**
- * remote_form_tag, and remote_form_for
- */
- $('form[data-remote="true"]').live('submit', rails.remote);
-
- /**
- * link_to_remote, button_to_remote, and submit_to_remote
- */
- $('a[data-remote="true"],input[data-remote="true"],input[data-remote-submit="true"]').live('click', rails.remote);
-
- /*
- * popup
- */
- $('a[data-popup],input[type="button"][data-popup]').live('click', function(e){
- var el = $(this),
- url = el.attr('data-url') || el.attr('href');
-
- e.preventDefault();
-
- if(el.attr('data-popup') === "true"){
- window.open(url);
- } else {
- window.open(url, el.attr('data-popup'));
- }
- });
-
- /**
- *
- * Rails 2.x Helper / Event Handlers
- * By default we listen to all callbacks, and status code callbacks and
- * check the element for data-<callback> attribute and eval it.
- *
- */
- rails.compat = {
- evalAttribute: function (element, attribute) {
- var el = $(element),
- attr = el.attr('data-' + attribute);
- return (attr) ? eval(attr) : true;
- }
- };
-
- $('form[data-remote="true"],a[data-remote="true"],input[data-remote="true"],script[data-observe="true"]')
- .live('rails:before', function (e) {
- rails.compat.evalAttribute(this, 'onbefore');
- })
- .live('rails:after', function (e, xhr) {
- rails.compat.evalAttribute(this, 'onafter');
- })
- .live('rails:loading', function (e, xhr) {
- rails.compat.evalAttribute(this, 'onloading');
- })
- .live('rails:loaded', function (e, xhr) {
- rails.compat.evalAttribute(this, 'onloaded');
- })
- .live('rails:complete', function (e, xhr) {
- rails.compat.evalAttribute(this, 'oncomplete');
- rails.compat.evalAttribute(this, 'on' + xhr.status);
- })
- .live('rails:success', function (e, data, status, xhr) {
- rails.compat.evalAttribute(this, 'onsuccess');
- })
- .live('rails:failure', function (e, xhr, status, error) {
- rails.compat.evalAttribute(this, 'onfailure');
- })
- .live('rails:observe', function (e) {
- rails.compat.evalAttribute(this, 'onobserve');
- });
-});
diff --git a/railties/lib/generators/rails/app/templates/public/javascripts/prototype.rails.js b/railties/lib/generators/rails/app/templates/public/javascripts/prototype.rails.js
deleted file mode 100644
index aaed677fda..0000000000
--- a/railties/lib/generators/rails/app/templates/public/javascripts/prototype.rails.js
+++ /dev/null
@@ -1,324 +0,0 @@
-Event.observe(document, 'dom:loaded', function() {
- function handle_remote(el, e){
- var data = null,
- method = el.readAttribute('method') || el.readAttribute('data-method') || 'GET',
- url = el.readAttribute('action') || el.readAttribute('data-url') || '#',
- async = el.readAttribute('data-remote-type') === 'synchronous' ? false : true,
- update = el.readAttribute('data-update-success'),
- position = el.readAttribute('data-update-position');
-
- if (el.readAttribute('data-submit')) {
- var submit_el = $(el.readAttribute('data-submit'));
- if(submit_el !== undefined && submit_el.tagName.toUpperCase() == 'FORM'){
- data = submit_el.serialize();
- }
- } else if (el.readAttribute('data-with')) {
- // It seems there is a big inconsistency between what :with means depending on the element type
- // so this is going to look a bit crazy
- if(el.tagName.toUpperCase() === 'SCRIPT' && el.readAttribute('data-observed') !== null){
- // Handle observe_field and observe_form
- var observed_element = $(el.readAttribute('data-observed'));
-
- if(observed_element.tagName.toUpperCase() === 'FORM'){
- data = el.readAttribute('data-with') + '=' + observed_element.serialize();
- } else if(observed_element.tagName.toUpperCase() === 'INPUT' && observed_element.readAttribute('type').toUpperCase() !== "BUTTON" && observed_element.readAttribute('type').toUpperCase() !== "SUBMIT") {
- data = el.readAttribute('data-with') + '=' + observed_element.getValue();
- }
- } else {
- // Handle link_to and button_to
- data = evalAttribute(el, 'data-with');
- }
- } else if(el.tagName.toUpperCase() === 'FORM') {
- data = el.serialize();
- }
-
- document.fire('rails:before');
-
- var request = new Ajax.Request(url, {
- method: method,
- asynchronous: async,
- parameters: data,
- evalJS: true,
- evalJSON: true,
- onComplete: function(xhr){
- document.fire('rails:complete', {xhr: xhr, element: el, submitted_button: getEventProperty(e, 'submitted_button')});
- },
- onLoading: function(xhr){
- document.fire('rails:after', {xhr: xhr, element: el});
- document.fire('rails:loading', {xhr: xhr, element: el});
- },
- onLoaded: function(xhr){
- document.fire('rails:loaded', {xhr: xhr, element: el});
- },
- onSuccess: function(xhr){
- document.fire('rails:success', {xhr: xhr, element: el});
- },
- onFailure: function(xhr){
- document.fire('rails:failure', {xhr: xhr, element: el});
- }
- });
-
- }
-
- function setEventProperty(e, property, value){
- if(e.memo === undefined){
- e.memo = {};
- }
-
- e.memo[property] = value;
- }
-
- function getEventProperty(e, property){
- if(e !== null && e.memo !== undefined && e.memo[property] !== undefined){
- return e.memo[property];
- }
- }
-
- function confirmed(e, el){
- if(getEventProperty(e,'confirm_checked') !== true){
- setEventProperty(e, 'confirm_checked', true);
-
- el = Event.findElement(e, 'form') || el;
- var confirm_msg = el.readAttribute('data-confirm');
-
- if(confirm_msg !== null){
- var result = el.fire('rails:confirm', {confirm_msg: confirm_msg});
- if(result.memo.stop_event === true){
- Event.stop(e);
- return false;
- }
- }
- }
- return true;
- }
-
- function disable_button(el){
- var disable_with = el.readAttribute('data-disable-with');
- if(disable_with !== null){
- el.writeAttribute('data-enable-with', el.readAttribute('value'));
- el.writeAttribute('value', disable_with);
- el.writeAttribute('disabled', true);
- }
- }
-
- function enable_button(el){
- var enable_with = el.readAttribute('data-enable-with');
- if(enable_with !== null){
- el.writeAttribute('value', enable_with);
- }
- el.writeAttribute('disabled', false);
- }
-
- function updateHTML(el, content, result){
- var element_id = null;
-
- if(result === 'success'){
- element_id = el.readAttribute('data-update-success');
- } else if(result === 'failure'){
- element_id = el.readAttribute('data-update-failure');
- }
-
- var element_to_update = $(element_id);
- if(element_to_update !== null){
- var position = el.readAttribute('data-update-position');
- if(position !== null){
- var options = {};
- options[position] = content;
- element_to_update.insert(options);
- } else {
- element_to_update.update(content);
- }
- }
- }
-
- $$("script[data-periodical=true]").each(function(el){
- var executor = new PeriodicalExecuter(function() { handle_remote(el);}, el.readAttribute('data-frequency'));
- });
-
- $$("script[data-observe=true]").each(function(el){
- var observed_element = $(el.readAttribute('data-observed'));
- var original_value = observed_element.tagName.toUpperCase() === 'FORM' ? observed_element.serialize() : observed_element.getValue();
- var callback = el.readAttribute('data-onobserve');
- var executor = new PeriodicalExecuter(function() {
- var value = observed_element.tagName.toUpperCase() === 'FORM' ? observed_element.serialize() : observed_element.getValue();
-
- if(original_value !== value){
- original_value = value;
-
- if(callback !== null){
- evalAttribute(el, 'onobserve');
- } else if(el.readAttribute('data-url') !== null){
- handle_remote(el);
- }
- }
- }, el.readAttribute('data-frequency'));
-
- });
-
- /**
- *
- * Event Listeners
- *
- * the original element is contained inside the event,
- * for some reason prototype wont let me listen for custom events on document
- * if the event wasn't fired on document
- *
- */
-
- Event.observe(document, 'submit', function (e) {
- var form = Event.findElement(e, 'form');
- // Make sure conditions and confirm have not already run
- if(form !== undefined && conditions_met(e, form) && confirmed(e, form)){
-
- var button = form.down('input[data-submitted=true]');
- button.writeAttribute('data-submitted', null);
- setEventProperty(e, 'submitted_button', button);
- disable_button(button);
-
- if(form.readAttribute('data-remote') === 'true'){
- Event.stop(e);
- handle_remote(form, e);
- }
- }
- });
-
- Event.observe(document, 'click', function (e) {
- var el = Event.findElement(e, 'a') || Event.findElement(e, 'input');
-
- if(el !== undefined && el.tagName.toUpperCase() === 'INPUT' && el.readAttribute('type').toUpperCase() === 'SUBMIT'){
- el.writeAttribute('data-submitted', 'true');
-
- // Submit is handled by submit event, don't continue on this path
- el = undefined;
- } else if(el !== undefined && el.tagName.toUpperCase() === 'INPUT' && el.readAttribute('type').toUpperCase() !== 'BUTTON'){
- // Make sure other inputs do not send this event
- el = undefined;
- }
-
- if(el !== undefined && conditions_met(e, el) && confirmed(e, el)){
- if(el.tagName.toUpperCase() === 'INPUT' && el.readAttribute('type').toUpperCase() === 'BUTTON'){
- disable_button(el);
- }
-
- if(el.readAttribute('data-remote') === 'true'){
- Event.stop(e);
- handle_remote(el, e);
- } else if(el.readAttribute('data-popup') !== null){
- Event.stop(e);
- document.fire('rails:popup', {element: el});
- }
- }
- });
-
- /**
- *
- * Default Event Handlers
- *
- */
- Event.observe(document, 'rails:confirm', function(e){
- setEventProperty(e, 'stop_event', !confirm(getEventProperty(e,'confirm_msg')));
- });
-
- Event.observe(document, 'rails:popup', function(e){
- var el = getEventProperty(e, 'element');
- var url = el.readAttribute('href') || el.readAttribute('data-url');
-
- if(el.readAttribute('data-popup') === true){
- window.open(url);
- } else {
- window.open(url, el.readAttribute('data-popup'));
- }
- });
-
- Event.observe(document, 'rails:complete', function(e){
- var el = getEventProperty(e, 'element');
-
- if(el.tagName.toUpperCase() === 'FORM'){
- var button = getEventProperty(e, 'submitted_button') ;
- enable_button(button);
- }
- });
-
- Event.observe(document, 'rails:success', function(e){
- var el = getEventProperty(e, 'element'),
- xhr = getEventProperty(e, 'xhr');
-
- if(xhr.responseText !== null){
- updateHTML(el, xhr.responseText, 'success');
- }
- });
-
- Event.observe(document, 'rails:failure', function(e){
- var el = getEventProperty(e, 'element'),
- xhr = getEventProperty(e, 'xhr');
-
- if(xhr.responseText !== null){
- updateHTML(el, xhr.responseText, 'failure');
- }
- });
-
- /**
- *
- * Rails 2.x Helpers / Event Handlers
- *
- */
- function evalAttribute(el, attribute){
- var js = el.readAttribute('data-' + attribute);
-
- if(js){
- eval(js);
- }
- }
-
- function conditions_met(e, el){
- if(getEventProperty(e,'condition_checked') !== true){
- setEventProperty(e, 'condition_checked', true);
-
- el = Event.findElement(e, 'form') || el;
- var conditions = el.readAttribute('data-condition');
-
- if(conditions !== null){
- if(eval(conditions) === false){
- Event.stop(e);
- return false;
- }
- }
- }
- return true;
- }
-
- Event.observe(document, 'rails:success', function(e){
- evalAttribute(el, 'onsuccess');
- });
-
- Event.observe(document, 'rails:failure', function(e){
- evalAttribute(el, 'onfailure');
- });
-
- Event.observe(document, 'rails:complete', function(e){
- var el = getEventProperty(e, 'element');
-
- evalAttribute(el, 'oncomplete');
- evalAttribute(el, 'on' + getEventProperty('xhr', xhr.status));
-
- if(el.readAttribute('data-periodical') === 'true'){
- evalAttribute(el, 'onobserve');
- }
- });
-
- Event.observe(document, 'rails:loading', function(e){
- evalAttribute(el, 'onloading');
- });
-
- Event.observe(document, 'rails:loaded', function(e){
- evalAttribute(el, 'onloaded');
- });
-
- Event.observe(document, 'rails:before', function(e){
- evalAttribute(el, 'onbefore');
- });
-
- Event.observe(document, 'rails:after', function(e){
- evalAttribute(el, 'onafter');
- });
-});