Posted: April 1st, 2007 | Author: Panagiotis Karageorgakis | Filed under: jQuery | 16 Comments »
jQuery is a very popular JavaScript library among web developers, gaining more and more fans as it evolves. It’s fast, lightweight and does many things while being unobtrusive, meaning that no code has to be incorporated in an (X)HTML document’s body. This way, the designer can write the code, and then go to the document’s head and add a few lines of code to do some fancy stuff with the document. Between the several built-in effects are the popular fade-in and fade-out effects that, due to the chainablity of jQuery can be used sequentially, for a fade-in-then-fade-out effect.
Chainability, is the ability to “chain” different methods on an object, like this:
Chainability in all its glory
$("#foo").show().hide();
which will just show and then hide the element with the id “foo”.
Fade-in-fade-out
Using the concept of chainability, we can achieve a fade-in-fade-out effect easily:
A simple fade-in-fade-out
$(document).ready(function() {
$("#foo").fadeIn(2000).fadeOut(2000);
});
The above fragment of codefades in the #foo element with a duration of 2 seconds (2000 milliseconds — the argument is in ms), then it fades out the element. The duration of the fade-out effect is another 2 seconds. But what happens if we wanted to have a delay, between the fading-in and fading-out of the element? Say, for example, that we want to fade in the element, then keep it that way for 5 seconds, and then fade it out again.
Intuitively, the “I-dont-read-documentation-but-guess-my-way-around” kind of developer would try to chain a delay effect, like this:
We wish we could do this…
$(document).ready(function() {
$("#foo").fadeIn(2000).delay(5000).fadeOut(2000);
});
However, this won’t work, simply because there’s not a delay() function. The outcome would be for the element to fade in, and then do just nothing, since the script encounters a function that is non-existent and just stops there. So how can we achieve that?
The trick
Let’s think of what happens during the fadeIn() function: the JavaScript alters the opacity property of an element, from zero to 1, which corresponds to a transition between 0% and 100% of opacity. The fadeOut() function does the reverse: changes the opacity property gradually from 1 to zero. There’s a third function named fadeTo(), which fades the given element to a specific opacity that is passed to it as an argument. For example, the following line of code would make the #foo element go from total invisibility to 50% opacity (the effect will last 3 seconds):
Fade from completely opaque to 50% visible
$("#foo").fadeTo(3000, 0.5);
The trick is to simulate the delay by applying a fade-in (or fade-out) effect that does not change the opacity of an element, but rather spends it’s time doing nothing. The concept is as follows:
- Fade-in the element from 0 opacity to 1, for 2 seconds
- Fade-in the element again from 1 opacity to 1, for 5 seconds
- Fade-out the element from 1 opacity to 0, for 2 seconds
This way, we just insert a transition that last 5 seconds but does not change the opacity of the element, since the target opacity has the same value as in the current condition. The code would just be as simple as this:
The trick is to use the fadeTo() effect!
$(document).ready(function() {
$("#foo").fadeIn(2000).fadeTo(5000, 1).fadeOut(2000);
});
As Karl Swedberg correctly stated in a comment below, the same effect can be achieved by using the animate() effect, i.e.: .animate({opacity: 1.0}, 3000)
Delaying an effect before it begins
Now, let’s alter the desired effect a little bit. Let’s say that, our foo element is rather shy; it doesn’t want to appear just as the page loads, but would rather give the reader some time to settle in, before it intrudes in the page. A few seconds would be enough for our element to feel comfortably, so we want to give it 3 seconds time until it appears. How do we do this? Intuitively we would expect something like the following code to work:
(This is not the right way to code what we want)
$(document).ready(function() {
$("#foo").fadeTo(3000, 0).fadeIn(2000)
.fadeTo(5000, 1).fadeOut(2000);
});
Previewing this in our browser, we see that it’s not what we expected. Foo shows momentarily, then disappears, waits, and then begin to fade in. But why did foo make a quick appearance and then disappear, before it does it’s part? Maybe it wanted to peek and see who the viewer is, but I bet there’s a better explanation, and there is one: the original opacity of it was 1, so fading to 0 creates a transition (a short one) to the target opacity.
[Edit: The following part of this section of the document has been updated to add support for internet Explorer 7]
Here’s a way to achieve this effect. This method has been tested in Safari and Firefox 2 for the Mac, as well as Firefox 2 and IE 7 for Windows. The trick here is to initially hide the element, not by altering it’s opacity, but rather by taking it out of the document flow. This can be done the same way designers choose to hide accessibility text, by creating a class like the following:
Create a .hidden class
.hidden {
position: absolute;
top: -10000px;
}
Then all we have to do is this: apply the class to our element, create a fadeTo transition that takes the desired time, remove the class from the element then go on with our normal effects. To make a long story short, in order to have all the aforementioned browsers support this, we must keep in mind two things:
- Use fadeTo() effects to substitute fadeIn() and fadeOut() effects (e.g. fadeTo(”normal”, 1) is the same as fadeIn(”normal”) )
- Use the remove class attribute as the delaying transition’s callback function
In a nutshell, if we want to have an element delay 3 seconds, fade in, wait another 3 seconds and then fade out, here’s the proper code:
The right way to do it
$("#foo").addClass("hidden").fadeTo(3000, 0, function() {
$(this).removeClass("hidden")
}).fadeTo("slow", 1).fadeTo(3000, 1).fadeTo("slow", 0);
Now, if anyone’s kind enough to try this with Internet Explorer 6 or below, plase let us know by leaving a comment.
You can see a real world live example of this behaviour in a simple intro page (that has inspired me to write this article). Three seconds after the page loads, an image containing some text appears above the graphic, waits for 2 secs and fades out.
Posted: March 7th, 2007 | Author: Panagiotis Karageorgakis | Filed under: CodeIgniter | No Comments »
The problem
Enhancing an existing web app built with CodeIgniter (or Code Igniter, or CI for short), I wanted to add an automatic e-mail message functionality. This way, when the contact form is submitted, except for the inquiry being presented in the administrative backend, an e-mail would be sent to the site’s owner address to notify them that someone wants to contact them.
Reading the CI manual, I was fascinated to see how easy this is to implement. I injected a few lines of code in my controller and tested it locally. Voila, it worked! And I didn’t have to configure anything. This was awesome, but let’s try it at the server too, shall we?
The production server, utilizing a shared hosting environment in a VPS, was expected to be more strict in such matters, and it turned out it was. The same set of code returned the following error:
Message: mail(): SAFE MODE Restriction in effect. The fifth parameter is disabled in SAFE MODE.
Obviously, PHP’s safe mode is on, and this seems to be troubling the mail code. But turning safe mode off, in order for this to work, is not a good idea. Even if it’s not turned off for the whole server but just for this site, still that would somehow weaken the security of the website. So an alternate solution had to be found: a way to make CI work with safe mode.
The solution
After googling about this problem with no results, I was lucky to find out the solution is really simple. It turns out that CI code has already predicted this, and all you have to do is to tell it that safe mode is on. That can be done quite easily, by changing the following line in the system/application/libraries/Email.php file:
bq. var $_safe_mode = FALSE;
should be changed to
bq. var $_safe_mode = TRUE;
That’s it! You can now send mail from within a controller with no problem. (Don’t you wish though, that this was documented?)