Archive for April, 2009

WebGUI Survey goodies

April 9th, 2009

Kaleb (aka perlmonkey2) and I have been rounding out WebGUI‘s Survey wobject with a bunch of features over the past couple of weeks. Here’s a run-down of some of the highlights:

Improved Visual Feedback

The Survey Edit page now uses “Loading…” progress masks whenever it’s busy doing something. When you’re dealing with large data sets (and slow servers) it’s really handy to be able to see when the page is busy doing loading/saving/etc..

load-mask

Multi-choice Bundles

Survey ships with a bunch of useful multiple-choice question bundles to get you going. Some of these are very generic such as Gender (Male/Female), Yes/No, etc.. Others are more specific to single domain, such as Confidence (an 11 answer scale from “0 – Not at all confident” to “10 – Extremely confident”). Of course, every site is going to want a different set of re-usable bundles. You can now create your own bundles, and add/edit/delete the default ones.

multichoice-bundles

Validation Warnings

Now that Survey is a complex beast, allowing you to do all sorts of fancy things, it pays to have some automated checking of various things that could go wrong. The Edit Survey page constantly checks your Survey instance for warnings, and alerts you if anything smells bad.. everything from using Jump Expressions when enableSurveyExpressionEngine is disabled for your site, to duplicate Section/Question variable names, circular Jump targets, all the way up to full-blown Expression Engine compilation & pseudo-execution checking.

warnings

Survey Summaries

This is a long-awaited feature curtesy of Kaleb. You can now define which answers are correct, and assign arbitraty numeric scores to them. Then, when the user reaches the end of the Survey, they get shown their quiz results – both numerically (in a YUI DataTable) and graphically (with YUI Charts).

summaries

Coming soon to this department will be the ability to display quiz summaries at the end of individual sections rather than just all at the end.

Visualisation

Meanwhile, I’ve been building a tool to allow you to visualise the branching structure of a Survey using GraphViz. Here is an example of a real-world Survey instance that has ~500 questions. Turning this into a button that allows you to generate visualisations on the fly from the Edit Survey page on your own site is just a matter of sorting out the last remaining issues with GraphViz/ImageMagick support in the wre.

visualisation

Branch Expressions

This has been the main focus of my work, and probably deserves a post all to itself. Survey now has a dedicated expression engine, which allows you to control branching using a large sub-set of the Perl language. Expressions are evaluated using Safe module, which limits what opcodes the expression can generate and limits access to only the variables that we chose to expose. Of course, even Safe.pm has caveats about what it can and can’t protect you from (for example infinite loops), so it’s important to note that the expression engine is disabled by default, and can only be enabled by site administrators in the WebGUI site config file.

When it comes down to it, branch expressions are just perl code, so you have a whole lot of power at your disposal. You can access recorded responses for the user by supplying the Section/Question variable name to the value() sub:


value(variable_name);

To actually trigger a branch, you call the jump() sub:


jump { value(q1) == 1 } section3

That says, if the user’s recorded response value to q1 has a numeric value of 1, jump to section 3.

Here’s a more advanced one:


jump { score(q1) > 5 and value(q2) =~ m/textmatch/ } section3;
jump { avg(value(q1), value(q2), value(home/anotherSurvey, q3)) > 10 } section4;

The above expression demonstrates some of the cooler branch expression features:

  • Two alternative jump clauses
  • Branching based of Question score  (if you ask for score(Section) you get the total score for that section)
  • Text matching (you have the power of Perl at your disposal after all)
  • Calling a utility function, in this case avg(). The expression engine makes available a bunch of handy utility functions, such as all of the subs from List::Util (min, max, sum, etc..)
  • Resolving the recorded response value from another survey instance altogether (the first argument to value() and score() can be an assetId or an asset url.)

Behind the scenes, the ExpressionEngine is quite nice too, telling you what it’s doing along the way, which makes debugging complex expressions quite painless.

Along with all these changes, the test suite continues to grow. Check it out in the next WebGUI beta and let us know what you think.

WebGUI Carousel Wobject

April 6th, 2009

Carousel Wobject

There’s a new wobject coming in the latest WebGUI beta (version 7.7.3), called Carousel. On the surface, it’s a nice little integration between WebGUI and YUI, but below the surface it’s a great multi-purpose tool for rendering content dynamically in Javascript or Flash.

It’s a common requirement to want to display rich text via Javascript or Flash. For example you might have a clickable diagram that shows different text depending on what part of the diagram a user clicks on.

Giving content managers access to the dynamic text can be rather cumbersome. In the worst case scenario the text is hard-coded in the Flash or Javascript source, out of reach of the content manager. Better solutions are where you have a bunch of editable Articles or Snippets that the Flash or Javascript reads from.

None of these solutions are very satisfactory though, because as far as the content manager is concerned the dynamic object is a single asset, and they really want a simple way to edit all of the text elements from the same place.

