Otaqui.Com

Pete Otaqui’s blog about web development and everything else

Archive for the ‘Professional’ Category

Started work on jQuery UI Modal widget

leave a comment

I’ve started working a jQuery UI Modal widget, for use in a project built on top of the widget library.

We have very high accessibility standards, and the current “{modal:true}” option for the dialog widget unfortunately wasn’t as good as we needed. Seeing that the team had identified the need for a standalone Modal widget, the team thought we could try and get the ball rolling.

You can see the work in progress here in the modal widget in my fork of jquery ui.

I’ve also been having a discssion about the modal widget with Scott Gonzalez of the jQuery UI team.

Written by pete

October 13th, 2010 at 10:26 pm

Posted in Professional

Tagged with ,

CSSP: Loading CSS with Javascript – and getting an onload callback.

4 comments

It seems fairly straightforward to require CSS with Javascript. The most obvious method that I thought of was creating a <link> tag and appending it to the head of the document. An alternative would be to load the text of the css file with an ajax XHR call, and then inject that into a <style> tag.

These are both fine for most cases, but what about a situation where you have a hard dependency on the css for the javascript to work correctly? You could take a best-guess at a wait time for the CSS to load, or even set the XHR to be synchronous – however both of these are very poor for both actual and perceived performance of your page (and the former may simply fail).

When might this be the case? Let’s say you have some asynchronously loaded javascript that is intended to create a widget on the page, something like this (which assumes you are using jQuery as your dom library):


