Popouts with Rails

In a previous article about Stuff To Do, my ajaxified priority queue program, I talked about how best to keep track of the user’s state of activity, should they so desire.

I opted for the popup, as that was the best compromise between simplicity, and ease of use for the end user. From an end-user point of view, it’s similar to how gtalk can detach from gmail if you want to run it in its own window.

The trick was to implement the popup/popout in Rails, which actually ended up being pretty easy, and, all things considered, is a pretty cool technique. It’s neat to pop stuff in and out of a web page.

The easy part is popping out the window:

<%= link_to_remote("Pop out " + image_tag('popout', :border => 0),
                   {:url => { :controller => 'tasks', :action => 'popout' } },
                   :title => 'Pop the status window into a popup window') -%>

Which subsequently calls popup.rjs:

page.replace_html('status', "<i><small>status in popup window</small></i></br>" +
                  link_to_remote("<small>Restore</small>",
                                 {:url => { :controller => 'tasks', :action => 'popin' }},
                                 :title => 'Restore the status window'))
page << 'statuspopup();'

Which is pretty simple – the first call replaces the html in the status div, and the second calls the javascript function statuspopup. This lets us replace what was in the status window with some placeholder text and a ‘restore’ link in case things get screwy and the user wants to simply restore the old content of the div in question. It’s worth noting that we also store the popped out status in session[:popped_out] in order to let the application know that the window is “popped out”.

This doesn’t actually pop the window itself up. The statuspopup function in javascript (located in application.js) takes care of that:

function statuspopup() {
  window.newwindow = window.open('/tasks/openstatus','status',
                                 'height=10,width=210,status=no');
  return false;
}

And then the openstatus action opens the same rails partial that the regular page does:

<%= render(:partial => '/tasks/status', ...

Meaning that you don’t have to rewrite the same code in two places.

So, that’s all it takes to pop up a new window, and replace the contents of the old div in the html page giving the user the sense of having popped a piece of the page out into a popup.

So far so good. Now what happens when the user closes the popup? Luckily, we get a reference to the window that opened the popup called window.opener that we can use to comunicate with the main window. For instance, in our case we set up an event listener to fire when the window closes:

window.addEventListener("unload", statusClosed, false);

And this, in turn, takes care of popping the window back into the main page:

function statusClosed() {
new Ajax.Request('/tasks/popin', { method: 'get', asynchronous: false })

$('popoutlink').style.display = 'inline';
w = window.opener;
target = w.window.document.getElementById('status');
code = $('onidle').childNodes[1].innerHTML;
target.innerHTML = $('status').innerHTML;
target.style['backgroundColor'] = '#bbddbb';
target.style['backgroundColor'] = '#bbddbb';
w.eval(code);
}

Once again, pretty simple. What’s happening:

  • Ajax.Request just takes care of letting the rails app know that we’ve popped in, which resents session[:popped_out].

  • Then grab the window opener, and find the status element within that window.

  • Instead of re-rendering everything with a rails partial, we simply transfer the HTML that was residing in our popup to the main window:

    target.innerHTML = $(‘status’).innerHTML;
    target.style[‘backgroundColor’] = ‘#bbddbb’;
    target.style[‘backgroundColor’] = ‘#bbddbb’;

We also fix up the color just a bit, to mark the user as active.

All in all, it’s pretty useful for time tracking. In Linux, it’s ver easy to set the new popup to follow you around the screen, making it so that it’s not a bother at all to wave the mouse at it to let the application know you’re online. All you do is set the ‘on top’ and ‘always on visible workspace’ options – at least in Gnome.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s