Lightview for modal dialogs on Rails

Posted by Ric Thu, 26 Jun 2008 21:57:00 GMT

Long-time followers of this blog will know that I’ve tried various solutions for modal dialogs in rails apps (namely, Prototype-Window, and Redbox).

Prototype-Window worked fine, but uses Prototype 1.5RC3, and I’m using rails 2 with Prototype 1.6. The guys behind Prototype-Window are working on a new open source library, Prototype-UI which uses Prototype 1.6 and Script.aculo.us 1.8, but it’s still just a release candidate at the moment. This is a really exciting development and it will be interesting to see how this project progresses.

Initially, I was a big fan of Redbox, but I uncovered a few problems as time went on (including some cross-browser issues), which meant that it lost favour. To be fair to Craig Ambrose, the developer of Redbox, he did mention to me that he wasn’t currently working on it, and that it was just built to fit the exact requirements he had at the time.

So, to get down to the topic of this blog post… my current modal dialog solution du jour is Lightview by Nick Stakenburg. It’s not free, but relatively cheap, even for commercial use (€49 for one domain – if you compare this cost to the amount of developer-time it would take to write something of equal quality, it’s really a no-brainer). You can download a free-trial so that you can try it out before buying. I can’t comment on the quality of the code because it’s obfuscated but the documentation on the website is great, and the product itself works well across all major browsers.

I thought I would share how i got Lightview working in a rails application, for showing ajax content.

1. Download Lightview from here. (I’m using version 2.2.9.2)

2. Make a lightview folder in your application’s public/javascripts folder, and copy the contents (i.e. the css, images and js folders) of the lightview 2.x folder into your new folder.

3. Create a new file, lightview_helper.rb, in your helpers folder, and add the following code into it.

module LightviewHelper

# A lightview is shown with js like below (example taken from the lightview site: 
# (http://www.nickstakenburg.com/projects/lightview/)
# There are 2 levels of arguments: 
#   top-level 'parameters' (href, rel etc.)
#   2nd-level 'options' (autosize, ajax etc.)

#  Lightview.show({
#    href: '/ajax/',
#    rel: 'ajax',
#    title: 'Login',
#    caption: 'Enter your username and password to login',
#    options: {
#      autosize: true,
#      topclose: true,
#      ajax: {
#        method: 'get',
#        onComplete: function(){ $('name').focus(); }
#      }
#    }
#  });

 # link to a light view.
 # name: the text to display in the link
 # options: url options for the content to show in the lightview
 # html_options: html_options to pass to link_to 
 # lightview_params: parameters (top-level arguments) for lightview, that differ from or add to defaults
 # lightview_options: options (2nd-level arguments) for lightview, that differ from or add to the defaults
 def link_to_lightview( name, options = {}, html_options = {}, lightview_params = {}, lightview_options = {} )

    # get hold of the js for showing the lightview
    show_lightview_js = show_lightview( options, lightview_params, lightview_options )

    # merge in the javascipt on the onclick event, keeping any other onclick code intact.    
    html_options.merge!({ 
      :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{show_lightview_js} return false;" 
    })

    # return a link which points to #, but has the onclick event in the html options.
    link_to( name, "#", html_options )

  end 

  # returns javascript for showing a lightview.
  # url_options : hash of options to pass to url_for 
  # parameters: parameters (top-level arguments) for lightview, that differ from or add to defaults
  # options: options (2nd-level arguments) for lightview, that differ from or add to the defaults
  def show_lightview( url_options, parameters, options = {} )

    # get hold of the default options and merge in what is passed in to this method
    lightview_options = get_default_lightview_options
    lightview_options.merge!( options )

    # get hold of the default parameters
    lightview_params = get_default_lightview_params
    #  merge in any paramters passed in
    lightview_params.merge!(parameters)
    #merge in the href and options(from above)
    lightview_params.merge!( 
      { 
        :href => "'#{escape_javascript(url_for(url_options))}'",
        :options => options_for_javascript(lightview_options)
      }
    )

    # return js to show the lightview 
    "      
      Lightview.show(
        #{options_for_javascript(lightview_params)}   
       );
    "

  end

  # returns js to hide a lightview
  def close_lightview_js
    "Lightview.hide();"
  end

  # appends javsascript to hide a lightview to the page
  def close_lightview_rjs
    page<<close_lightview_js
  end

  private 

  # a default set of parameters for showing a lightview 
  # (top-level arguments -see comments at top of file)
  def get_default_lightview_params
    {
      :rel => "'ajax'",
    }
  end

  # a default set of options for showing a lightview 
  # (2nd-level arguments -see comments at top of file)
  def get_default_lightview_options
    {
       :autosize => true,
       :ajax => options_for_javascript({ :evalScripts => true }) # this is so any js in the displayed page is available (e.g. for autocompleter)
    }
  end

