diff options
Diffstat (limited to 'actionpack/lib/action_view/helpers')
-rw-r--r-- | actionpack/lib/action_view/helpers/cache_helper.rb | 2 | ||||
-rw-r--r-- | actionpack/lib/action_view/helpers/prototype_helper.rb | 375 |
2 files changed, 189 insertions, 188 deletions
diff --git a/actionpack/lib/action_view/helpers/cache_helper.rb b/actionpack/lib/action_view/helpers/cache_helper.rb index 2cdbae6e40..64d1ad2715 100644 --- a/actionpack/lib/action_view/helpers/cache_helper.rb +++ b/actionpack/lib/action_view/helpers/cache_helper.rb @@ -32,7 +32,7 @@ module ActionView # <i>Topics listed alphabetically</i> # <% end %> def cache(name = {}, options = nil, &block) - _last_render.handler.new(@controller).cache_fragment(block, name, options) + @controller.fragment_for(output_buffer, name, options, &block) end end end diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index d0c281c803..edb43844a4 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -3,25 +3,25 @@ require 'set' module ActionView module Helpers # Prototype[http://www.prototypejs.org/] is a JavaScript library that provides - # DOM[http://en.wikipedia.org/wiki/Document_Object_Model] manipulation, + # DOM[http://en.wikipedia.org/wiki/Document_Object_Model] manipulation, # Ajax[http://www.adaptivepath.com/publications/essays/archives/000385.php] - # functionality, and more traditional object-oriented facilities for JavaScript. + # functionality, and more traditional object-oriented facilities for JavaScript. # This module provides a set of helpers to make it more convenient to call - # functions from Prototype using Rails, including functionality to call remote - # Rails methods (that is, making a background request to a Rails action) using Ajax. - # This means that you can call actions in your controllers without - # reloading the page, but still update certain parts of it using + # functions from Prototype using Rails, including functionality to call remote + # Rails methods (that is, making a background request to a Rails action) using Ajax. + # This means that you can call actions in your controllers without + # reloading the page, but still update certain parts of it using # injections into the DOM. A common use case is having a form that adds # a new element to a list without reloading the page or updating a shopping # cart total when a new item is added. # # == Usage - # To be able to use these helpers, you must first include the Prototype - # JavaScript framework in your pages. + # To be able to use these helpers, you must first include the Prototype + # JavaScript framework in your pages. # # javascript_include_tag 'prototype' # - # (See the documentation for + # (See the documentation for # ActionView::Helpers::JavaScriptHelper for more information on including # this and other JavaScript files in your Rails templates.) # @@ -29,7 +29,7 @@ module ActionView # # link_to_remote "Add to cart", # :url => { :action => "add", :id => product.id }, - # :update => { :success => "cart", :failure => "error" } + # :update => { :success => "cart", :failure => "error" } # # ...through a form... # @@ -50,8 +50,8 @@ module ActionView # :update => :hits, # :with => 'query' # %> - # - # As you can see, there are numerous ways to use Prototype's Ajax functions (and actually more than + # + # 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 @@ -63,7 +63,7 @@ module ActionView # 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 normall return to the browser, it will # return to the Ajax call. As such, you typically don't want to render with a layout. This call will cause - # the layout to be transmitted back to your page, and, if you have a full HTML/CSS, will likely mess a lot of things up. + # the layout to be transmitted back to your page, and, if you have a full HTML/CSS, will likely mess a lot of things up. # You can turn the layout off on particular actions by doing the following: # # class SiteController < ActionController::Base @@ -74,8 +74,8 @@ module ActionView # # render :layout => false # - # You can tell the type of request from within your action using the <tt>request.xhr?</tt> (XmlHttpRequest, the - # method that Ajax uses to make background requests) method. + # You can tell the type of request from within your action using the <tt>request.xhr?</tt> (XmlHttpRequest, the + # method that Ajax uses to make background requests) method. # def name # # Is this an XmlHttpRequest request? # if (request.xhr?) @@ -93,7 +93,7 @@ module ActionView # # Dropping this in your ApplicationController turns the layout off for every request that is an "xhr" request. # - # If you are just returning a little data or don't want to build a template for your output, you may opt to simply + # If you are just returning a little data or don't want to build a template for your output, you may opt to simply # render text output, like this: # # render :text => 'Return this from my method!' @@ -103,7 +103,7 @@ module ActionView # # == Updating multiple elements # See JavaScriptGenerator for information on updating multiple elements - # on the page in an Ajax response. + # on the page in an Ajax response. module PrototypeHelper unless const_defined? :CALLBACKS CALLBACKS = Set.new([ :uninitialized, :loading, :loaded, @@ -114,64 +114,64 @@ module ActionView :form, :with, :update, :script ]).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 + # 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>. + # 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. + # render :partial. # # Examples: - # # Generates: <a href="#" onclick="new Ajax.Updater('posts', '/blog/destroy/3', {asynchronous:true, evalScripts:true}); + # # 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", + # 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}); + # # 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", + # 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" } + # :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 + # 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', + # # 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 + # 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'}); + # # 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. + # 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, + # # 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, @@ -180,43 +180,43 @@ module ActionView # # The callbacks that may be specified are (in order): # - # <tt>:loading</tt>:: Called when the remote document is being + # <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 + # <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 + # <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 + # + # 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...?')}, + # # 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 + # 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 + # 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 + # JavaScript code snippets via some optional parameters. In their order # of use these are: # # <tt>:confirm</tt>:: Adds confirmation dialog. @@ -228,7 +228,7 @@ module ActionView # <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 + # 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. @@ -238,10 +238,10 @@ module ActionView # URL query string. # # Example: - # + # # :with => "'name=' + $('name').value" # - # You can generate a link that uses AJAX in the general case, while + # 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 @@ -251,7 +251,7 @@ module ActionView # 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) + def link_to_remote(name, options = {}, html_options = nil) link_to_function(name, remote_function(options), html_options || options.delete(:html)) end @@ -262,15 +262,15 @@ module ActionView # 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', + # # 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'}, + # # 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" } @@ -286,11 +286,11 @@ module ActionView javascript_tag(code) end - # Returns a form tag that will submit using XMLHttpRequest in the - # background instead of the regular reloading POST arrangement. Even + # 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 + # 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+. # @@ -299,21 +299,21 @@ module ActionView # # Example: # # Generates: - # # <form action="/some/place" method="post" onsubmit="new Ajax.Request('', + # # <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 => + # 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 + # 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)}); + # # <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 -%> @@ -323,19 +323,19 @@ module ActionView options[:form] = true options[:html] ||= {} - options[:html][:onsubmit] = - (options[:html][:onsubmit] ? options[:html][:onsubmit] + "; " : "") + + 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 + # 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. + # values for the fields. # - # === Resource + # === Resource # # Example: # <% remote_form_for(@post) do |f| %> @@ -348,7 +348,7 @@ module ActionView # ... # <% end %> # - # === Nested Resource + # === Nested Resource # # Example: # <% remote_form_for([@post, @comment]) do |f| %> @@ -387,23 +387,23 @@ module ActionView concat('</form>') 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. + # 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)}); + # # + # # 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" /> # <%= button_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)}); + # # 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" /> # <%= button_to_remote 'update_btn', 'Update', :url => { :action => 'update' }, # :update => { :success => "succeed", :failure => "fail" } @@ -423,7 +423,7 @@ module ActionView tag("input", options[:html], false) end alias_method :submit_to_remote, :button_to_remote - + # 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. @@ -433,11 +433,11 @@ module ActionView # Returns the JavaScript needed for a remote function. # Takes the same arguments as link_to_remote. - # + # # Example: - # # Generates: <select id="options" onchange="new Ajax.Updater('options', + # # Generates: <select id="options" onchange="new Ajax.Updater('options', # # '/testing/update_options', {asynchronous:true, evalScripts:true})"> - # <select id="options" onchange="<%= remote_function(:update => "options", + # <select id="options" onchange="<%= remote_function(:update => "options", # :url => { :action => :update_options }) %>"> # <option value="0">Hello</option> # <option value="1">World</option> @@ -455,7 +455,7 @@ module ActionView update << "'#{options[:update]}'" end - function = update.empty? ? + function = update.empty? ? "new Ajax.Request(" : "new Ajax.Updater(#{update}, " @@ -476,9 +476,9 @@ module ActionView # 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', + # # 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, @@ -500,14 +500,14 @@ module ActionView # 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 + # <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 @@ -518,7 +518,7 @@ module ActionView # variable +value+. # # Examples - # + # # :with => "'my_custom_key=' + value" # :with => "'person[name]=' + prompt('New name')" # :with => "Form.Element.serialize('other-field')" @@ -544,7 +544,7 @@ module ActionView # observe_field 'book_title', # :url => 'http://example.com/books/edit/1', # :with => 'title' - # + # # # Sends params: {:book_title => 'Title of the book'} when the focus leaves # # the input field. # observe_field 'book_title', @@ -558,7 +558,7 @@ module ActionView 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 @@ -574,16 +574,17 @@ module ActionView build_observer('Form.EventObserver', form_id, options) end end - - # All the methods were moved to GeneratorMethods so that + + # All the methods were moved to GeneratorMethods so that # #include_helpers_from_context has nothing to overwrite. class JavaScriptGenerator #:nodoc: def initialize(context, &block) #:nodoc: @context, @lines = context, [] + @context.output_buffer = @lines if @context include_helpers_from_context @context.instance_exec(self, &block) end - + private def include_helpers_from_context @context.extended_by.each do |mod| @@ -591,17 +592,17 @@ module ActionView end extend GeneratorMethods end - - # JavaScriptGenerator generates blocks of JavaScript code that allow you - # to change the content and presentation of multiple DOM elements. Use + + # JavaScriptGenerator generates blocks of JavaScript code that allow you + # to change the content and presentation of multiple DOM elements. Use # this in your Ajax response bodies, either in a <script> tag or as plain # JavaScript sent with a Content-type of "text/javascript". # - # Create new instances with PrototypeHelper#update_page or with - # ActionController::Base#render, then call +insert_html+, +replace_html+, - # +remove+, +show+, +hide+, +visual_effect+, or any other of the built-in - # methods on the yielded generator in any order you like to modify the - # content and appearance of the current page. + # Create new instances with PrototypeHelper#update_page or with + # ActionController::Base#render, then call +insert_html+, +replace_html+, + # +remove+, +show+, +hide+, +visual_effect+, or any other of the built-in + # methods on the yielded generator in any order you like to modify the + # content and appearance of the current page. # # Example: # @@ -614,12 +615,12 @@ module ActionView # page.visual_effect :highlight, 'list' # page.hide 'status-indicator', 'cancel-link' # end - # + # # # Helper methods can be used in conjunction with JavaScriptGenerator. - # When a helper method is called inside an update block on the +page+ + # When a helper method is called inside an update block on the +page+ # object, that method will also have access to a +page+ object. - # + # # Example: # # module ApplicationHelper @@ -655,7 +656,7 @@ module ActionView # end # end # - # You can also use PrototypeHelper#update_page_tag instead of + # You can also use PrototypeHelper#update_page_tag instead of # PrototypeHelper#update_page to wrap the generated JavaScript in a # <script> tag. module GeneratorMethods @@ -668,7 +669,7 @@ module ActionView end end end - + # Returns a element reference by finding it through +id+ in the DOM. This element can then be # used for further method calls. Examples: # @@ -689,31 +690,31 @@ module ActionView JavaScriptElementProxy.new(self, ActionController::RecordIdentifier.dom_id(id)) end end - - # Returns an object whose <tt>to_json</tt> evaluates to +code+. Use this to pass a literal JavaScript + + # Returns an object whose <tt>to_json</tt> evaluates to +code+. Use this to pass a literal JavaScript # expression as an argument to another JavaScriptGenerator method. def literal(code) ActiveSupport::JSON::Variable.new(code.to_s) end - + # Returns a collection reference by finding it through a CSS +pattern+ in the DOM. This collection can then be # used for further method calls. Examples: # # page.select('p') # => $$('p'); # page.select('p.welcome b').first # => $$('p.welcome b').first(); # page.select('p.welcome b').first.hide # => $$('p.welcome b').first().hide(); - # + # # You can also use prototype enumerations with the collection. Observe: - # + # # # Generates: $$('#items li').each(function(value) { value.hide(); }); # page.select('#items li').each do |value| # value.hide - # end + # end # - # Though you can call the block param anything you want, they are always rendered in the + # Though you can call the block param anything you want, they are always rendered in the # javascript as 'value, index.' Other enumerations, like collect() return the last statement: # - # # Generates: var hidden = $$('#items li').collect(function(value, index) { return value.hide(); }); + # # Generates: var hidden = $$('#items li').collect(function(value, index) { return value.hide(); }); # page.select('#items li').collect('hidden') do |item| # item.hide # end @@ -721,13 +722,13 @@ module ActionView def select(pattern) JavaScriptElementCollectionProxy.new(self, pattern) end - + # Inserts HTML at the specified +position+ relative to the DOM element # identified by the given +id+. - # + # # +position+ may be one of: - # - # <tt>:top</tt>:: HTML is inserted inside the element, before the + # + # <tt>:top</tt>:: HTML is inserted inside the element, before the # element's existing content. # <tt>:bottom</tt>:: HTML is inserted inside the element, after the # element's existing content. @@ -750,7 +751,7 @@ module ActionView insertion = position.to_s.camelize call "new Insertion.#{insertion}", id, render(*options_for_render) end - + # Replaces the inner HTML of the DOM element with the given +id+. # # +options_for_render+ may be either a string of HTML to insert, or a hash @@ -764,7 +765,7 @@ module ActionView def replace_html(id, *options_for_render) call 'Element.update', id, render(*options_for_render) end - + # Replaces the "outer HTML" (i.e., the entire element, not just its # contents) of the DOM element with the given +id+. # @@ -786,7 +787,7 @@ module ActionView # </div> # # # Insert a new person - # # + # # # # Generates: new Insertion.Bottom({object: "Matz", partial: "person"}, ""); # page.insert_html :bottom, :partial => 'person', :object => @person # @@ -798,7 +799,7 @@ module ActionView def replace(id, *options_for_render) call 'Element.replace', id, render(*options_for_render) end - + # Removes the DOM elements with the given +ids+ from the page. # # Example: @@ -810,9 +811,9 @@ module ActionView def remove(*ids) loop_on_multiple_args 'Element.remove', ids end - + # Shows hidden DOM elements with the given +ids+. - # + # # Example: # # # Show a few people @@ -822,7 +823,7 @@ module ActionView def show(*ids) loop_on_multiple_args 'Element.show', ids end - + # Hides the visible DOM elements with the given +ids+. # # Example: @@ -832,9 +833,9 @@ module ActionView # page.hide 'person_29', 'person_9', 'person_0' # def hide(*ids) - loop_on_multiple_args 'Element.hide', ids + loop_on_multiple_args 'Element.hide', ids end - + # Toggles the visibility of the DOM elements with the given +ids+. # Example: # @@ -844,9 +845,9 @@ module ActionView # page.toggle 'person_14', 'person_12', 'person_23' # Shows the previously hidden elements # def toggle(*ids) - loop_on_multiple_args 'Element.toggle', ids + loop_on_multiple_args 'Element.toggle', ids end - + # Displays an alert dialog with the given +message+. # # Example: @@ -856,21 +857,21 @@ module ActionView def alert(message) call 'alert', message end - + # Redirects the browser to the given +location+ using JavaScript, in the same form as +url_for+. # # Examples: # # # Generates: window.location.href = "/mycontroller"; # page.redirect_to(:action => 'index') - # + # # # Generates: window.location.href = "/account/signup"; # page.redirect_to(:controller => 'account', :action => 'signup') def redirect_to(location) url = location.is_a?(String) ? location : @context.url_for(location) record "window.location.href = #{url.inspect}" end - + # Reloads the browser's current +location+ using JavaScript # # Examples: @@ -884,17 +885,17 @@ module ActionView # Calls the JavaScript +function+, optionally with the given +arguments+. # # If a block is given, the block will be passed to a new JavaScriptGenerator; - # the resulting JavaScript code will then be wrapped inside <tt>function() { ... }</tt> + # the resulting JavaScript code will then be wrapped inside <tt>function() { ... }</tt> # and passed as the called function's final argument. - # + # # Examples: # # # Generates: Element.replace(my_element, "My content to replace with.") # page.call 'Element.replace', 'my_element', "My content to replace with." - # + # # # Generates: alert('My message!') # page.call 'alert', 'My message!' - # + # # # Generates: # # my_method(function() { # # $("one").show(); @@ -907,7 +908,7 @@ module ActionView def call(function, *arguments, &block) record "#{function}(#{arguments_for_call(arguments, block)})" end - + # Assigns the JavaScript +variable+ the given +value+. # # Examples: @@ -918,13 +919,13 @@ module ActionView # # Generates: record_count = 33; # page.assign 'record_count', 33 # - # # Generates: tabulated_total = 47 + # # Generates: tabulated_total = 47 # page.assign 'tabulated_total', @total_from_cart # def assign(variable, value) record "#{variable} = #{javascript_object_for(value)}" end - + # Writes raw JavaScript to the page. # # Example: @@ -933,10 +934,10 @@ module ActionView def <<(javascript) @lines << javascript end - + # Executes the content of the block after a delay of +seconds+. Example: # - # # Generates: + # # Generates: # # setTimeout(function() { # # ; # # new Effect.Fade("notice",{}); @@ -949,13 +950,13 @@ module ActionView yield record "}, #{(seconds * 1000).to_i})" end - - # Starts a script.aculo.us visual effect. See + + # Starts a script.aculo.us visual effect. See # ActionView::Helpers::ScriptaculousHelper for more information. def visual_effect(name, id = nil, options = {}) record @context.send(:visual_effect, name, id, options) end - + # Creates a script.aculo.us sortable element. Useful # to recreate sortable elements after items get added # or deleted. @@ -963,66 +964,66 @@ module ActionView def sortable(id, options = {}) record @context.send(:sortable_element_js, id, options) end - + # Creates a script.aculo.us draggable element. # See ActionView::Helpers::ScriptaculousHelper for more information. def draggable(id, options = {}) record @context.send(:draggable_element_js, id, options) end - + # Creates a script.aculo.us drop receiving element. # See ActionView::Helpers::ScriptaculousHelper for more information. def drop_receiving(id, options = {}) record @context.send(:drop_receiving_element_js, id, options) end - + private def loop_on_multiple_args(method, ids) - record(ids.size>1 ? - "#{javascript_object_for(ids)}.each(#{method})" : + record(ids.size>1 ? + "#{javascript_object_for(ids)}.each(#{method})" : "#{method}(#{ids.first.to_json})") end - + def page self end - + def record(line) returning line = "#{line.to_s.chomp.gsub(/\;\z/, '')};" do self << line end end - + def render(*options_for_render) old_format = @context && @context.template_format @context.template_format = :html if @context - Hash === options_for_render.first ? - @context.render(*options_for_render) : + Hash === options_for_render.first ? + @context.render(*options_for_render) : options_for_render.first.to_s ensure @context.template_format = old_format if @context end - + def javascript_object_for(object) object.respond_to?(:to_json) ? object.to_json : object.inspect end - + def arguments_for_call(arguments, block = nil) arguments << block_to_function(block) if block arguments.map { |argument| javascript_object_for(argument) }.join ', ' end - + def block_to_function(block) generator = self.class.new(@context, &block) literal("function() { #{generator.to_s} }") - end + end def method_missing(method, *arguments) JavaScriptProxy.new(self, method.to_s.camelize) end end end - + # Yields a JavaScriptGenerator and returns the generated JavaScript code. # Use this to update multiple elements on a page in an Ajax response. # See JavaScriptGenerator for more information. @@ -1035,13 +1036,13 @@ module ActionView def update_page(&block) JavaScriptGenerator.new(@template, &block).to_s end - + # Works like update_page but wraps the generated JavaScript in a <script> # tag. Use this to include generated JavaScript in an ERb template. # See JavaScriptGenerator for more information. # # +html_options+ may be a hash of <script> attributes to be passed - # to ActionView::Helpers::JavaScriptHelper#javascript_tag. + # to ActionView::Helpers::JavaScriptHelper#javascript_tag. def update_page_tag(html_options = {}, &block) javascript_tag update_page(&block), html_options end @@ -1049,7 +1050,7 @@ module ActionView protected def options_for_ajax(options) js_options = build_callbacks(options) - + js_options['asynchronous'] = options[:type] != :synchronous js_options['method'] = method_option_to_s(options[:method]) if options[:method] js_options['insertion'] = "Insertion.#{options[:position].to_s.camelize}" if options[:position] @@ -1062,7 +1063,7 @@ module ActionView elsif options[:with] js_options['parameters'] = options[:with] end - + if protect_against_forgery? && !options[:form] if js_options['parameters'] js_options['parameters'] << " + '&" @@ -1071,14 +1072,14 @@ module ActionView end js_options['parameters'] << "#{request_forgery_protection_token}=' + encodeURIComponent('#{escape_javascript form_authenticity_token}')" end - + options_for_javascript(js_options) end - def method_option_to_s(method) + def method_option_to_s(method) (method.is_a?(String) and !method.index("'").nil?) ? method : "'#{method}'" end - + def build_observer(klass, name, options = {}) if options[:with] && (options[:with] !~ /[\{=(.]/) options[:with] = "'#{options[:with]}=' + encodeURIComponent(value)" @@ -1095,7 +1096,7 @@ module ActionView javascript << ")" javascript_tag(javascript) end - + def build_callbacks(options) callbacks = {} options.each do |callback, code| @@ -1108,7 +1109,7 @@ module ActionView end end - # Converts chained method calls on DOM proxy elements into JavaScript chains + # Converts chained method calls on DOM proxy elements into JavaScript chains class JavaScriptProxy < ActiveSupport::BasicObject #:nodoc: def initialize(generator, root = nil) @@ -1124,7 +1125,7 @@ module ActionView call("#{method.to_s.camelize(:lower)}", *arguments, &block) end end - + def call(function, *arguments, &block) append_to_function_chain!("#{function}(#{@generator.send(:arguments_for_call, arguments, block)})") self @@ -1133,23 +1134,23 @@ module ActionView def assign(variable, value) append_to_function_chain!("#{variable} = #{@generator.send(:javascript_object_for, value)}") end - + def function_chain @function_chain ||= @generator.instance_variable_get(:@lines) end - + def append_to_function_chain!(call) function_chain[-1].chomp!(';') function_chain[-1] += ".#{call};" end end - + class JavaScriptElementProxy < JavaScriptProxy #:nodoc: def initialize(generator, id) @id = id super(generator, "$(#{id.to_json})") end - + # Allows access of element attributes through +attribute+. Examples: # # page['foo']['style'] # => $('foo').style; @@ -1160,11 +1161,11 @@ module ActionView append_to_function_chain!(attribute) self end - + def []=(variable, value) assign(variable, value) end - + def replace_html(*options_for_render) call 'update', @generator.send(:render, *options_for_render) end @@ -1172,11 +1173,11 @@ module ActionView def replace(*options_for_render) call 'replace', @generator.send(:render, *options_for_render) end - + def reload(options_for_replace = {}) replace(options_for_replace.merge({ :partial => @id.to_s })) end - + end class JavaScriptVariableProxy < JavaScriptProxy #:nodoc: @@ -1195,7 +1196,7 @@ module ActionView def to_json(options = nil) @variable end - + private def append_to_function_chain!(call) @generator << @variable if @empty @@ -1213,7 +1214,7 @@ module ActionView def initialize(generator, pattern) super(generator, @pattern = pattern) end - + def each_slice(variable, number, &block) if block enumerate :eachSlice, :variable => variable, :method_args => [number], :yield_args => %w(value index), :return => true, &block @@ -1222,18 +1223,18 @@ module ActionView append_enumerable_function!("eachSlice(#{number.to_json});") end end - + def grep(variable, pattern, &block) enumerate :grep, :variable => variable, :return => true, :method_args => [pattern], :yield_args => %w(value index), &block end - + def in_groups_of(variable, number, fill_with = nil) arguments = [number] arguments << fill_with unless fill_with.nil? add_variable_assignment!(variable) append_enumerable_function!("inGroupsOf(#{arguments_for_call arguments});") - end - + end + def inject(variable, memo, &block) enumerate :inject, :variable => variable, :method_args => [memo], :yield_args => %w(memo value index), :return => true, &block end @@ -1295,13 +1296,13 @@ module ActionView function_chain.push("return #{function_chain.pop.chomp(';')};") end end - + def append_enumerable_function!(call) function_chain[-1].chomp!(';') function_chain[-1] += ".#{call}" end end - + class JavaScriptElementCollectionProxy < JavaScriptCollectionProxy #:nodoc:\ def initialize(generator, pattern) super(generator, "$$(#{pattern.to_json})") |