Rails Helpers (and a little bit of javascript)

Posted by admin, Mon Mar 12 10:56:00 UTC 2007

On a website I have the following simple Rails/Scriptaculous list -

  • A List Item
  • Another List Item

Click on the first item and then on the link referring to the next item.

The first problem I had with this was that the standard scriptaculous routines don't support a blind-if-not-visible-already option - so when you clicked on the referring link, if the section it referred to was already visible it would hide and be displayed.

I needed to check the display property of the DIV and only do the blind/appear if the DOM was currently hidden. I chose to do this using a combination of some javascript and a helper.

Javascript

1
2
3
4
5
6
7
8
9
10
11
12
function slideshow(dom, options) {
  Effect.toggle(dom,'blind',options);
  Effect.toggle(dom,'appear',options);
}

function highlight(dom, slideoptions, options) {
  if ($(dom).getStyle('display') == 'none') {
    Effect.toggle(dom,'blind',slideoptions);
    Effect.toggle(dom,'appear',slideoptions);
  }
  new Effect.Highlight(dom,options);
}

The javascript is pretty simple but it helps to reduce the code clutter in both the helper and the generated HTML.

Helper

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
module ApplicationHelper
    def slideshow(element_id = false, js_options = {})
      element = element_id ? element_id.to_json : "element"
      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]

      "slideshow(#{element},#{options_for_javascript(js_options)});"

    end

    def highlight(element_id = false, sl_options={}, js_options={})
      element = element_id ? element_id.to_json : "element"

      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]

      sl_options[:queue] = if sl_options[:queue].is_a?(Hash)
        '{' + sl_options[:queue].map {|k, v| k == :limit ? "#{k}:#{v}" : "#{k}:'#{v}'" }.join(',') + '}'
      elsif sl_options[:queue]
        "'#{sl_options[:queue]}'"
      end if sl_options[:queue]

      "highlight(#{element}, #{options_for_javascript(sl_options)}, #{options_for_javascript(js_options)});"
    end
end

I stole most of the code in the helper from the existing scriptaculous helper. As you can see it is just a simple wrapper to generate the javascript function call. I could have simplified the use of my new helpers still by having the helper itself generate the links also but this would have also required supportting any additional attributes etc.. - as link_to_function already does this I decided using it was a no brainer.

View

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<ul>
 <li><%= link_to_function 'A List Item', 
  slideshow(:list1, { :duration => 0.5, :queue => 'parallel' }) %>
  <div id="list1" style="display: none">
   The text in this list item refers to the list item below,
   and when you click on 
   <%= link_to_function 'this link', 
    highlight(:list2,
      { :duration => 0.5, :queue => 'parallel' },
      { :duration => 0.5, :queue => 'end' } ) %> 
    the item below should open also
  </div>
 </li>
 <li><%= link_to_function 'Another List Item', 
    slideshow( :list1, { :duration => 0.5, :queue => 'parallel' } ) %>
  <div id="list2" style="display: none">
    This is the text explaining the second item in this list.
  </div>
 </li>
</ul>

Filed Under: Rails | Tags:

Comments

Have your say

A name is required. You may use HTML in your comments.