Simple Modal Boxes: FaceBox with Prototype

August 28th, 2009 by Harisenbon Leave a reply »
alertI’ve updated my code with a newer version: Version 1.2 which includes such awesome things as full IFrame support and better support for classes and styles! You can check out the Article, or just download the code from here! The way the code is used has been changed, so be sure to read the README!

This article will teach you how to:

Open facebook-styled modal windows in both alert box and full ajax-styled version, using the FaceBox modal window script and Prototype.

I wanted my signup page for Ippatsu, an online Japanese learning application, to use a modal window for the sign up dialog. This allows me to use most of the visible area for copywriting, while not requiring a page transition to load the signup form.
You can also create modal windows like these with Prototype and the OSS code I’m releasing below.

Ippatsu's Flashcard FaceBox

Ippatsu's Flashcard FaceBox

A little history

Originally these modal boxes were used mainly for photogalleries and whatnot, and took up the entire screen with a cool faded out background and had a lot of animations. Probably the nicest and most well known was PhatFusion’s lightbox and multibox which are written on the MooTools javascript library.

As time went on, people wanted simpler boxes that did away with all the animation and crap and so extremely simple boxes like Particletree’s Lightbox Gone Wild which is a simple box with no animation over a 70% black border. It’s small, simple and gives a rather nice effect.

So what’s the problem?

Well, the problem with animation should be obvious: It’s slow and can be jerky on certain browsers. Definately not something you want to use for a UI Element.

And the issue with the background is that when you have your entire site blacked out, while you gain focus on the window you’ve just put up, it’s not very useful for information that you want to give the user without preventing them from seeing the rest of your site. In other words, we want a Modal Window instead of a lightbox type thing.

So Bring on the Modal Windows!

As far as this discussion is concerned, I’m going to be ignoring the windows-like full modal windows that allow dragging and dropping and whatnot, and only focus on simple Modal Boxes that can be used to display data. In particular, FaceBox.

Get to the Code Already

Ok, so FaceBox is a JQuery based modal window that is pretty much copied from the facebook site where they use it to display small bits of ajax text. It is amazing. You can get it at http://famspam.com/facebox . However, it only works with JQuery, whose existance I was not aware of at the time of creating my site, so I had to find a Prototype version.

FaceBox Prototype in google gave me a couple of good links, the most popular being Phill Burrows’ blog in which he ported FaceBox from JQuery to Prototype. Unfortunately, the post (and code) is rather old, and did not work on the newest version of Prototype that I was using (1.6.0.3).

Eventually I came to two guys who took Phill Burrow’s code and updated it: Robert Gaal and Scott Davis. Both seem very nice, but I was having some problems with the slightly older Robert Gaal version, and so decided to go with JetViper’s version, as it also proposed to have class support.

Unfortunately there were a few large problems with the FaceBox code as it as written:

  1. The code did not support class definitions of the FaceBox like it purported to (because of a coding error)
  2. There was no way to set the size of the FaceBox from code
  3. If the page being loaded was really long (such as having cakephp debug information) the window would stretch to fit all the contents height-wise, without scrolling
  4. No iframe support, so loading a page with javascript borked the load.
  5. No Close on Escape button

So I dug into the code and made some changes, and was able to fix problems 1-3 and 5 (and am still working on 4). The entirety of the code can be downloaded at the bottom of this page.

Fixing the classes

Looking at the original .js (line 175), you can see that Scott’s code says that you can add a class to the FaceBox content by changing the rel tag in the link to “facebox[.my_class]”

// support for rel="facebox[.inline_popup]" syntax, to add a class
var klass = elem.rel.match(/facebox\[\.(\w+)\]/);
if (klass) klass = klass[1];

Unfortunately, due to the way that FaceBox searches for FaceBox-enabled links, it will not recognize “facebox[.my_class]” as a FaceBox, as it looks for a direct match with rel=facebox.

So, I fixed that bug by changing line 93 in the watchClickEvents from

$$('a[rel=facebox]').each .....

to

$$('a[rel|=facebox]').each .....

The |= selector is a CSS Selector (valid in prototype) that allows you to define that The attribute’s exact value is “facebox” or starts with the word “facebox” and is immediately followed by “-”, so it would be “facebox-”. You can read more about Attribute Selectors at Smashing Magazine’s Taming Advanced CSS Selectors. It’s an amazing read. You can also learn about ~= (whitespace seperated) ^= (starts with) $= (ends with) and *= (contains) all of which are valid types of CSS selectors.

But wait, you say! How does “facebox-” translated to “facebox[.my_class]“?!?

It doesn’t.

I find facebox[.my_class] to be really unwieldy, so I changed it to facebox-my_class. This way, you can also put additional rel data in the link if you need, as long as facebox comes first.
All of these are valid:

rel="facebox-my_class help"
rel="facebox-my_class"
rel="facebox"

