module DeRjs::JqueryGenerator::GeneratorMethods
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.
Example:
# Generates: # new Element.insert("list", { bottom: "<li>Some item</li>" }); # new Effect.Highlight("list"); # ["status-indicator", "cancel-link"].each(Element.hide); update_page do |page| page.insert_html :bottom, 'list', "<li>#{@item.name}</li>" 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
object, that method will also have access to a page
object.
Example:
module ApplicationHelper def update_time page.replace_html 'time', Time.now.to_s(:db) page.visual_effect :highlight, 'time' end end # Controller action def poll render(:update) { |page| page.update_time } end
Calls to JavaScriptGenerator not matching a helper method below generate a proxy to the JavaScript Class named by the method called.
Examples:
# Generates: # Foo.init(); update_page do |page| page.foo.init end # Generates: # Event.observe('one', 'click', function () { # $('two').show(); # }); update_page do |page| page.event.observe('one', 'click') do |p| p[:two].show end end
You can also use PrototypeHelper#update_page_tag instead of PrototypeHelper#update_page to wrap the generated JavaScript in a <script>
tag.
Constants
- SCRIPTACULOUS_EFFECTS
Public Instance Methods
Writes raw JavaScript to the page.
Example:
page << "alert('JavaScript with Prototype.');"
# File lib/de_rjs/jquery_generator.rb, line 392 def <<(javascript) @lines << javascript end
Returns a element reference by finding it through id
in the DOM. This element can then be used for further method calls. Examples:
page['blank_slate'] # => $('blank_slate'); page['blank_slate'].show # => $('blank_slate').show(); page['blank_slate'].show('first').up # => $('blank_slate').show('first').up();
You can also pass in a record, which will use ActionController::RecordIdentifier.dom_id to lookup the correct id:
page[@post] # => $('post_45') page[Post.new] # => $('new_post')
# File lib/de_rjs/jquery_generator.rb, line 132 def [](id) case id when String, Symbol, NilClass JavaScriptElementProxy.new(self, id) else JavaScriptElementProxy.new(self, ActionView::RecordIdentifier.dom_id(id)) end end
Displays an alert dialog with the given message
.
Example:
# Generates: alert('This message is from Rails!') page.alert('This message is from Rails!')
# File lib/de_rjs/jquery_generator.rb, line 314 def alert(message) call 'alert', message end
# File lib/de_rjs/jquery_generator.rb, line 504 def arguments_for_call(arguments, block = nil) arguments << block_to_function(block) if block arguments.map { |argument| javascript_object_for(argument) }.join ', ' end
Assigns the JavaScript variable
the given value
.
Examples:
# Generates: my_string = "This is mine!"; page.assign 'my_string', 'This is mine!' # Generates: record_count = 33; page.assign 'record_count', 33 # Generates: tabulated_total = 47 page.assign 'tabulated_total', @total_from_cart
# File lib/de_rjs/jquery_generator.rb, line 383 def assign(variable, value) record "#{variable} = #{javascript_object_for(value)}" end
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 function() { ... }
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(); # $("two").hide(); # }); page.call(:my_method) do |p| p[:one].show p[:two].hide end
# File lib/de_rjs/jquery_generator.rb, line 366 def call(function, *arguments, &block) record "#{function}(#{arguments_for_call(arguments, block)})" end
Executes the content of the block after a delay of seconds
. Example:
# Generates: # setTimeout(function() { # ; # new Effect.Fade("notice",{}); # }, 20000); page.delay(20) do page.visual_effect :fade, 'notice' end
# File lib/de_rjs/jquery_generator.rb, line 406 def delay(seconds = 1) record "setTimeout(function() {\n\n" yield record "}, #{(seconds * 1000).to_i})" end
Hides the visible DOM elements with the given ids
.
Example:
# Hide a few people # Generates: ["person_29", "person_9", "person_0"].each(Element.hide); page.hide 'person_29', 'person_9', 'person_0'
# File lib/de_rjs/jquery_generator.rb, line 290 def hide(*ids) call "#{JQUERY_VAR}(\"#{jquery_ids(ids)}\").hide" #loop_on_multiple_args 'Element.hide', ids end
Inserts HTML at the specified position
relative to the DOM element identified by the given id
.
position
may be one of:
:top
-
HTML is inserted inside the element, before the element's existing content.
:bottom
-
HTML is inserted inside the element, after the element's existing content.
:before
-
HTML is inserted immediately preceding the element.
:after
-
HTML is inserted immediately following the element.
options_for_render
may be either a string of HTML to insert, or a hash of options to be passed to ActionView::Base#render. For example:
# Insert the rendered 'navigation' partial just before the DOM # element with ID 'content'. # Generates: Element.insert("content", { before: "-- Contents of 'navigation' partial --" }); page.insert_html :before, 'content', :partial => 'navigation' # Add a list item to the bottom of the <ul> with ID 'list'. # Generates: Element.insert("list", { bottom: "<li>Last item</li>" }); page.insert_html :bottom, 'list', '<li>Last item</li>'
# File lib/de_rjs/jquery_generator.rb, line 197 def insert_html(position, id, *options_for_render) insertion = position.to_s.downcase insertion = 'append' if insertion == 'bottom' insertion = 'prepend' if insertion == 'top' call "#{JQUERY_VAR}(\"#{jquery_id(id)}\").#{insertion}", render(*options_for_render) # content = javascript_object_for(render(*options_for_render)) # record "Element.insert(\"#{id}\", { #{position.to_s.downcase}: #{content} });" end
# File lib/de_rjs/jquery_generator.rb, line 482 def jquery_ui_effect(name, js_options) if SCRIPTACULOUS_EFFECTS.has_key? name.to_sym effect = SCRIPTACULOUS_EFFECTS[name.to_sym] name = effect[:method] mode = effect[:mode] js_options = js_options.merge(effect[:options]) if effect[:options] end js_options[:queue] = if js_options[:queue].is_a?(Hash) '{' + js_options[:queue].map {|k, v| k == :limit ? "#{k}:#{v}" : "#{k}:'#{v}'" }.join(',') + '}' elsif js_options[:queue] "'#{js_options[:queue]}'" end if js_options[:queue] [:color, :direction, :startcolor, :endcolor].each do |option| js_options[option] = "'#{js_options[option]}'" if js_options[option] end js_options[:duration] = (js_options[:duration] * 1000).to_i if js_options.has_key? :duration "#{mode || "effect"}(\"#{name}\",#{options_for_javascript(js_options)})" end
Returns a JavaScript snippet to be used on the Ajax callbacks for starting visual effects.
If no element_id
is given, it assumes “element” which should be a local variable in the generated JavaScript execution context. This can be used for example with drop_receiving_element
:
<%= drop_receiving_element (...), :loading => visual_effect(:fade) %>
This would fade the element that was dropped on the drop receiving element.
For toggling visual effects, you can use :toggle_appear
, :toggle_slide
, and :toggle_blind
which will alternate between appear/fade, slidedown/slideup, and blinddown/blindup respectively.
You can change the behaviour with various options, see script.aculo.us for more documentation.
# File lib/de_rjs/jquery_generator.rb, line 463 def jquery_ui_visual_effect(name, element_id = false, js_options = {}) #element = element_id ? ActiveSupport::JSON.encode(jquery_id((JavaScriptVariableProxy === element_id) ? element_id.as_json : element_id)) : "this" if element_id element = if element_id =~ /\A<%=.*%>\z/ # if completely using erb "\"##{element_id}\"" # USER BEWARE ! else ActiveSupport::JSON.encode(jquery_id((JavaScriptVariableProxy === element_id) ? element_id.as_json : element_id)) end else element = "this" end #if ['fadeIn','fadeOut','fadeToggle'].include?(name) # "$(\"#{jquery_id(element_id)}\").#{name}();" #else "#{JQUERY_VAR}(#{element}).#{jquery_ui_effect(name, js_options)}" #end end
Returns an object whose to_json
evaluates to code
. Use this to pass a literal JavaScript expression as an argument to another JavaScriptGenerator method.
# File lib/de_rjs/jquery_generator.rb, line 143 def literal(code) JsonLiteral.new(code.to_s) 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')
# File lib/de_rjs/jquery_generator.rb, line 327 def redirect_to(location) #url = location.is_a?(String) ? location : @context.url_for(location) url = location.to_s record "window.location.href = #{url.inspect}" end
Reloads the browser's current location
using JavaScript
Examples:
# Generates: window.location.reload(); page.reload
# File lib/de_rjs/jquery_generator.rb, line 339 def reload record 'window.location.reload()' end
Removes the DOM elements with the given ids
from the page.
Example:
# Remove a few people # Generates: ["person_23", "person_9", "person_2"].each(Element.remove); page.remove 'person_23', 'person_9', 'person_2'
# File lib/de_rjs/jquery_generator.rb, line 264 def remove(*ids) call "#{JQUERY_VAR}(\"#{jquery_ids(ids)}\").remove" #loop_on_multiple_args 'Element.remove', ids end
Replaces the “outer HTML” (i.e., the entire element, not just its contents) of the DOM element with the given id
.
options_for_render
may be either a string of HTML to insert, or a hash of options to be passed to ActionView::Base#render. For example:
# Replace the DOM element having ID 'person-45' with the # 'person' partial for the appropriate object. page.replace 'person-45', :partial => 'person', :object => @person
This allows the same partial that is used for the insert_html
to be also used for the input to replace
without resorting to the use of wrapper elements.
Examples:
<div id="people"> <%= render :partial => 'person', :collection => @people %> </div> # Insert a new person # # Generates: new Insertion.Bottom({object: "Matz", partial: "person"}, ""); page.insert_html :bottom, :partial => 'person', :object => @person # Replace an existing person # Generates: Element.replace("person_45", "-- Contents of partial --"); page.replace 'person_45', :partial => 'person', :object => @person
# File lib/de_rjs/jquery_generator.rb, line 251 def replace(id, *options_for_render) call "#{JQUERY_VAR}(\"#{jquery_id(id)}\").replaceWith", render(*options_for_render) #call 'Element.replace', 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 of options to be passed to ActionView::Base#render. For example:
# Replace the HTML of the DOM element having ID 'person-45' with the # 'person' partial for the appropriate object. # Generates: Element.update("person-45", "-- Contents of 'person' partial --"); page.replace_html 'person-45', :partial => 'person', :object => @person
# File lib/de_rjs/jquery_generator.rb, line 216 def replace_html(id, *options_for_render) call "#{JQUERY_VAR}(\"#{jquery_id(id)}\").html", render(*options_for_render) # call 'Element.update', id, render(*options_for_render) 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
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(); }); page.select('#items li').collect('hidden') do |item| item.hide end
# File lib/de_rjs/jquery_generator.rb, line 169 def select(pattern) JavaScriptElementCollectionProxy.new(self, pattern) end
Shows hidden DOM elements with the given ids
.
Example:
# Show a few people # Generates: ["person_6", "person_13", "person_223"].each(Element.show); page.show 'person_6', 'person_13', 'person_223'
# File lib/de_rjs/jquery_generator.rb, line 277 def show(*ids) call "#{JQUERY_VAR}(\"#{jquery_ids(ids)}\").show" #loop_on_multiple_args 'Element.show', ids end
Toggles the visibility of the DOM elements with the given ids
. Example:
# Show a few people # Generates: ["person_14", "person_12", "person_23"].each(Element.toggle); page.toggle 'person_14', 'person_12', 'person_23' # Hides the elements page.toggle 'person_14', 'person_12', 'person_23' # Shows the previously hidden elements
# File lib/de_rjs/jquery_generator.rb, line 303 def toggle(*ids) call "#{JQUERY_VAR}(\"#{jquery_ids(ids)}\").toggle" #loop_on_multiple_args 'Element.toggle', ids end
Starts a script.aculo.us visual effect. See ActionView::Helpers::ScriptaculousHelper for more information.
# File lib/de_rjs/jquery_generator.rb, line 414 def visual_effect(name, id = nil, options = {}) record jquery_ui_visual_effect(name, id, options) end
Private Instance Methods
# File lib/de_rjs/jquery_generator.rb, line 565 def block_to_function(block) generator = self.class.new(@context, &block) literal("function() { #{generator.to_s} }") end
# File lib/de_rjs/jquery_generator.rb, line 557 def javascript_object_for(object) if object.is_a?(String) && object =~ /\A<%=.*%>\z/m # if completely using erb "\"#{object}\"" else ::ActiveSupport::JSON.encode(object) end end
# File lib/de_rjs/jquery_generator.rb, line 518 def loop_on_multiple_args(method, ids) record(ids.size>1 ? "#{javascript_object_for(ids)}.each(#{method})" : "#{method}(#{javascript_object_for(ids.first)})") end
# File lib/de_rjs/jquery_generator.rb, line 510 def options_for_javascript(options) if options.empty? '{}' else "{#{options.keys.map { |k| "#{k}:#{options[k]}" }.sort.join(', ')}}" end end
# File lib/de_rjs/jquery_generator.rb, line 524 def page self end
# File lib/de_rjs/jquery_generator.rb, line 528 def record(line) line = "#{line.to_s.chomp.gsub(/\;\z/, '')};" self << line line end
# File lib/de_rjs/jquery_generator.rb, line 534 def render(*options) with_formats(:html) do case option = options.first when Hash @context.render(*options) else option.to_s end end end
# File lib/de_rjs/jquery_generator.rb, line 545 def with_formats(*args) return yield unless @context lookup = @context.lookup_context begin old_formats, lookup.formats = lookup.formats, args yield ensure lookup.formats = old_formats end end