Module: DeRjs::JqueryGenerator::GeneratorMethods

Defined in:
lib/de_rjs/jquery_generator.rb

Overview

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.

Constant Summary collapse

SCRIPTACULOUS_EFFECTS =
{
  :appear => {:method => 'fade', :mode => 'show'},
  :blind_down => {:method => 'blind', :mode => 'show', :options => {:direction => 'vertical'}},
  :blind_up => {:method => 'blind', :mode => 'hide', :options => {:direction => 'vertical'}},
  :blind_right => {:method => 'blind', :mode => 'show', :options => {:direction => 'horizontal'}},
  :blind_left => {:method => 'blind', :mode => 'hide', :options => {:direction => 'horizontal'}},
  :bounce_in => {:method => 'bounce', :mode => 'show', :options => {:direction => 'up'}},
  :bounce_out => {:method => 'bounce', :mode => 'hide', :options => {:direction => 'up'}},
  :drop_in => {:method => 'drop', :mode => 'show', :options => {:direction => 'up'}},
  :drop_out => {:method => 'drop', :mode => 'hide', :options => {:direction => 'down'}},
  :fade => {:method => 'fade', :mode => 'hide'},
  :fold_in => {:method => 'fold', :mode => 'hide'},
  :fold_out => {:method => 'fold', :mode => 'show'},
  :grow => {:method => 'scale', :mode => 'show'},
  :shrink => {:method => 'scale', :mode => 'hide'},
  :slide_down => {:method => 'slide', :mode => 'show', :options => {:direction => 'up'}},
  :slide_up => {:method => 'slide', :mode => 'hide', :options => {:direction => 'up'}},
  :slide_right => {:method => 'slide', :mode => 'show', :options => {:direction => 'left'}},
  :slide_left => {:method => 'slide', :mode => 'hide', :options => {:direction => 'left'}},
  :squish => {:method => 'scale', :mode => 'hide', :options => {:origin => "['top','left']"}},
  :switch_on => {:method => 'clip', :mode => 'show', :options => {:direction => 'vertical'}},
  :switch_off => {:method => 'clip', :mode => 'hide', :options => {:direction => 'vertical'}},
  :toggle_appear => {:method => 'fade', :mode => 'toggle'},
  :toggle_slide => {:method => 'slide', :mode => 'toggle', :options => {:direction => 'up'}},
  :toggle_blind => {:method => 'blind', :mode => 'toggle', :options => {:direction => 'vertical'}},
}

Instance Method Summary collapse

Instance Method Details

#<<(javascript) ⇒ Object

Writes raw JavaScript to the page.

Example:

page << "alert('JavaScript with Prototype.');"


392
393
394
# File 'lib/de_rjs/jquery_generator.rb', line 392

def <<(javascript)
  @lines << javascript
end

#[](id) ⇒ Object

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')


132
133
134
135
136
137
138
139
# 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

#alert(message) ⇒ Object

Displays an alert dialog with the given message.

Example:

# Generates: alert('This message is from Rails!')
page.alert('This message is from Rails!')


314
315
316
# File 'lib/de_rjs/jquery_generator.rb', line 314

def alert(message)
  call 'alert', message
end

#arguments_for_call(arguments, block = nil) ⇒ Object



504
505
506
507
# 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

#assign(variable, value) ⇒ Object

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


383
384
385
# File 'lib/de_rjs/jquery_generator.rb', line 383

def assign(variable, value)
  record "#{variable} = #{javascript_object_for(value)}"
end

#call(function, *arguments, &block) ⇒ Object

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


366
367
368
# File 'lib/de_rjs/jquery_generator.rb', line 366

def call(function, *arguments, &block)
  record "#{function}(#{arguments_for_call(arguments, block)})"
end

#delay(seconds = 1) ⇒ Object

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


406
407
408
409
410
# 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

#hide(*ids) ⇒ Object

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'


290
291
292
293
# 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

#insert_html(position, id, *options_for_render) ⇒ Object

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>'


197
198
199
200
201
202
203
204
# 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

#jquery_id(id) ⇒ Object

:nodoc:



112
113
114
# File 'lib/de_rjs/jquery_generator.rb', line 112

def jquery_id(id) #:nodoc:
  id.sub(/<%=.*%>/,'').to_s.count('#.*,>+~:[/ ') == 0 ? "##{id}" : id
end

#jquery_ids(ids) ⇒ Object

:nodoc:



116
117
118
# File 'lib/de_rjs/jquery_generator.rb', line 116

def jquery_ids(ids) #:nodoc:
  Array(ids).map{|id| jquery_id(id)}.join(',')
end

#jquery_ui_effect(name, js_options) ⇒ Object



482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
# 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

#jquery_ui_visual_effect(name, element_id = false, js_options = {}) ⇒ Object

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.



463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
# 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

#literal(code) ⇒ Object

Returns an object whose to_json evaluates to code. Use this to pass a literal JavaScript expression as an argument to another JavaScriptGenerator method.



143
144
145
# File 'lib/de_rjs/jquery_generator.rb', line 143

def literal(code)
  JsonLiteral.new(code.to_s)
end

#redirect_to(location) ⇒ Object

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')


327
328
329
330
331
# 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

#reloadObject

Reloads the browser’s current location using JavaScript

Examples:

# Generates: window.location.reload();
page.reload


339
340
341
# File 'lib/de_rjs/jquery_generator.rb', line 339

def reload
  record 'window.location.reload()'
end

#remove(*ids) ⇒ Object

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'


264
265
266
267
# 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

#replace(id, *options_for_render) ⇒ Object

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


251
252
253
254
# 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

#replace_html(id, *options_for_render) ⇒ Object

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


216
217
218
219
# 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

#select(pattern) ⇒ Object

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


169
170
171
# File 'lib/de_rjs/jquery_generator.rb', line 169

def select(pattern)
  JavaScriptElementCollectionProxy.new(self, pattern)
end

#show(*ids) ⇒ Object

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'


277
278
279
280
# 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

#to_sObject

:nodoc:



100
101
102
103
104
105
106
107
108
109
110
# File 'lib/de_rjs/jquery_generator.rb', line 100

def to_s #:nodoc:
  #(@lines * $/).tap do |javascript|
    #if ActionView::Base.debug_rjs
      #source = javascript.dup
      #javascript.replace "try {\n#{source}\n} catch (e) "
      #javascript << "{ alert('RJS error:\\n\\n' + e.toString()); alert('#{source.gsub('\\','\0\0').gsub(/\r\n|\n|\r/, "\\n").gsub(/["']/) { |m| "\\#{m}" }}'); throw e }"
    #end
  #end

  @lines * $/
end

#toggle(*ids) ⇒ Object

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


303
304
305
306
# 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

#visual_effect(name, id = nil, options = {}) ⇒ Object

Starts a script.aculo.us visual effect. See ActionView::Helpers::ScriptaculousHelper for more information.



414
415
416
# 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