So, in light of this, we have to change the regex match in the click_handler from:

// support for rel="facebox[.inline_popup]" syntax, to add a class
var klass = elem.rel.match(/facebox\[\.(\w+)\]/);
if (klass) klass = klass[1];

to

// support for rel="facebox-inline_popup" syntax, to add a class
 var klass = elem.rel.match(/facebox\-(\w+)/);
 if (klass) klass = klass[1];

And then in your CSS to use the class:

#facebox_content.my_class{
 height: 300px;
 width: 500px;
 }

Done and done!

(As a smaller bug fix, I noticed that the original code never deletes previously added classes — only appends them, so I added this line to the reveal function to make sure that the classes were reset each time you opened a FaceBox

contentWrapper.className = 'content';

Stylize that Sucker!

So, problem 2 is that FaceBox has no way to stylize the lightwindow contents on a per-link basis — you have to define a whole new class for each type of lightwindow that you want. This in itself is not so bad, but it would be nice to have that slight extra amount of customizable power.

So, what I did is just add a “style” variable to each of the reveal/ajax/etc function calls, and had it append that style to the facebox_content div.

reveal    : function(data, klass, style){
....
//Set H/W or any other styles (also clears styles)
 contentWrapper.writeAttribute('style', style);
....

If you’re calling the lightbox from code, you just add whatever style attributes you want to the call

facebox.ajax('mypage.html', 'my_class', 'height:300px;width:400px;'

If you’re using the automatic calling from the rel tag, then you have to add a rev tag, and put your stylesheet in there. Anything you put in the rev tag will be copied to the style attribute of the contentWrapper

<a href="mypage.html" rel="facebox-my_class" rev="height:300px;width:400px">Link</a>

Simple as that!

(It should be noted however, that the height and width of the content_window does not take into account the borders, padding and footer of the FaceBox, so be sure to leave yourself a little margin of error)

No Scrollbars?!?

You still with me? It’s been long, I know, but just hang with me a little more. This is the last point.

So, as I said earlier, there’s a problem(?) with FaceBox wherein long content just makes the FaceBox longer until all the content is shown. As this system is made for display quick banners and small ajax pages and what not, it’s understandable that it would be left out, but why not put it in when it’s so damn simple?

So how do you do it?

//facebox.css
#facebox_content{
 overflow: auto;
 }

That’s it.

What this does is allows the FaceBox to extend to show all the content normally, but if you decided that the FaceBox needs a certain height (through a class or styling) then the FaceBox will be set to that height, and anything that goes over that height will be scrollable.

That Damn Simple.

In Conclusion

Not much of an “In Conclusion.” I’ve pretty much said all I want to say, so all there is left is to check out the codes~

If you find any problems or bugs, feel free to drop me a comment!

alertI’ve updated my code with a newer version: Version 1.2 which includes such awesome things as full IFrame support and better support for classes and styles! You can check out the Article, or just download the code from here! The way the code is used has been changed, so be sure to read the README!

Download FaceBox v 1.1 (Open sourced under the MIT License)

Advertisement

6 comments

  1. Robin says:

    Thanks for this great script.
    I’m trying to get this to work in a project I’m working on, But i’m only able to show static images.

    loading a page via Ajax does not seem to work, any hints for me?
    many thanks..

  2. Harisenbon says:

    One thing you need to be careful of when loading AJAX is that you need to make sure that you are loading only PART of a page by ajax, not the whole thing (Head, body, etc). Because at current the data loads into a DIV and not an IFRAME, if you try to load another full page, the Javascript and HEAD tags start fighting with each other, and end up not displaying correctly.

    I’m working on an iframe version as well (because I want to use this for my paypal-processing) but the current version is more geared towards small forms, alerts, etc, rather than a full sub-browser. I’ll definitely post the new version when it gets finished!

    Ok. It’s finished. ;)
    Try checking out the new version and how to use it.

  3. Robin says:

    Ah, Yes, I forgot about the full page stuff (using cakePHP also, I just needed to render my view as ajax.)

    The newer version will be quite useful as I will need to integrate paypal at some point..

  4. Harisenbon says:

    I’ve noticed that in some instances my views are being automatically rendered in my ajax layout as long as they’re made through an ajax request.
    However, it’s really one of those “Sometimes it works / Some times it doesn’t” things, and I haven’t figured out the rhyme or reason to it yet…

  5. Robin says:

    Hi, I’m currenty using facebox in my project, but I have one issue, not directly related to facebox, but I think you might know the solution..

    Facebox initialised when the page has finished loading, and attaches to the hrefs with the correct class.

    This works fine.

    but I have a portion of my site that loads search results using ajax.
    in the ajax result I have another set of href links that I also want to display in a facebow pop-up.

    My javascript knowledge is too limited to also initialise the facebox when the ajax requedt completes?

    Any Idea’s on how to get this to work?

    many thanks.
    Robin

Leave a Reply