end

4. Change the get_default_lightview_params and get_default_lightview_options methods to reflect what you want your defaults to be.

5. Add a method to the application helper:

def use_lightview
    # Avoid multiple inclusions
    @content_for_lightview_css = "" 
    @content_for_lightview_js = "" 
    content_for :lightview_css do
      stylesheet_link_tag "/javascripts/lightview/css/lightview.css"
    end  
    content_for :lightview_js do
      javascript_include_tag "/javascripts/lightview/js/lightview.js"
    end
  end

6. In the application layout (views/layouts/application.rhtml), yield the appropriate contents.

<head>
  <!-- ... -->
  <%= yield :lightview_css %>
  <%= javascript_include_tag "prototype" %>
  <%= javascript_include_tag "scriptaculous" %> 
  <%= javascript_include_tag "effects" %> 
  <%= javascript_include_tag "controls" %>
  <%= yield :lightview_js %> 
  <!-- ... -->
</head>

7. Now, just use the helper methods in your views. e.g.

<% use_lightview -%>
<%= link_to_lightview(
        "link text", 
        {:controller=>'my_controller', :action=>'my_action', :id=>my_id}, #url options
        {:class => "whatever"}, # html options
        {:title => "'Add type'"}, # lightview params
        {:autosize => false, :width => 100, :height => 200} # lightview options
      )%>   

See the Lightview website for details of all the configuration options. Note that the configuration in the lightview.js file (in public/javascripts/lightview/js) is for all lightviews. If you need multiple versions of these settings, just make another lightview folder with a different name, and adapt the helper methods.

If you want to open two (or more) lightviews in succession (e.g. for a wizard), just link to another lightview from inside the first. The lightview will just resize and show the new content.

Technorati Profile

16 comments | no trackbacks

Update on Rails on OS X Leopard

Posted by Ric Tue, 17 Jun 2008 13:44:00 GMT

A few months ago I posted an article on how to get rails going on OS X Leopard, in which I advocated using Macports.

MacPorts and Ruby 1.8.7

In order to solve a strange problem with my MacBook Pro, I recently re-installed Leopard from scratch. (Apple said that they had fixed the problem in 10.5.3, but sometimes the problem lingered if you had been running on a non-updated version for a while. So far the problem hasn’t reoccurred, but I’m going to withhold judgment until I’ve run trouble-free for a few weeks – watch this space!).

Anyhow, I followed my own instructions in order to get my development environment back up and running again. However, Macports now installs ruby 1.8.7 by default, and it seems there is a problem with using this version of ruby with rails. When I tried to run my application, I got an error like this:

wrong number of arguments (2 for 1)
    /opt/local/lib/ruby/1.8/cgi/session.rb:267:in `respond_to?'
    /opt/local/lib/ruby/1.8/cgi/session.rb:267:in `initialize_without_cgi_reader' 
    /opt/local/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/cgi_ext/session.rb:39:in `initialize'
    ...

I couldn’t figure out how to get Macports to install a previous version of ruby. Note that this doesn’t work:

  sudo port install ruby @1.8.6

If anyone knows how to do this, please leave a comment! Maybe I’m being stupid.

UPDATE 19th June 2008: You might want to check out this post by Sho Fukamachi for tips on how to fix Ruby 1.8.7

UPDATE 1 July 2008: Check out my latest blog post for more info on reverting to 1.8.6

Hivelogic

At least with Macports, I could just delete the /opt/local folder and start again. So, I reverted back to using Dan Benjamin’s instructions on HiveLogic so that I could install ruby 1.8.6. Dan’s procedure works a treat, except that I recommend defining the path in ~./bash_profile instead of ~/.bash_login. (See the first comment on his article, and this).

Netbeans 6.1

Since I wrote the original blog article, Netbeans 6.1 has been released. Most of the settings are the same as for version 6.0, but there are few new bits:

For the fast step-through debugging, you need to make sure you have the right versions of ruby-debug installed, i.e. ruby-debug-base 0.10.0 and ruby-debug-ide 0.1.10

You also need to make sure your ruby platform is set up under Tools->Ruby Platforms, and tell Netbeans to use this platform by going to Build->Set Main Project Configuration->Customize.

I’ve noticed a couple of bugs in Netbeans 6.1, such as not refreshing the svn properties every time (work around this by choosing show changes from the Subversion menu before committing), and forgetting some editing preferences. Hopefully these will be fixed soon.

1 comment | 1 trackback

TinyMCE WYSIWYG Text Editor on Rails

Posted by Ric Mon, 16 Jun 2008 12:14:00 GMT

In Swirrl, we needed users to be able to easily create formatted text. For a time, we toyed with using a markup language such as Textile, but decided that only techies would really be comfortable with writing in a markup language, and we wanted our app to be as accessible as possible.

Basically, what we needed was a WYSIWYG (what you see is what you get) editor. We looked into a couple of options but eventually settled on TinyMCE. This is a really flexible javascript-based text editor, which is already used in many applications on the web. It simply produces html, and provides a way for techie users to edit that html directly if they want, but ‘normal’ users don’t have to worry about any markup.

After reading the rails wiki, the TinyMCE wiki and playing around a bit, I found it quite easy to integrate into our rails application. There’s quite a lot of suggestions on different ways to go about this, so I thought I’d document what worked for me…

1. Download TinyMCE

2. Make a new folder in your rails app: ‘public/javascripts/tiny_mce’

3. Copy the contents of the ‘jscripts/tiny_mce’ folder from the download into this new folder in your rails app. (So now you should have a folder in your rails app: ‘public/javascripts/tiny_mce/’ which contains the ‘langs’, ‘plugins’ and ‘themes’ folders, amongst other things.)

4. Make a new file: ‘public/javascripts/mce_editor.js’ and add your TinyMCE initialisation code, e.g.

tinyMCE.init({
    theme:"advanced",
    mode:"textareas",
    plugins : "safari",
    ...
});

(Get more information on the TinyMCE API and configuration options from the TinyMCE wiki)

5. Add a method to the application helper
def use_tinymce
    @content_for_tinymce = "" 
    content_for :tinymce do
      javascript_include_tag "tiny_mce/tiny_mce"
    end
    @content_for_tinymce_init = "" 
    content_for :tinymce_init do
      javascript_include_tag "mce_editor"
    end
end

6. In the application layout (views/layouts/application.rhtml), yield the appropriate contents. According to this TinyMCE wiki page the order of javascript files is important.

<head>
  <!-- ... -->
  <%= javascript_include_tag "prototype" %>
  <%= yield :tinymce %>
  <%= javascript_include_tag "scriptaculous" %> 
  <%= javascript_include_tag "effects" %> 
  <%= javascript_include_tag "controls" %>
  <%= yield :tinymce_init %> 
  <!-- ... -->
</head>

7. Now, to use tinymce in a view or layout, just make a call to the new helper method e.g.

  <% use_tinymce -%>
  <%= textarea_tag :foo, :bar, ... :class => "mce-editor" %>

8. Although TinyMCE does do some tidying up of the html code, you will also want to add white-listing to your implementation to prevent people submitting anything dodgy. (Note that for some of the more advanced TinyMCE formatting, you will need to allow the “style” attribute in your whitelist).

Gotcha: If you want your users to be able to post xml code in their text areas, you will have to use the xml encoding option, and decode that content if you’re showing it outside of a TinyMCE editor anywhere e.g:

  <%= white_list(CGI.unescapeHTML(@page.content)) -%>

(Note: I found that this option doesn’t work correctly in TinyMCE version 3.0.8 but is fixed in 3.0.9)

23 comments | no trackbacks

Wikinomics

Posted by Ric Wed, 11 Jun 2008 16:18:00 GMT

I’ve just finished reading Wikinomics by Don Tapscott and Anthony D. Williams.

I posted an entry over at the Swirrl Blog with some views on its contents:

In all, I thought it was a good read with some great insights into how business is evolving, but the edition I read was published in 2006 and such is the rate of developments in this area, some references and examples felt dated… (Read the rest of the article)

no comments | no trackbacks

My name is Ric and I'm a coffeeholic

Posted by Ric Wed, 11 Jun 2008 08:47:00 GMT

coffee

Being a self-confessed coffee addict, I found this article interesting.

It’s slightly off-topic for this blog, I know, but most programmers can’t survive without their caffeine hit, so I thought it might appeal.

(Coffee image by Klaus Post)

no comments | no trackbacks

Older posts: 1 2 3 4 5 ... 13