function moveLargePanels() {
    // make a panel container for large panels
    $('<div id="largePanelContainer"></div>')
        .appendTo('body');
    $('.panel').each( function(i, panel) {
        if ( panel.outerWidth() > 300 ) {
            panel.appendTo('#largePanelContainer');
        }
    }
}

And some corresponding CSS:

.panel {
    border:1px solid #000;
    padding: 20px;
}

The idea here is that, since there is some interaction between the logic in the javascript (a test for the “outerWidth”) and the styling in the CSS (setting the padding) that the javascript can only work correctly once the CSS has been loaded and applied.

This should be fine right? Start the javascript and the css loading, and have events attached to the load of each letting you know when everything is ready and it’s safe to fire “moveLargePanels()”. Wrong, or at least tricky, and essentially impossible if the CSS is loaded from a different domain to the hosting webpage.

You can get James Burke’s excellent description of this problem here:
http://requirejs.org/docs/faq-advanced.html#css
And a first pass at solving this (in some browsers) here:
http://bugs.dojotoolkit.org/ticket/5402

Burke mentions a using a “well known” style rule to test whether the style is loaded. I suggest a standard pattern for the rule, and also a mechanism for dynamically setting it.

Enter CSSP

You may have heard of JsonP – a way of serving dynamically generated JSON which is padded with a method call (the method name is supplied in the query string of the URL), which allows for cross domain loading of javascript. The idea behind CSSP is similar – it defines a pattern for loading css cross domain. Instead of wrapping in a callback though, we can use the URL query string mechanism to supply the special “test rule” that we use.

Dynamic Rule Pattern

Given this url:

http://someserver.com/stylefile.css?cssp=123456

.panel { ... }
.largePanelsContainer { .. }

/* and the special rule: */
cssp { zIndex:123456; }

So, in whatever loader we want to build, we can add something like this (n.b. this isn’t tested code):

var cssp_counter = 0;
function loadCss(url, callback, className, zIndex) {
    // create a counter for special class names, so they are unique
    className = className || 'cssp' + (cssp_counter++);
    zIndex = zIndex || 123456;
    url = url + '?' + className + '=' + zIndex;
    $('<link>')
        .attr({
            rel: "stylesheet",
            type: "text/css",
            href: url
        .appendTo('head');
    // append a dummy div to the body for the test
    var div = $('<div></div>')
        .addClass(className)
        .appendTo('body');
    // now poll for the z-index value:
    var cssp_interval = setInterval( function() {
        // if the zIndex is applied, we know the css has loaded
        if ( div.css('zIndex') == zIndex ) {
            div.remove();
            // callback:
            callback();
            clearInterval( cssp_interval );
        }
    }, 100);

}

The code above to do the loading and fire a callback is very naive. It would be much better to have an event that can have listeners added, and to have some tests and some failure management like a maximum timeout.

Default Rule Pattern

This obviously presupposes that the CSS is dynamically generated to some degree, even just by adding the special rule to an otherwise static file. I think that an alternative to the performance-conscious would be a “default” special rule, based on the css filename. This needs some thought, and could well be tied to a build-step in your deployment process (you do have one, right?). The pattern comes in two parts:

  • There is a standard zIndex that is always used.
  • The filename includes the “special class name” that is used within.

For example:

Given the file: styles.fhddgso9j.css

.someclass { ... }
.otherclass { ... }

/* and the special rule */
.fhddgso9j { z-index: 123456; }

The javascript to go alone with this might look something like:

var cssp_counter = 0;
function loadCss(url, callback) {
    // create a counter for special class names, so they are unique
    className = getSpecialClassName(url);
    zIndex = 123456;
    $('<link>')
        .attr({
            rel: "stylesheet",
            type: "text/css",
            href: url
        .appendTo('head');
    // append a dummy div to the body for the test
    var div = $('<div></div>')
        .addClass(className)
        .appendTo('body');
    // now poll for the z-index value:
    var cssp_interval = setInterval( function() {
        // if the zIndex is applied, we know the css has loaded
        if ( div.css('zIndex') == zIndex ) {
            div.remove();
            // callback:
            callback();
            clearInterval( cssp_interval );
        }
    }, 100);
}
function getSpecialClassName(url) {
  // get just the filename, e.g. "styles.9ufosdfij.css"
  var filename = url.substring( url.lastIndexOf('/')+1, url.length);
  // split on the "." marks
  var parts = filename.split('.');
  // assume it will be the second-to-last part (since the last should be "css")
  var className = parts[ parts.length-2 ];
  return className;
}

As noted above, this naive, untested code.

Wrapping Up

Ideally I’d like any “css loader” to use actual browser events (or properties) where possible, and to fallback on this setup as a last resort.

If I get time I’ll implement this and put the code on github. Please do get in touch if you’d like to pair on this!

Written by pete

September 28th, 2010 at 10:16 pm

Posted in Professional

Tagged with , , ,

Review of “Simplicity is Highly Overrated”

leave a comment

Dan Norman writes that “simplicity is highly overrated” and asks whether you would buy an equivalent product with less features for the same, or more, money.

Dan is a usability expert and although says that while he prefers simplicity and what I would call “poignancy” in design, most purchases are not based on the premise of being “just right”. The article is a good read, but I think he misses a swathe of well selling products. He details various things like washing machines and other white goods (although lots of the same issues apply to software) but completely misses any discussion of personal electronics, and how long can one talk about design in that area without mentioning the ipod.

When the ipod first came out it was a very poor cousin to a great deal of its competitors in terms of features, let alone the number of controls. It could play fewer music formats, it stopped you from powerful management of your music, it didn’t even have a radio! Yet it sold incredibly well and very quickly got to the same point in the public consciousness that the Sony WalkMan did where a single product’s name became synonymous with a whole class of devices.

The ipod was not cheap. Nor, despite its simplicity, did it *look* cheap, which Dan seems to be suggesting is inevitable. It was excellently marketed, but it was also just a really good product with the entire user interface (what there was of it – not even a radio remember, let alone picture-viewing or other features that other mp3 players had at the time) being very simple to use.

Adding features is the “simple” way to try and boost the cost and sales of product (or a piece of software) but making “simplicity” the key feature that makes it worth more is pretty hard to beat in the long run.

Written by pete

September 6th, 2010 at 1:05 pm

Posted in Professional

Tagged with

Adobe CS3 “licensing for this product has stopped working” fix

leave a comment

After getting a new computer, and restoring my old system from a Time Machine backup, I found my Adobe Web Premium CS3 stopped working. Every application I started (Photoshop, Fireworks, Flash, etc) gave the error message:

Licensing for this product has stopped working.

After following every suggestion I could find in Adobe’s knowledge base and various online articles, I still couldn’t get any of the applications to start.

As a final act of complete desperation, after many rounds of removal-reboot-reinstall, I finally ran the installer and chose a product that I had not installed before (Contribute). Once that was done I started up the new app, and it asked me for my license key – which I entered and the app started. Then I tried Photoshop and it started up fine!

So – if you didn’t do a complete install int he first place, one of the easiest things could be to add a new app to your install, and get that to reset your licensing for you.

Written by pete

June 23rd, 2010 at 5:55 pm

Posted in Professional

Tagged with

Public Opinion

leave a comment

News networks giving a greater voice to viewers because the social web is so popular are like a chef on the Titanic who, seeing the looming iceberg and fleeing customers, figures ice is the future and starts making snow cones.

via XKCD.

Written by pete

June 22nd, 2010 at 4:13 pm

Posted in Professional