We designed the new Wobject specifically for this scenario. The Edit Screen of the wobject allows content managers to add as many rich text editor (RTE) boxes as they like (dynamically, a la FilePile). These RTEs are displayed one after the other on a single screen, allowing the content manager to edit all of the text in a single place. For each RTE, the content manager can also specify a unique ID.

carousel-edit

By default, the template for the Carousel wobject renders your RTE items into an attractive YUI Carousel widget:

carousel-view

The Wobject template does this by looping over all of the RTEs and generating markup expected by the YUI Carousel widget. This has the nice side-effect of allowing your widget to gracefully degrade in non-js browsers.

Taking a step back, we have a WebGUI wobject that lets us manipulate a collection of RTEs. The only part of the wobject specific to the YUI Carousel is the template. Let’s have a look at it:

<div class="yui-skin-sam">

...

<tmpl_if item_loop>
<div id="<tmpl_var assetId>">
<ol>
 <tmpl_loop item_loop>
	<li class="item" id="<tmpl_var itemId>">
 <tmpl_var text></li>
</tmpl_loop></ol>
</div>
<script>
 YAHOO.util.Event.onDOMReady(function (ev) {
 var carousel = new YAHOO.widget.Carousel("<tmpl_var assetId>", {
 isCircular: true,
 numVisible: 1,
 animation: { speed: 0.5 }
 });
 carousel.render(); // get ready for rendering the widget
 carousel.show();   // display the widget
 });
 </script>

</tmpl_if></div>
</script>

We can just as easily create our own template to do something else with the data. Returning to our original example, say you want to use the RTE text in a Flash diagram. All you have to do is change the template to output the contents of each RTE into a textarea dom element, styled to be hidden from view, with the id attribute set to the RTE unique id. Then, your Flash (or Javascript for that matter) can easily read in the rich text via DOM methods (e.g. document.getElementById(RTE_unique_id).value) and display it dynamically and/or do whatever it likes with it.

For example, we might use a template such as:


<tmpl_loop item_loop>
 <textarea id="<tmpl_var itemId>" style="visibility: hidden;"><tmpl_var text></textarea>
 </tmpl_loop>

The only coordination required is that the person deploying the wobject would need to know how many text blocks the flash/javascript expects, and what unique ids to use.  For some flash/javascript widgets you could ignore unique ids altogether by adding a special class attribute to the generated textareas and then using a class selector to dynamically select all matching textareas on the page.

This should make it easier to use dynamic flash/javascript widgets in WebGUI whilst still retaining the power and ease of use of a content management system.

The curse of console.log

April 3rd, 2009

Here’s a common scenario, you’re on-site demonstrating some fancy new Javascript interface you’ve written, only to discover that some part of it that was working so beautifully on your dev box inexplicably breaks. hmm you think, must be a bloody IE bug. You try it in Firefox.. it still doesn’t work, what the?!

Later that day you get home and on a hunch run a quick search through your source tree:

> ack  ‘console.log’
www/extras/wobject/Survey/dd.js
96:console.log(destEl);

The culprit is Firebug’s console.log() function. The damn thing is just too handy. So handy that a few years ago the collective web development community abandoned alert() as the #1 debugging weapon of choice. Now we all use console.log(). Forget the firebug debugger, nobody can be bothered bringing up their js source in the script tab and clicking the break button or setting a watch variable, that’s like, 4 clicks too many man! Whack in a of console.log(a, b, c)s and it’s all there, plain as day in the firebug console, ready to be clicked on and examined further  in the DOM tab.

Until you forget that not everyone in the world runs firebug. Hard to believe, I know. But actually, the problem occurs for anyone who hasn’t got the firebug console turned on for YOUR SITE. The problem being of course that you probably always have the firebug console turned on for your site, but no-one else in the world does. So the likelihood of being bitten are pretty high.

Of course, there are lots of workarounds. One approach is to just define console.log as an empty function (and while you’re at it, you may as well define all the other Firebug functions too):


if (!("console" in window) || !("firebug" in console)) {
 var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
 window.console = {};
 for (var i = 0, len = names.length; i < len; ++i) {
 window.console[names[i]] = function(){};
 }
}

In my case the code was part of a drag and drop method used in WebGUI. And like all sane web projects, WebGUI oursources its cross-browser Javascript concerns to a library (in our case YUI). And it turns out YUI has a perfectly good logger of its own, guaranteed to be available on any page that YUI is loaded onto. Hello YAHOO.log();

Now, “YAHOO.log” is 1 letter shorter than “console.log”, so why does everyone end up using console.log() all the same? Maybe they don’t like typing in upper-case. More probably they noticed that when they use YAHOO.log(‘blah’); nothing appears in the firebug console. What gives? Well, you need to tell YAHOO to pass on log  messages to the console, that’s what. Type the following line first, and everything will work out just fine:


YAHOO.widget.Logger.enableBrowserConsole();

Of course, that’s a lot more letters than just typing console.log(), and what’s more you need to use YAHOO.lang.dump() to serialise objects passed to log() (no nice firebug object examination), which admittedly is a lot less fun. But it does mean a little less broken code in production.