Blog entries by Adrien Di Mascio [3]

Javascript date support

2008/11/27 by Adrien Di Mascio

Coming from the python and mx.DateTime world, the javascript Date object is not really appealing. For me, the most disturbing things are :

  • The year parameter in the Date constructor is always considered as a XXe century year if year < 100. (this goes along with the getYear / getFullYear distinction).
  • The inconsistency between months and days indexes : months indexes starts at 0 whereas days indexes starts at 1.
  • The lack of decent strptime / strftime functions (even basic ones not taking locales into account).

Recently, I've worked with the great Timeline project which makes an heavy use of dates and I had the need for a very basic strptime implementation. This can by no mean be considered as a comprehensive implementation, but it might help so here it is:

var _DATE_FORMAT_REGXES = {
    'Y': new RegExp('^-?[0-9]+'),
    'd': new RegExp('^[0-9]{1,2}'),
    'm': new RegExp('^[0-9]{1,2}'),
    'H': new RegExp('^[0-9]{1,2}'),
    'M': new RegExp('^[0-9]{1,2}')
}

/*
 * _parseData does the actual parsing job needed by `strptime`
 */
function _parseDate(datestring, format) {
    var parsed = {};
    for (var i1=0,i2=0;i1<format.length;i1++,i2++) {
    var c1 = format[i1];
    var c2 = datestring[i2];
    if (c1 == '%') {
        c1 = format[++i1];
        var data = _DATE_FORMAT_REGXES[c1].exec(datestring.substring(i2));
        if (!data.length) {
            return null;
        }
        data = data[0];
        i2 += data.length-1;
        var value = parseInt(data, 10);
        if (isNaN(value)) {
            return null;
        }
        parsed[c1] = value;
        continue;
    }
    if (c1 != c2) {
        return null;
    }
    }
    return parsed;
}

/*
 * basic implementation of strptime. The only recognized formats
 * defined in _DATE_FORMAT_REGEXES (i.e. %Y, %d, %m, %H, %M)
 */
function strptime(datestring, format) {
    var parsed = _parseDate(datestring, format);
    if (!parsed) {
    return null;
    }
    // create initial date (!!! year=0 means 1900 !!!)
    var date = new Date(0, 0, 1, 0, 0);
    date.setFullYear(0); // reset to year 0
    if (parsed.Y) {
    date.setFullYear(parsed.Y);
    }
    if (parsed.m) {
    if (parsed.m < 1 || parsed.m > 12) {
        return null;
    }
    // !!! month indexes start at 0 in javascript !!!
    date.setMonth(parsed.m - 1);
    }
    if (parsed.d) {
    if (parsed.m < 1 || parsed.m > 31) {
        return null;
    }
    date.setDate(parsed.d);
    }
    if (parsed.H) {
    if (parsed.H < 0 || parsed.H > 23) {
        return null;
    }
    date.setHours(parsed.H);
    }
    if (parsed.M) {
    if (parsed.M < 0 || parsed.M > 59) {
        return null;
    }
    date.setMinutes(parsed.M);
    }
    return date;
}

// and now monkey patch the Timeline's parser ...
/* provide our own custom date parser since the default
 * one only understands iso8601 and gregorian dates
 */
Timeline.NativeDateUnit.getParser = function(format) {
    if (typeof format == "string") {
    if (format.indexOf('%') != -1) {
        return function(datestring) {
            if (datestring) {
                return strptime(datestring, format);
            }
            return null;
        };
    }
        format = format.toLowerCase();
    }
    if (format == "iso8601" || format == "iso 8601") {
    return Timeline.DateTime.parseIso8601DateTime;
    }
    return Timeline.DateTime.parseGregorianDateTime;
};

gajim, dbus and wmii

2008/09/02 by Adrien Di Mascio
http://upload.wikimedia.org/wikipedia/commons/d/de/Gajim.png

I've been using for a long time a custom version of gajim in order to make it interact with wmii. More precisely, I have, in my wmii status bar, a dedicated log zone where I print notification messages such as new incoming emails or text received from gajim (with different colors if special words were cited, etc.).

I recently decided to throw away my custom gajim and use python and dbus to achieve the same goal in a cleaner way. A very basic version can be found in the simpled project. As of now, the only way to get the code is trhough mercurial:

hg clone http://www.logilab.org/hg/simpled

The source file is named gajimnotifier.py. In this file, you'll also find a version sending messages to Ion's status bar.


Browsers strangeness ...

2008/06/07 by Adrien Di Mascio

... or when inverting two lines of code in your HTML's HEAD can speed up your web page rendering !

If you have the following HTML page:

<html>
  <head>
    <link rel="stylesheet" type="text/css" href="http://yourdomain.com/css1.css" />
    <script type="text/javascript">
      var somearray = [1, 2, 3];
    </script>
    <link rel="stylesheet" type="text/css" href="http://yourdomain.com/css2.css" />
  </head>
  <body>
    <h1>Hello</h1>
  </body>
</html>

Firefox3 [1] will download the CSS sequentially, hence if both CSS get 250ms to download, this page will approximatively appear in more or less half a second.

Now, if you just move the inline script before the two CSS declarations:

<html>
  <head>
    <script type="text/javascript">
      var somearray = [1, 2, 3];
    </script>
    <link rel="stylesheet" type="text/css" href="http://yourdomain.com/css1.css" />
    <link rel="stylesheet" type="text/css" href="http://yourdomain.com/css2.css" />
  </head>
  <body>
    <h1>Hello</h1>
  </body>
</html>

The two CSS files are now downloaded in parallel, and your page now take about half time to render !

One of the lessons here is that optimizing your website's backend is great and necessary, but is a quite long term and hard job. On the other hand, optimizing the frontend is often easier and pays off immediatly (well, so to speak...). Don't forget that in complex and rich web sites, most of the time can be spent on the client side.

[1] It seems that Firefox 2 doesn't event try to download CSS in parallel.

Going further

http://developer.yahoo.com/yslow/help/images/OverallGrade_Size.png

Of course, this is quite browser-dependant ! It would be simpler if all browsers behaved the same way but fortunately, there is a very nice tool named cuzillion developed by Steve Souders at Google (formerly Chief performance at Yahoo and developer of Yslow, a firebug's extension which is able to point out performance problems of your site). This tool lets you create web pages online by inserting inline scripts, CSS, images, etc. and then test how long the page takes to be rendered in your browser. You can control the order of the inserted elements as well as customize their properties (how long it shoud take to download, choose another domain to download, if a script is defined with a script tag, an XHR, an iframe, etc.)