Rob's Blog - March 2009
Contents
Here are Rob's Blog entries for March 2009.
Blog entries for other months can be found in the main blog index.
One of the most popular stories on this website is on Alternating Table Rows With Template Toolkit And CSS. The example I use is how to stripe alternate rows in an HTML table by applying a seperate class to each row.
As I've been learning jQuery lately, I thought I'd update this example to show how to do it using this excellent JavaScript framework.
Firstly, we need to setup our styles. We'll have a lite and a dark class to use that will just set a different background colour.
<style type="text/css">
.lite {background-color: #ddffff;}
.dark {background-color: #aaffff;}
</style>
We'll also need an example table.
<table class="stripe">
<tbody>
<tr>
<td>1</td><td>One</td>
</tr>
<tr>
<td>2</td><td>Two</td>
</tr>
<tr>
<td>3</td><td>Three</td>
</tr>
<tr>
<td>4</td><td>Four</td>
</tr>
<tr>
<td>5</td><td>Five</td>
</tr>
</tbody>
</table>
Notice how I have given the table a class of stripe. This is important, I'm going to use jQuery to only select table elements that have this class name, else every table on the page would be striped.
The jQuery to achieve the striping is actually very simple.
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$('table.stripe>tbody>tr:even').addClass("lite");
$('table.stripe>tbody>tr:odd').addClass("dark");
});
</script>
Firstly we added the jQuery library to the page. Next we setup our striping code to only run once the DOM is place. This is important as we're going to be selecting and manipulating over the DOM next. The next two lines apply the lite class to even table rows and the dark class to odd table rows. Let's look at this in a bit more detail.
The selector $('table.stripe>tbody>tr:even') is easier to explain backwards. We look for even matching tr elements, that have a parent of tbody, that has a parent of table with a class of stripe. The use of the > symbol instead of just a space is to make sure the elements are direct parent and child elements instead of just ancestor and descendant. Why is this important? Well if we used a space any nested tables that happened to have an striped ancestor would also be striped. This isn't normally what we'd want to happen.
Entered: 2009-03-19 11:45:24
Modified: 2009-04-03 18:51:16
Bookmarks from del.icio.us
Entered: 2009-03-19 00:15:08
You know the story, you've inherited a lovely design and XHTML page build from your designer. The pages are modular and built using server side includes (SSI). The site is easy to update, until you're asked to make something dynamic.
Normally, I'd use Perl's excellent Template Toolkit, and just convert the SSIs to Template Toolkit INCLUDEs. However in this case, the SSIs were nested so I couldn't take this approach.
The solution turns out to be quite easy, especially as I'm using Apache 2 as my webserver.
Apache 2 has output filters, so I can get the output of my CGI scripts to be parsed by Apache for SSIs directly using mod_include.
In my apache conf file, I need to do something like the following.
<Location /cgi-bin/withssi/>
SetHandler cgi-script
SetOutputFilter INCLUDES
Options +ExecCGI +Includes
</Location>
This will turn on SSI parsing on the output of CGI scripts served from the location of /cgi-bin/withssi.
The key line to notice here is SetOutputFilter INCLUDES as that makes sure the output returned is parsed by mod_include before it reaches the web browser.
Entered: 2009-03-17 09:34:36
In the previous article Knowing When It's Safe To Talk To Flash From JavaScript we saw how to call Flash from JavaScript.
We embedded the Flash movie directly into the page, however there are times when we may want to insert the movie dynamically using JavaScript. How can we do this?
Well it turns out fairly easily, especially if we use one of the modern JavaScript framework libraries like jQuery.
jQuery is very extendable, and has a powerful plugin based architecture. Thankfully someone has done the hard work for us and written a plugin to handle the embedding of Flash. Take a look at the jQuery.flash plugin.
How do we use it, well first we need to add the two libraries to the page, jQuery and jQuery.flash.
<script type="text/javascript" src="jquery-1.3.2.js"></script>
<script type="text/javascript" src="jquery.flash.js"></script>
In our page body, we'll add a bit of HTML that will have it's content replaced by the Flash movie.
<-- the content of the following div will be replaced. -->
<div id="example">Flash here</div>
Now let's add the JavaScript that will replace the div's content. We'll wrap it inside jQuery's ready function to make sure everything we need is in place. This is a better version of the window.onload function we saw in the previous article that waits until the page can be manipulated, and not until everythting has been downloaded.
$(document).ready(function() {
$('#example').flash(
{
src: 'test.swf',
height: 1,
width: 1,
flashvars: {onLoad: 'flashLoaded'}
},
{ version: 8}
);
});
This creates the object or embed as necessary, and loads the movie "test.swf", with a height and width of 1 pixel and the flashvars parameters we saw in the previous article. In this case, the onLoad parameter has a value of flashLoaded, the name of the function we want to call when the flash has loaded and is ready to execute. There is also a parameter saying the minimum version of the Flash player we need, let's use version 8 here.
Now when the page is loaded, the <div> block will be replaced with the flash movie, and this in turn will call our callback function flashLoaded.
Update: Using Mootools
Mootools is another excellent JavaScript framework library, and it has Flash support built into it's core using the Swiff class.
For Mootools, firstly we need to make sure it's loaded.
<!-- load the mootools library -->
<script type="text/javascript" src="mootools.js"></script>
Now we'll wrap our Swiff object creation in Mootools domready event. This is the equivilant to what we did earlier in jQuery with the ready event.
window.addEvent('domready', function() {
var flash = new Swiff('test.swf', {
container: $('example'),
width: 1,
height: 1,
callBacks: {
onLoad: flashLoaded
}
});
});
Here we're creating a new Swiff object, and telling it to place the flash object / embed tag it creates inside the div with the id of example like we did with the jQuery example. We specify the height and width both of 1 pixel and setup the callback.
As you can see, Mootools specifically calls this a callback unlike jQuery's flashvars. They mean the same thing here, so we say the onLoad callback function in the Flash movie's ActionScript will call the local JavaScript function flashLoaded.
Entered: 2009-03-16 18:54:59
Modified: 2009-03-16 21:36:43
I've been doing some work lately where JavaScript in an XHTML page needs to talk to some ActionScript 3.0 in a Flash movie.
The most common problem here is knowing when you can start talking to the Flash movie. The browser may have loaded all the scripts and started to execute them, but the flash movie may not have loaded or initialised at that point. If you try to talk to the movie at this point, you'll get errors.
There are a couple of ways around this. You could code the flash movie into the page using <object> and <embed> html tags, then make sure your JavaScript calls the movie after the onload event has been called. E.g.
function flashLoaded() {
alert("Flash loaded");
}
window.onload = function() {
// flash should have loaded by now.
flashLoaded();
}
Now that isn't ideal, the flash may have loaded, but the movie may not have initialised so you could still have problems.
The safest way is to include a callback function in your ActionScript that runs once the movie has finished initialising. This will call some JavaScript on your page letting you know the movie has loaded and can be interacted with. We can use the ExternalInterface class in the ActionsScript to achieve this.
Let's assume our ActionScript class is called test, and we have a function in our JavaScript called flashLoaded. The following code is a quick way to let the JavaScript know the movie has loaded.
public function test():void
{
ExternalInterface.call("flashLoaded");
}
This is great, but it does mean we've had to hardcode the name of the calling function. What if we had two Flash movies in the page and they both called this function. This could cause problems. We need a way to pass in a function name dynamically.
Flash has something that used to be called FlashVars that can help us here. It's basically a list of parameters and values that are passed and appended as a query string to the end of the movie files name. These are then available to ActionScript. In our object we alter the movie paramter accordingly.
<-- in the flash object tag -->
<param name="movie" value="test.swf?onLoad=flashLoaded" />
If you use the embed tag, make sure you alter the movie parameter there as well.
To see the passed parameters in ActionScript was need to use root.loaderInfo.parameters. Our initialiser function should be altered to use the following code, in this case we want to use the onLoad parameter.
public function test():void
{
ExternalInterface.call(root.loaderInfo.parameters.onLoad);
}
Great, we can now vary our the name of our callback. However problems could still occur. The movie may be loaded but the stage may not be ready. We need to add a little bit more wrapping code to handle this. The following code should do the trick.
package {
import flash.display.Sprite;
import flash.events.*;
import flash.external.ExternalInterface;
public class test extends Sprite
{
public function test():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
public function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
ExternalInterface.call(root.loaderInfo.parameters.onLoad);
}
}
}
As you can see we've moved the callback into the init function, and this is only called when the stage is ready.
You should now be safely able to script your flash movie from JavaScript.
See Knowing When It's Safe To Talk To Flash From JavaScript - Part 2 for examples on how to integrate this with a modern JavaScript library like jQuery.
Entered: 2009-03-12 18:35:55
Modified: 2009-03-16 20:34:55
Bookmarks from del.icio.us
Entered: 2009-03-11 00:15:07
I've been using Catalyst quite a bit recently. For those of you who don't know what Catalyst is, the easiest buzzword compliant comparison is Ruby On Rails for Perl.
Normally in Catalyst if you want to break the flow from a current method, you use the forward method of the catalyst object to internally redirect to a new handler.
Imagine I have a handler responding to requests at /test.
If I want my request to be dealt with by the handler at /robspage I can issue a forward request in the handler at /test like this...
$c->forward($c->uri_for('/robspage'));
## code will continue here.
Once the code at /robspage has run, control returns to the calling handler.
This isn't always what is needed, if I don't want the handler to return and keep running I would need to use the detach method instead.
$c->detach($c->uri_for('/robspage'));
## code will not continue here.
This is great, however, the calling URL will not change and the user will not know they are actually seeing /robspage instead of /test. Sometimes this is the behaviour we want, however in this case I want the user to know a redirect has happened and for this to be reflected in their browser.
To achieve this, we have to use the redirect method of the the response object.
$c->res->redirect($c->uri_for('/robspage'));
$c->detach();
Note that I have added a $c->detach(); call after the redirect as I don't want the processing chain to continue.
Entered: 2009-03-06 10:04:21
Modified: 2009-03-06 10:17:53